Django Large File Serving - django

I am trying to make an app like youtube, where I need to serve huge number of files and each Video file size can be large [ 50MB or 1GB, or 2GB or more]. I am using SQLite DataBase. How can I serve these files in an efficient way?
models.py
class VideoContent(models.Model):
contenttitle = models.CharField(max_length=300, blank=False)
file = models.FileField(blank=False, verbose_name='Your Video Content',
validators=[FileExtensionValidator(
allowed_extensions=['MOV', 'avi', 'mp4', 'webm', 'mkv']
)])
uploaded = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
def __str__(self) -> str:
return self.contenttitle.title()
** views.py **
class VideoContents(ListView):
template_name = 'contents/index.html'
context_object_name = 'videos'
ordering = '-uploaded'
model = VideoContent
# def get_queryset(self):
# return VideoContent.objects.all()

Related

Detected path traversal attempt - Django/Heroku(Bucketeer)

I'm getting this error when trying to upload using FileField. I'm using Bucketeer on Heroku to upload to an AWS bucket. I've seen a few threads on this issue but haven't been able to figure it out.
The file upload view:
class UploadTicketAttachment(APIView):
permission_classes = []
parser_classes = (MultiPartParser, FormParser)
def post(self, request, format=None):
user = request.user
serializer = AttachmentSerialiazer(data=request.data)
if serializer.is_valid(raise_exception=True):
serializer.validated_data['uploaded_by'] = user
serializer.save()
return Response(serializer.data['id'])
else:
return Response(f'{serializer.errors}, attachment upload failed')
The model:
class Attachment(models.Model):
file = models.FileField(upload_to="/ticket_attachments", blank=True, null=True)
created_on = models.CharField(max_length=20, null=True)
uploaded_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, null=True, related_name="uploaded_by")
parent_ticket = models.ForeignKey(Ticket, on_delete=models.CASCADE, null=True, related_name="attachment")
def __str__(self):
return self.file.name
For the settings/bucketeer configuration I followed which uses django-storages:
https://dev.to/heroku/properly-managing-django-media-static-files-on-heroku-o2l
I don't think the issue is on that end since I set it up the exact same way in another project and it works fine with the only difference being that the other project uses ImageField instead of FileField.
Django version is 4.0.2. Any ideas? Thanks

I can't save my file through model after base64 encode at django-rest

I have fields named image1 and image2 in my model. I'm getting the base64 content of the files when creating (I'll send this to the remote api for another action). When I do base64 conversion, I cannot record in my model. It gives an error like;
ValueError: I/O operation on closed file
models.py
class HelpDeskDemandModel(models.Model):
code = models.CharField(max_length=50, unique=True, null=False, blank=False)
image1 = models.ImageField(upload_to="municy_helpdesk_images/%Y/%m/%d/", null=True, blank=True)
image2 = models.ImageField(upload_to="municy_helpdesk_images/%Y/%m/%d/", null=True, blank=True)
serializers.py
class HelpDeskDemandSerializer(serializers.ModelSerializer):
class Meta:
model = HelpDeskDemandModel
fields = [
'code', 'image1', 'image2'
]
def create(self, validated_data):
base64_files = []
for i in range(1, 3):
img = validated_data.get(f"image{i}", None)
if img:
with img.open('rb') as f:
base64_content = base64.b64encode(f.read()).decode()
base64_files.append(base64_content)
# the error occurs on this line
instance = HelpDeskDemandModel.objects.create(**validated_data)
return instance
this is how i solved it.
I created a new object with ContentFile and passed this object to the model
validated_data.update({f"image{i}": ContentFile(file_content_byte, img.name)})
serializers.py
class HelpDeskDemandSerializer(serializers.ModelSerializer):
class Meta:
model = HelpDeskDemandModel
fields = [
'code', 'image1', 'image2'
]
def create(self, validated_data):
base64_files = []
for i in range(1, 3):
img = validated_data.get(f"image{i}", None)
if img:
with img.open('rb') as f:
file_content_byte=f.read()
base64_content = base64.b64encode(file_content_byte).decode()
validated_data.update({f"image{i}": ContentFile(file_content_byte, img.name)})
base64_files.append(base64_content)
# the error occurs on this line
instance = HelpDeskDemandModel.objects.create(**validated_data)
return instance

