skexPet
skexPet

Reputation: 31

How to save file in django rest

I have problem with saving files to my server. I need to upload and save files, but id doesn't work for me. I can send file from my UI to my rest api, but i am not able to save the files.

My Models

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)

It seems that everything works fine and the database is updated correctly, but the files are not saved on server.

Upvotes: 3

Views: 5859

Answers (2)

Ohad the Lad
Ohad the Lad

Reputation: 1929

An example using 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')

and last 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)
#

EXAMPLE upload a file, open python cmd line

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)

Upvotes: 6

Muhammad Hassan
Muhammad Hassan

Reputation: 14391

You do not have to write your custom code. Using ModelSerializer, you can achieve what you want.

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

You can add other fields that you want according to your requirement.

In your API view,

class YourView(generics.GenericApiView):
    serializer_class = TicketFilesSerializer

    def post(self, request, *args, **kwargs):
        serializer = self.get_serializer(request.data)
        if serializer.is_valid():
            serializer.save()

You have to send data in multipart format.

Upvotes: 0

Related Questions