0

Am doing a project in angular js and django.

This is the model.

class MessageAttachments(models.Model):
    filename = models.CharField(max_length=100)
    file_size = models.IntegerField(max_length=100)
    attachment = models.FileField(upload_to='files/')

    def __unicode__(self):
        return self.filename

Inside api.py i wrote my own function to save message attachments.

def send(self, request, **kwargs):
        self.method_check(request, allowed=['post'])
        data = self.deserialize(request, request.body, format=request.META.get('CONTENT_TYPE', 'application/json'))
        file_data = data.get('attach', '')
        try:
            b = file_data.encode('utf-8')
            message_attach = MessageAttachments()
            message_attach.filename =  'file'
            message_attach.file_size = 'file'
            message_attach.attachment = ContentFile(b64decode(b), 'test')
            message_attach.save()
            return self.create_response(request, {
                    'success': True,
                    'msg': msg.id
                })         
        except:
            return self.create_response(request, {
                    'success': False
                })

As you can see i tried ContentFile . But its not working. I need to get the file size too from that. The string is stored inside variable file_data. i tried b64decode from base64. Even though the decoding works file is not stored.

Am using python 3.4 and django 1.6.

Neel Basu
  • 12,638
  • 12
  • 82
  • 146
CodeJunkie
  • 147
  • 1
  • 2
  • 13
  • What class is the "send" method part of? From my experience using v0.10.0 of Tastypie you would need to override the "deserialize" method of ModelResource. And make sure your upload is encoded as "multipart/form-data" -- then you can get the file upload from request.FILES. – kchan Sep 05 '14 at 05:46
  • it is part of the class MessagesResource. Upload is done in angularjs. How to do multipart in that? Can you specify how to override deserialize.. There are other variables to be recieved from deserialize. Why ContentFile is not working? – CodeJunkie Sep 05 '14 at 05:51
  • I added an answer below. Please see if that works for you. – kchan Sep 05 '14 at 06:04

2 Answers2

0

I'm not sure if there are differences in other versions of Tastypie, but for v0.10.0 (and below) the method suggested by the answer to this question has worked for me:

This is an example of a Resource class that overrides the deserialize methof of TastyPie's ModelResource:

class MultipartResource(object):
    """
    multi-part resource for uploads

    Resource definition for deserializing file/image uploads
    * see:
    https://github.com/toastdriven/django-tastypie/issues/42

    """
    def deserialize(self, request, data, format=None):
        if not format:
            format = request.META.get('CONTENT_TYPE', 'application/json')

        if format == 'application/x-www-form-urlencoded':
            return request.POST

        if format.startswith('multipart'):
            data = request.POST.copy()
            upload = request.FILES
            data.update(upload)
            return data

        return super(MultipartResource, self).deserialize(request, data, format)

In your api.py you would declare your resource like this and access the deserialized data normally:

class MyResource(MultipartResource, ModelResource):

    def hydrate(self, bundle):
        upload = bundle.data.get('attach')
        # ....

Note: This assumes your frontend is sending data to your API as regular POST data -- the upload does not need to be encoded. But it needs to be sent as "multipart/form-data":

<form action="#" method="post" enctype="multipart/form-data">
...
Community
  • 1
  • 1
kchan
  • 836
  • 8
  • 13
0

You can handle the upload as multipart data as shown in @kchan 's answer. However if you send the image as base64 encoded string you may override the obj_create method

import base64
from django.core.files import File
from django.core.files.temp import NamedTemporaryFile

class MyResource(MultiPartResource, ModelResource):
    # ....

    # attach the base64 encoded media in image
    def obj_create(self, bundle, request=None, **kwargs):
        image_encoded = bundle.data['image']
        image_decoded = base64.b64decode(image_encoded)

        # I am hard coding extension to jpeg, you may guess extension from mime type
        image_file = NamedTemporaryFile(suffix='.jpeg', delete=True)
        image_file.write(image_decoded)
        image_file.flush()

        # change MyResource to your resource name
        res = super(MyResource, self).obj_create(bundle, request=request, **kwargs)
        # assuming you ImageField name is image
        res.obj.image.save(image_file.name, File(image_file))
        return res 
Neel Basu
  • 12,638
  • 12
  • 82
  • 146