如何在Django Rest中保存文件

时间:2019-06-24 13:37:43

标签: django file-upload django-rest-framework

我无法将文件保存到服务器。我需要上传和保存文件,但是id对我不起作用。我可以将文件从用户界面发送到我的rest api,但是我无法保存文件。

我的模特

fs = FileSystemStorage(location='/media/attachments/')

...

class TicketLog(models.Model):
    ticket = models.ForeignKey(Ticket, on_delete=models.DO_NOTHING, related_name='ticket_log')
    created_date = models.DateTimeField(auto_now=False, auto_now_add=True)
    created_by = models.ForeignKey(
        User,
        on_delete=models.DO_NOTHING,
        related_name='ticketlog_creator')
    note = models.TextField()

    class Meta:
        ordering = ['pk']

    def __str__(self):
        return self.note


class TicketFiles(models.Model):
    ticketlog = models.ForeignKey(TicketLog, on_delete=models.CASCADE, related_name='log_file', blank=True, null=True)
    attachment = models.FileField(upload_to='attachments', storage=fs)

class UploadWithFile(APIView):
    parser_classes = [MultiPartParser, ]

    def post(self, request):

        content = request.data['file']
        data = json.loads(request.data['data'])
        queue = Queue.objects.get(pk=data['queue']['id'])
        priority = Priority.objects.get(pk=data['priority']['id'])
        status = Status.objects.get(pk=data['status']['id'])
        created_by = User.objects.get(pk=data['ticket_log'][0]['created_by_id'])
        ticket_data = Ticket(
            name=data['name'],
            priority=priority,
            status=status,
            queue=queue,
            created_date=datetime.datetime.now(),
            created_by=created_by
        )
        ticket_data.save()

        log_data = TicketLog(
            ticket=ticket_data,
            created_date=datetime.datetime.now(),
            created_by=created_by,
            note=data['ticket_log'][0]['note']
        )
        log_data.save()

        file_data = TicketFiles(
            ticketlog=log_data
        )
        file_data.attachment.save(content.name, content)
        file_data.save()

        return HttpResponse(content)

似乎一切正常,数据库已正确更新,但文件未保存在服务器上。

2 个答案:

答案 0 :(得分:0)

使用rest_framework.parsers == >> FileUploadParser的示例:

url.py:

urlpatterns = +[
    url(r'^docs/$', views.DocumentView.as_view(), name='docs'),
]

models.py

class Document(models.Model):
    DOC_CATEGORY = (
        ('profile_pic', 'Profile_Picture'),
    )

    class Meta:
        ordering = ['uploaded_at']

    uploaded_at = models.DateTimeField(auto_now_add=True)
    file = models.FileField(blank=False, null=False)
    # description
    remark = models.CharField(max_length=200, blank=True, null=True)
    user = models.ForeignKey(User, blank=True, on_delete=models.DO_NOTHING,)
    category = models.CharField(
        'Document category',
        max_length=64,
        choices=DOC_CATEGORY,
        default='profile_pic')

    def __str__(self):
        return self.file.name

serializers.py

class DocumentSerializer(serializers.ModelSerializer):
    class Meta():
        model = Document
        fields = ('file', 'remark', 'uploaded_at', 'user', 'category')

和最后的views.py:

from rest_framework.parsers import FileUploadParser

class DocumentView(APIView):

    http_method_names = ['get', 'post']
    model = Document
    # fields = ['upload', ]
    success_url = reverse_lazy('/')
    parser_class = (FileUploadParser,)
    # permission_classes = [DocumentViewPerm, ]
    # allow any for the example!!!
    permission_classes = [AllowAny, ]

    def get_object(self, pk):

         return serializers.serialize(
              'json', list(Document.objects.filter(pk=pk))
                )
    def get(self, request, pk=None, format=None):
        category = request.query_params.get('category', None)
        if request.query_params.get('pk'):
            return HttpResponse(
                self.get_object(pk=request.query_params.get('pk'),
                content_type="application/json")


        return HttpResponse(self.get_object(request.user.pk), 
            content_type="application/json")

    def post(self, request, *args, **kwargs):
        file_serializer = DocumentSerializer(data=request.data)
        ########################################################
        # when uploading keep these headers- no content type !!!

        # headers = {'Authorization': '{}'.format(token), 'Accept': 
        # 'application/json'}
        ########################################################
        if file_serializer.is_valid():
            file_serializer.save(user=self.request.user)
            # save all fields 
            # remark  # category 
            remark = request.data.get('remark')
            category = request.data.get('category')

            return Response(file_serializer.data, 
                status=status.HTTP_201_CREATED)

        else:
            return Response(file_serializer.errors, 
                status=status.HTTP_400_BAD_REQUEST)

示例上传文件,打开python cmd行

import requests, json
# no content type in headers !!!

headers = {'Accept': 'application/json',
 'Authorization': "TOKEN"}
with open('pathtofile', 'rb') as f:
  r = requests.post('http://MachineIP/docs/', files={'file': f}, data={'remark': 'my remark'}, headers=headers)

答案 1 :(得分:0)

您不必编写自定义代码。使用ModelSerializer,您可以实现所需的功能。

.has

您可以根据需要添加其他所需字段。

在您的API视图中,

class TicketFilesSerializer(serializer.ModelSerializer):
    class Meta:
        model = TicketFiles
        fields = '__all__'

您必须以多部分格式发送数据。