corrupted files uploading csv and zip files via postman toward django rest api

Hi, I'm using django 4.0.6 (python 3.8) with djangorestframework
3.13.1 on windows. I'm testing on localhost my app with postman and postman agent up to date.
The main goal is to send 3 csv file, 1 zip file end 2 textfield
information
The authorization JWT is working fine.
The shortest csv is uploaded correctly
If I upload a long csv or zip files they result in corrupted files.
Only short csv files are correctly uploaded,
long csv files result in corrupted lines on the lower part of
the text with this sort of characters: Û™eÞqHÂÔpŠl°‹<û
yj­Ïª›kÃx›Ûr-¥x¡S¼à2SÕkÛår'mÒÕµd5ÿ¶Vê0#1 ̦Záë1§ŠIÇaÎ
“’ÏÛ€t»vRoT"·‡Qf„¾´é-Oa)]ЧK‹5C¤sWB0),3 Zž—2¸Ñóo«jŸH“
I can't figure out how to fix it, reading other posts I couldn't find
a solution that fit with this situation.
Thank You for any suggestion!
Here my model:
class FileUploader(models.Model):
id_file = models.AutoField('id_file', primary_key=True)
Campaign_Name = models.CharField('Campaign_Name', max_length=255)
ViewpointSurvey = models.FileField('ViewpointSurvey',upload_to=path_and_rename_base,max_length=255,blank=False,null=False,db_column='ViewpointSurvey', name='ViewpointSurvey')
ProjectSurvey = models.FileField('ProjectSurvey', upload_to=path_and_rename_base, max_length=255, blank=False, null=False,
db_column='ProjectSurvey', name='ProjectSurvey')
Trajectories = models.FileField('Trajectories', upload_to=path_and_rename_base, max_length=255, blank=False, null=False,
db_column='Trajectories', name='Trajectories')
screenshots = models.FileField('screenshots', upload_to=path_and_rename_base, max_length=255, blank=False,
null=False,
db_column='screenshots', name='screenshots')
timestamp=models.DateTimeField('timestamp',auto_now_add=True,db_column='timestamp', name='timestamp')
id_project=models.CharField('id_project', max_length=255)
class Meta:
db_table = "file_uploader"
verbose_name_plural = 'file_uploader'
verbose_name = "file_uploader"
Here the view:
class CSVUploadAPI(GenericAPIView):
parser_classes = [MultiPartParser]
serializer_class = UploadSerializer
def put(self, request):
data_collect = request.data
serializer = UploadSerializer(data=data_collect)
if serializer.is_valid():
serializer.save()
return Response('Done')
else:
return Response(UploadSerializer.errors,status=status.HTTP_400_BAD_REQUEST)
Here the serializer:
class UploadSerializer(serializers.ModelSerializer):
class Meta:
model= FileUploader
fields = ('id_project','ProjectSurvey','Trajectories','ViewpointSurvey','screenshots','Campaign_Name')
Here the path_and_rename_base function:
def path_and_rename_base(instance, filename):
upload_to = 'files/'
ext = filename.split('.')[-1]
# set filename as random string
filename = '{}.{}'.format(uuid.uuid4(), ext)
return os.path.join(upload_to, filename)
Here the postman headers
postman headers
Here the postman body
postman body
Here the file list with sizes
Highlighted file is the only one uploaded correctly

Django rest framework : How to serve binary directly in the body

