Django channels image saving, TextField or ImageField - django

Chat app using django channels
I am using websockets to send base64 encoded string to the server, the base64 encoded string could be saved in TextField or saved in ImageField by decoding using base64 library, which method is preferred, why?
EDIT
I am interested in which method is preferred and why, but not how to implement

You can use this function for converting base64 data that you get from your request into django contentfile which can be added to image model field later
import base64
from django.core.files.base import ContentFile
def base64_file(data, name=None):
_format, _img_str = data.split(';base64,')
_name, ext = _format.split('/')
if not name:
name = _name.split(":")[-1]
return ContentFile(base64.b64decode(_img_str), name='{}.{}'.format(name, ext))
# Simple example
data = request.GET.get('base64data')
data = base64_file(data, name='profile_picture')
UserProfile.profile_picture = data
UserProfile.save()

Related

convert multiple files from base64 to pdf in memory

I am receiving several files in base64 format and I need to upload them to aws s3 in pdf format but so far I have tried everything and I still can't do it, is there any way to convert them to pdf without creating a file?
i'm using django rest framwork
"balance":"base64String",
"stateOfCashflow":"base64String",
"financialStatementAudit":"base64String",
"managementReport":"base64String",
"certificateOfStockOwnership":"base64String",
"rentDeclaration":"base64String",
I solved it on my own, I found a library called drf_extra_fields which does just what I need.
in the serializer is necesary to use base64filefield which takes the string in base 64 and transforms it into pdf behind the scenes
from drf_extra_fields.fields import Base64FileField
import PyPDF2
import io
class PDFBase64File(Base64FileField):
ALLOWED_TYPES = ['pdf']
def get_file_extension(self, filename, decoded_file):
try:
PyPDF2.PdfFileReader(io.BytesIO(decoded_file))
except PyPDF2.utils.PdfReadError as e:
print(e)
else:
return 'pdf'
class PDFSerializer(serializers.ModelSerializer):
pdf = PDFBase64File()
class Meta:
model = pdf
fields = "__all__"

saving blob in django creates a file with size 0

I post an audio blob to django using ajax, before posting I do
console.log(blob)
//prints
//Blob(262188) {size: 262188, type: "audio/wav"}
//size: 262188
//type: "audio/wav"
//__proto__: Blob
Inside the django view:
from django.core.files.storage import default_storage
from django.core.files.base import ContentFile
audio_data = request.FILES.get("recordedBlob", None)
print(type(audio_data)) #prints <class 'django.core.files.uploadedfile.InMemoryUploadedFile'>
print(audio_data.size) #prints 262188
path = default_storage.save('audio/' + '123' + '.wav', ContentFile(audio_data.read()))
But when I open the audio file in my file system, it is size Zero Bytes.
Any idea how to save the blob correctly?
I was calling
print(len(audio_data.read()))
and it seems like calling .read() empties out the data. So taking this line away solved the problem.

Can't upload image file while testing Django

I am developing API using Django REST Framework.
I have a Django model that has models.ImageField and it works just fine.
But when I want to unittest creating model object, I get error:
UnicodeDecodeError: 'utf-8' codec can't decode byte 0x89 in position 0: invalid start byte
My code:
class PlacesTest(APITestCase):
. . .
def test_create_place_full(self):
. . .
image = SimpleUploadedFile(name='test.jpg',
content=open('test.png', 'rb').read(),
content_type='image/jpeg')
request = self.factory.post(reverse('place-list'),
{'name': 'test_place_1',
'picture': image,
})
I have tried passing string with path to image, and I've tried methods from Django testing model with ImageField to do tests, but no success.
What type should I pass to Django REST framework when adding image: file object or string with path?
How can I add real file to my tests?
Found solution for my problem if someone is interested:
all I needed was specifying format='multipart' in request arguments:
request = self.factory.post(reverse('place-list'),
{'name': 'test_place_1',
'picture': self.image},
format='multipart')
in my project was:
REST_FRAMEWORK = {
...
'TEST_REQUEST_DEFAULT_FORMAT': 'json'
}
so no image could be added to POST request.

Django REST Framework FileField Data in JSON

In Django REST Framework (DRF), how do I support de-Serializing base64 encoded binary data?
I have a model:
class MyModel(Model):
data = models.FileField(...)
and I want to be able to send this data as base64 encoded rather than having to multi-part form data or a "File Upload". Looking at the Parsers, only FileUploadParser and MultiPartParser seem to parse out the files.
I would like to be able to send this data in something like JSON (ie send the binary data in the data rather than the files:
{
'data':'...'
}
I solved it by creating a new Parser:
def get_B64_JSON_Parser(fields):
class Impl(parsers.JSONParser):
media_type = 'application/json+b64'
def parse(self, *args, **kwargs):
ret = super(Impl, self).parse(*args, **kwargs)
for field in fields:
ret[field] = SimpleUploadedFile(name=field, content=ret[field].decode('base64'))
return ret
return Impl
which I then use in the View:
class TestModelViewSet(viewsets.ModelViewSet):
parser_classes = [get_B64_JSON_Parser(('data_file',)),]
This is an old question, but for those looking for an up-to-date solution, there is a plugin for DRF (drf_base64) that handles this situation. It allows reading files encoded as base64 strings in the JSON request.
So given a model like:
class MyModel(Model):
data = models.FileField(...)
and an expected json like:
{
"data": "data:image/png;base64,iVBORw0KGgoA ....",
...
}
The (des) serialization can be handled just importing from drf_base modules instead of the drf itself.
from drf_base64.serializers import ModelSerializer
from .models import MyModel
class MyModel(ModelSerializer):
class Meta:
model = MyModel
Just remember that is posible to get a base64 encoded file in javascript with the FileReader API.
There's probably something clever you can do at the serialiser level but the first thing that comes to mind is to do it in the view.
Step 1: Write the file. Something like:
fh = open("/path/to/media/folder/fileToSave.ext", "wb")
fh.write(fileData.decode('base64'))
fh.close()
Step 2: Set the file on the model. Something like:
instance = self.get_object()
instance.file_field.name = 'folder/fileToSave.ext' # `file_field` was `data` in your example
instance.save()
Note the absolute path at Step 1 and the path relative to the media folder at Step 2.
This should at least get you going.
Ideally you'd specify this as a serialiser field and get validation and auto-assignment to the model instance for free. But that seems complicated at first glance.

Django FileField encoding

I have a django model as follows:
class ExportFile(BaseExportFile):
created_timestamp = models.DateTimeField(auto_now=True, editable=False)
data = models.FileField(upload_to='exports')
and a view function that renders a template to create a csv file:
def create_csv(request):
context = Context({'data': MyModel.objects.all()})
rendered = render_to_string('mytemplate.html', context)
# create tradefile and save
cf = ContentFile(rendered)
tf = ExportFile()
tf.data.save('myfile.csv', cf)
tf.save()
response = HttpResponse(mimetype='text/csv')
response['Content-Disposition'] = 'attachment; filename=%s' % 'myfile.csv'
response.write(rendered)
return response
The view not only saves the csv data to a FileField but it also returns it to the browser. The problem I have is the browser file works perfectly, but the file saved on the model is twice the size and when I use a diff program I can see extra hidden characters. I think it must be to do with the mime type vs django auto saving utf8 but I just can't figure it out!
Solved the problem!
The ContentFile is a subclass of cStringIO.StringIO - which deals with ASCII encoded files. The string therefore needs to be encoded as ASCII as everything in django is UTF8 by default
cf = ContentFile(rendered.encode('ascii'))