Sau khi dành 1 ngày cho việc này, tôi nhận ra rằng ...
Đối với những người cần tải lên một tệp và gửi một số dữ liệu, không có cách nào dễ dàng để bạn có thể làm cho nó hoạt động. Có một vấn đề mở trong thông số kỹ thuật json api cho điều này. Một khả năng tôi đã thấy là sử dụng multipart/related
như được hiển thị ở đây , nhưng tôi nghĩ rất khó để thực hiện nó trong drf.
Cuối cùng những gì tôi đã thực hiện là gửi yêu cầu dưới dạng formdata
. Bạn sẽ gửi từng tệp dưới dạng tệp và tất cả dữ liệu khác dưới dạng văn bản. Bây giờ để gửi dữ liệu dưới dạng văn bản, bạn có hai lựa chọn. trường hợp 1) bạn có thể gửi từng dữ liệu dưới dạng cặp giá trị khóa hoặc trường hợp 2) bạn có thể có một khóa duy nhất được gọi là dữ liệu và gửi toàn bộ json dưới dạng chuỗi trong giá trị.
Phương pháp đầu tiên sẽ hoạt động tốt nếu bạn có các trường đơn giản, nhưng sẽ là một vấn đề nếu bạn có các chuỗi tuần tự lồng nhau. Trình phân tích cú pháp nhiều phần sẽ không thể phân tích cú pháp các trường lồng nhau.
Dưới đây tôi cung cấp cách triển khai cho cả hai trường hợp
Models.py
class Posts(models.Model):
id = models.UUIDField(default=uuid.uuid4, primary_key=True, editable=False)
caption = models.TextField(max_length=1000)
media = models.ImageField(blank=True, default="", upload_to="posts/")
tags = models.ManyToManyField('Tags', related_name='posts')
serializers.py -> không cần thay đổi đặc biệt nào, không hiển thị trình tuần tự của tôi ở đây vì nó quá dài do áp lực ManyToMany Field có thể ghi được.
views.py
class PostsViewset(viewsets.ModelViewSet):
serializer_class = PostsSerializer
#parser_classes = (MultipartJsonParser, parsers.JSONParser) use this if you have simple key value pair as data with no nested serializers
#parser_classes = (parsers.MultipartParser, parsers.JSONParser) use this if you want to parse json in the key value pair data sent
queryset = Posts.objects.all()
lookup_field = 'id'
Bây giờ, nếu bạn đang làm theo phương pháp đầu tiên và chỉ gửi dữ liệu không phải Json dưới dạng các cặp giá trị khóa, thì bạn không cần một lớp phân tích cú pháp tùy chỉnh. DRF'd MultipartParser sẽ thực hiện công việc. Nhưng đối với trường hợp thứ hai hoặc nếu bạn có các bộ tuần tự lồng nhau (như tôi đã trình bày), bạn sẽ cần trình phân tích cú pháp tùy chỉnh như được hiển thị bên dưới.
utils.py
from django.http import QueryDict
import json
from rest_framework import parsers
class MultipartJsonParser(parsers.MultiPartParser):
def parse(self, stream, media_type=None, parser_context=None):
result = super().parse(
stream,
media_type=media_type,
parser_context=parser_context
)
data = {}
# for case1 with nested serializers
# parse each field with json
for key, value in result.data.items():
if type(value) != str:
data[key] = value
continue
if '{' in value or "[" in value:
try:
data[key] = json.loads(value)
except ValueError:
data[key] = value
else:
data[key] = value
# for case 2
# find the data field and parse it
data = json.loads(result.data["data"])
qdict = QueryDict('', mutable=True)
qdict.update(data)
return parsers.DataAndFiles(qdict, result.files)
Bộ tuần tự này về cơ bản sẽ phân tích cú pháp bất kỳ nội dung json nào trong các giá trị.
Ví dụ yêu cầu trong post man cho cả hai trường hợp: trường hợp 1 ,
Trường hợp 2