I need to return an Image (binary) directly in the body request, but what i get in response is a file generated with no extension and an empty array/json inside!
I'm using python 3, Django==1.10.5 and djangorestframework==3.5.3, drf-extensions==0.3.1 (for the nested routes) and django-extra-fields==0.9 for the ImageField.
(I have tried without django-extra-fields, it's the same)
I have already found one solution (thx a lot Enix ;p) with the base64 here :Django rest framework : How to download image with this image send directly in the body
But my boss doesn't want base64 and just want the binary inside the body response.
My models.py
class Image(models.Model):
class Meta:
verbose_name = _('Image')
verbose_name_plural = _('Images')
creation_date = models.DateTimeField(
help_text=_('Creation date'),
auto_now_add=True,
editable=False
)
modified_date = models.DateTimeField(
help_text=_('Last modification date'),
auto_now=True
)
image_file = models.ImageField(upload_to='', null=True)
My serializers.py
class ImageSerializer(serializers.ModelSerializer):
class Meta:
model = Image
fields = ('image_file',)
My views.py
class ImageViewSet(NestedViewSetMixin, viewsets.ModelViewSet):
http_method_names = ['get', 'put']
queryset = Image.objects.all()
serializer_class = ImageSerializer
pagination_class = None
def get_queryset(self, *args, **kwargs):
image = Image.objects.last() # This is just for the exemple.
filename = image.image_file
size = filename.size
response = FileResponse(open(filename.path, 'rb'), content_type="image/png")
response['Content-Length'] = size
response['Content-Disposition'] = "attachment; filename=%s" % 'notification-icon.png'
return response
I have made some test with :
django.core.files.File, filewrapper, deactivate the serializer
but have not yield desired results...
If someone find out what I'm doing wrong or maybe forgot something in the settings ? Any help regarding the same would be much appreciated!
Ok, I found my mistake...
I was trying to override get_queryset... and not the get method which doesn't work too because I need to override the list method!
I need to sleep a little bit more ;p
Here is a solution that work's great for me with Streaming for download large file if needed :
My models.py
class Image(models.Model):
class Meta:
verbose_name = _('Image')
verbose_name_plural = _('Images')
creation_date = models.DateTimeField(
help_text=_('Creation date'),
auto_now_add=True,
editable=False
)
modified_date = models.DateTimeField(
help_text=_('Last modification date'),
auto_now=True
)
image_file = models.ImageField(upload_to='', null=True)
My serializers.py
class ImageSerializer(serializers.ModelSerializer):
class Meta:
model = Image
fields = ('image_file',)
My views.py
class ImageViewSet(NestedViewSetMixin, viewsets.ModelViewSet):
http_method_names = ['get', 'put']
queryset = Image.objects.all()
serializer_class = ImageSerializer
pagination_class = None
def list(self, request, *args, **kwargs):
image = Image.objects.get(pk=get_your_good_record)
filename = image.image_file
size = filename.size
content_type_file = mimetypes.guess_type(filename.path)[0]
response = StreamingHttpResponse(open(image.image_file.path, 'rb'), content_type=content_type_file)
response['Content-Disposition'] = "attachment; filename=%s" % str(filename)
response['Content-Length'] = size
return response
So easy ;p

Upload images based on matching field and image name

I'm building an inventory list that includes the fields listed below in my Django model. I have a folder full of images that the name of the images correspond to the the Item Number. For install, the item number may be 4119, then the image file name will be 4119.jpg.
I would like to write a script that iterated over the items in the database and uploads the corresponding image. Any thoughts on where to start are greatly appreciated.
from django.db import models
def directory_path(instance, filename):
return '{0}/{1}/{2}'.format(supplier.name, pricelist.item_number, filename)
class Supplier(models.Model):
name = models.CharField(max_length=80)
def __str__(self):
return self.name
class PriceList(models.Model):
supplier = models.ForeignKey('Supplier', on_delete=models.CASCADE)
item_number = models.CharField(max_length=80)
description = models.CharField(max_length=120)
case_quantity = models.CharField(max_length=80)
piece_list_amount = models.CharField(max_length=80)
partner_list_amount = models.CharField(max_length=80)
upload = models.ImageField(upload_to=directory_path)
def __str__(self):
return self.item_number
You can look at my code and implement exactly what you need ... I hope this will be helpful for you:
import os
from Project.settings import BASE_DIR
from apps.showcase.models import Product
from django.core.files import File
obj_id_to_img_filename_mapping = (
(175, 'full_ef58c1a5af252d4459055481b1bbfa76.jpg'),
(176, 'full_2111856a6a092a3c65639aff56070aef.jpg'),
(177, 'full_b8154e9b348561ee295c2d1651ecca3c.gif'),
# ...
)
def update_product_images():
print('Starting upload products images...\n')
for product_id, file_name in obj_id_to_img_filename_mapping:
if file_name:
product = Product.objects.get(pk=product_id)
absolute_filename = os.path.join(BASE_DIR, 'apps/showcase/static/showcase/images/initial_data/product', file_name)
local_file = open(absolute_filename, 'r')
django_file = File(local_file)
product.image.save(file_name, django_file, save=True)
print(absolute_filename + '\n')