Django [=10th=] 将字典传递给文件

Django multipart/form-data pass Dict & File

我想创建一个 post 请求来发送一个文件以及字典形式的信息。我有以下实现:

# conftest.py
import pytest


@pytest.fixture
def api_client():
    from rest_framework.test import APIClient

    return APIClient()

用 pytest 测试:

# test_dataset.py
@pytest.mark.django_db()
class TestDatasetEndpoint:
    
    def test_dataset_create(self, api_client):

        data_raw = baker.make(Dataset)
        serialized_dataset = DatasetSerializer(data_raw).data
        print(serialized_dataset)
        file_path = "./Top 250s in IMDB.csv"

        with open(file_path, "rb") as fp:

            encoded_data = encode_multipart(
                BOUNDARY, {"data": serialized_dataset, "file": fp}
            )

            response_post = api_client.post(
                reverse("datasets-list"),
                encoded_data,
                content_type="multipart/form-data; boundary=BOUNDARY",
            )

        assert response_post.status_code == 201

服务器端:

# views.py
class DatasetViewSet(viewsets.ModelViewSet):
    queryset = Dataset.objects.all()
    serializer_class = DatasetSerializer

    def create(self, request, *args, **kwargs) -> Response:

        data = request.data

        return Response(request.data["data"], status=status.HTTP_201_CREATED)

最后,数据集模型是:

class Dataset(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    name = models.CharField(max_length=100)
    path = models.CharField(max_length=100, editable=False, null=True, blank=True)
    description = models.CharField(max_length=500, null=True, blank=True)
    useCase = models.CharField(max_length=100, editable=False, null=True, blank=True)
    useCaseSpecificVariable = models.CharField(
        max_length=50, editable=False, null=True, blank=True
    )
    origin = models.CharField(max_length=50, editable=False, default="")
    creationDate = models.DateTimeField(editable=False, null=True, blank=True)
    workflowsUsedOn = models.JSONField(blank=True, null=True)
    owners = models.JSONField(blank=True, null=True)
    sampleSize = models.IntegerField(editable=False, default=0)
    featureSize = models.IntegerField(editable=False, default=0)
    metadataPath = models.CharField(
        max_length=100, editable=False, null=True, blank=True
    )
    timeFrom = models.DateTimeField(editable=False, null=True, blank=True)
    timeUntil = models.DateTimeField(editable=False, null=True, blank=True)

我得到的响应是字典和文件数据的组合。我如何处理服务器端的数据和文件(views.py)?

Django 可以通过表单处理此类请求。所以模式如下:

forms.py

from django import forms

class DatasetForm(forms.Form):
    class Meta:
        model = Dataset

views.py

class DatasetViewSet(viewsets.ModelViewSet):
    queryset = Dataset.objects.all()
    serializer_class = DatasetSerializer

    def create(self, request, *args, **kwargs) -> Response:

        dataset_form = DatasetForm(request.POST, request.FILES)
        if dataset_form.is_valid():
            dataset = dataset_form.save()

            return Response(self.serializer_class(dataset).data, status=status.HTTP_201_CREATED)
        else:
            return Response(dataset_form.error_messages, status=status.HTTP_400_BAD_REQUEST)

    

请注意,您需要有一个可以在您的模型上存储文件的字段。例如:file = models.FileField(upload_to='attachments', blank=False)

然后字典中字段的内容(以及您的文件的内容)将通过表单自动映射到相关字段。

查看更多信息:https://docs.djangoproject.com/en/4.0/topics/forms/