下面给你一个「零鉴权、最小可运行」的 Django + DRF + 七牛云直传示例。
只有 3 个文件需要改动/新增,复制即可跑通:
- 安装依赖
bash
pip install django djangorestframework qiniu python-dotenvsettings.py(只保留关键行)
python
INSTALLED_APPS = [
'django.contrib.staticfiles',
'rest_framework',
'uploader', # 新建 app,名字随意
]
# 七牛云密钥(放 .env 也行)
QINIU_ACCESS_KEY = '你的AK'
QINIU_SECRET_KEY = '你的SK'
QINIU_BUCKET_NAME = '你的空间名'
QINIU_BUCKET_DOMAIN = 'https://你的域名/' # 结尾带 /- 新建
uploader/views.py
python
from rest_framework.views import APIView
from rest_framework.response import Response
from qiniu import Auth
from django.conf import settings
import uuid, os
class UploadTokenView(APIView):
"""POST /upload/token/ 返回 uptoken + key + url"""
def post(self, request):
filename = request.data.get('filename', 'unnamed')
suffix = os.path.splitext(filename)[-1]
key = f"demo/{uuid.uuid4().hex}{suffix}"
token = Auth(
settings.QINIU_ACCESS_KEY,
settings.QINIU_SECRET_KEY
).upload_token(settings.QINIU_BUCKET_NAME, key)
return Response({
'uptoken': token,
'key': key,
'url': settings.QINIU_BUCKET_DOMAIN + key
})uploader/urls.py
python
from django.urls import path
from .views import UploadTokenView
urlpatterns = [
path('upload/token/', UploadTokenView.as_view()),
]- 根
urls.py
python
from django.urls import include, path
urlpatterns = [
path('', include('uploader.urls')),
]- 运行
bash
python manage.py migrate # 建表,虽然这里没模型
python manage.py runserver- 测试(curl 即可)
bash
curl -X POST http://localhost:8000/upload/token/ \
-H "Content-Type: application/json" \
-d '{"filename":"hello.txt"}'返回示例
json
{
"uptoken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"key": "demo/a3f42b1c8e5d4f7a89b3c1d4e5f6a7b8.txt",
"url": "https://你的域名/demo/a3f42b1c8e5d4f7a89b3c1d4e5f6a7b8.txt"
}把 uptoken、key 和文件一起 POST 到 https://upload.qiniup.com 就完成上传——全程不需要任何登录/鉴权。
- 用 curl 快速验证(本地文件版)
bash
# 1. 先拿 token(刚才的接口)
RESP=$(curl -s -X POST http://localhost:8000/upload/token/ \
-H "Content-Type: application/json" \
-d '{"filename":"hello.txt"}')
TOKEN=$(echo $RESP | jq -r .uptoken)
KEY=$(echo $RESP | jq -r .key)
# 2. 真正上传文件(关键步骤)
curl -F "token=$TOKEN" \
-F "key=$KEY" \
-F "file=@/path/to/hello.txt" \
https://upload.qiniup.com
# 返回 {"hash":"FqUqya...","key":"demo/xxx.txt"} 即成功- 前端浏览器直传最小示例
html
<input type="file" id="f">
<button onclick="up()">上传</button>
<script>
async function up() {
const file = document.getElementById('f').files[0];
// 1. 拿 uptoken
const {uptoken, key, url} = await fetch('http://localhost:8000/upload/token/', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({filename: file.name})
}).then(r => r.json());
// 2. 构造表单直传七牛
const form = new FormData();
form.append('token', uptoken);
form.append('key', key);
form.append('file', file);
await fetch('https://upload.qiniup.com', {method: 'POST', body: form});
alert('上传完成!七牛外链:' + url);
}
</script>- 常见坑检查清单
现象 原因 200 但空间没文件 只拿了 token,没发第二步 返回 bad tokentoken 里 bucket 与空间不符 / AK/SK 填错 返回 file is requiredform 里字段名必须叫 file返回 no such domain上传域名用错,参考控制台「上传地址」
一句话总结/upload/token/ ≠ 上传完成,它只是「通行证」;
再发一次 POST https://upload.qiniup.com 带上 token、key、file 才算真正上传,成功后七牛控制台立刻能看到文件。
补齐 2 个常用接口:
- 查看(列举)桶内文件 – 支持前缀、分页
- 删除指定文件 – 支持单条/批量
全部用 Class-based,复制即可跑通。
- 安装依赖(已装可跳过)
bash
pip install qiniuuploader/views.py追加
python
from rest_framework.views import APIView
from rest_framework.response import Response
from qiniu import Auth, BucketManager
from django.conf import settings
auth = Auth(settings.QINIU_ACCESS_KEY, settings.QINIU_SECRET_KEY)
bm = BucketManager(auth)
class FileListView(APIView):
"""
GET /files/?prefix=demo/&limit=10&marker=
列举空间文件,支持前缀、分页
"""
def get(self, request):
bucket = settings.QINIU_BUCKET_NAME
prefix = request.query_params.get('prefix', '')
limit = int(request.query_params.get('limit', 20))
marker = request.query_params.get('marker', None)
ret, eof, info = bm.list(bucket, prefix=prefix, limit=limit, marker=marker)
if ret is None:
return Response({'error': info.text}, status=400)
return Response({
'items': ret['items'], # 文件数组
'marker': ret.get('marker'), # 翻页游标
'eof': eof # 是否已读完
})
class FileDeleteView(APIView):
"""
POST /delete/ {"key": "demo/a3f42b.txt"}
删除单个文件;可改成批量
"""
def post(self, request):
key = request.data.get('key')
if not key:
return Response({'error': 'key 必填'}, status=400)
ret, info = bm.delete(settings.QINIU_BUCKET_NAME, key)
if ret is None or info.status_code != 200:
return Response({'error': info.text}, status=info.status_code)
return Response({'message': '已删除'})uploader/urls.py追加
python
urlpatterns += [
path('files/', FileListView.as_view(), name='file-list'),
path('delete/', FileDeleteView.as_view(), name='file-delete'),
]- 快速测试(curl)
bash
# 列举
curl "http://localhost:8000/files/?prefix=demo/&limit=5"
# 删除
curl -X POST http://localhost:8000/delete/ \
-H "Content-Type: application/json" \
-d '{"key":"demo/a3f42b1c8e5d4f7a89b3c1d4e5f6a7b8.txt"}'- 接口说明
接口 方法 参数 返回 /files/GET prefix路径前缀limit≤1000marker翻页游标{items:[{key,hash,fsize,putTime,mimeType,...}],marker,eof}/delete/POST {"key":"空间内文件名"}{"message":"已删除"}
批量删除可循环调用,或用七牛 batch 接口一次传 1000 条 。
至此,「上传-查看-删除」闭环完成,祝你使用愉快!