Access Multiple PDF Files with Django Rest Framework and REACT frontend - django

I am trying to access the uploaded files from my Django-rest-Framework which I uploaded with my React Frontend.
CourseDocument:
class CourseDocument(models.Model):
title = models.CharField(max_length=30, default='')
document = models.FileField(upload_to='courses')
course = models.ForeignKey(to='Course', on_delete=models.SET_NULL, null=True)
To my DRF endpoint:
#action(methods=\['GET', 'POST'\], detail=True, url_path='documents', permission_classes=EMPLOYEE_PERMISSION)
def course_documents(self, request, \*args, \*\*kwargs):
if request.method == 'GET':
qs = CourseDocument.objects.filter(course_id=kwargs['pk'])
fs = FileSystemStorage()
filename = qs.first().document.path
if fs.exists(filename):
with fs.open(filename) as pdf:
response = HttpResponse(pdf, content_type='application/pdf')
response['Content-Disposition'] = 'attachment; filename="mypdf.pdf"'
return response
else:
print("NOT FOUND")
if request.method == 'POST':
serializer = CourseDocumentSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(data=serializer.data, status=200)
else:
return Response(data=serializer.errors, status=400)
return Response(status=200)
I tried it so far with the FileSystemStorage to send it in an HTTP Response with content type application/pdf.
This did work, but only for one single PDF File.
I want to avoid to pass the pdf as a link to my backend because of security reasons.
How can I achieve sending multiple pdf files to my frontend?

Related

How to serialize an already existing image to save in a models.ImageField param?

I want to create Note object which one of the fields of the model is an ImageField using Django Rest Framework.
I can already create objects and update all different fields using my API, except for images.
My code:
models.py
class Note(OwnedModel):
note_id = models.UUIDField(primary_key=True,
default=uuid.uuid4,
editable=False)
# note_owner = models.ForeignKey(, null=True, blank=True, on_delete=models.SET_NULL)
note_name = models.CharField(max_length=50)
body = models.TextField()
updated = models.DateTimeField(auto_now=True)
created = models.DateTimeField(auto_now_add=True)
qr_image = models.ImageField(upload_to='notes', null=True)
def __str__(self):
return self.note_name[0:50]
class Meta:
ordering = ['-updated']
views.py
#api_view(['GET', 'POST'])
def getNote(request, pk=None):
if request.method == 'GET':
note = Note.objects.get(note_id=pk)
serializer = NoteSerializer(note, many=False)
return Response(serializer.data)
elif request.method == 'POST':
_data = request.data.copy()
owner = request.user.id
_data["owner"] = owner
# Generate QR code
qr_image = generate_qr(_data["note_name"])
# HOW TO PASS THE IMAGE TO THE SERIALIZER?
_data["qr_image"] = qr_image
# _data["qr_image"] = qr_image[0]
# _data["qr_image"] = qr_image[1]
serializer = NoteSerializer(data=_data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(status=status.HTTP_400_BAD_REQUEST)
serializers.py
class NoteSerializer(ModelSerializer):
class Meta:
model = Note
fields = '__all__'
qr_code.py
import qrcode
def generate_qr(qr_file_name=None):
qr = qrcode.QRCode(
version=1,
# error_correction=qrcode.constants.ERROR_CORRECT_L,
box_size=4,
border=3,
)
qr.add_data(qr_file_name)
qr.make(fit=True)
img = qr.make_image()
# img = qr.make_image(fill_color="black", back_color="white")
path='images/notes/'+str(qr_file_name)+'.jpg'
img.save(path)
return path, img
The QR code is properly generated and saved in the upload path perfectly.
What I cannot manage to build line _data["qr_image"] = qr_image correctly, or if I need to return the image in a different way from the generate_qr function. Everything else it is working well (for example create the Note object form the Admin and uploading the qr image).
#api_view(['GET', 'POST'])
def getNote(request, pk=None):
if request.method == 'GET':
# automatically raise 404 if obj does not exist
note = get_object_or_404(Note.objects, note_id=pk)
# many=False is default, dont need that
serializer = NoteSerializer(note)
return Response(serializer.data)
elif request.method == 'POST':
serializer = NoteSerializer(data=request.data)
# raise_exception=True will raise validation error (400) automatically
serializer.is_valid(raise_exception=True)
# get note name after validation to be sure it has proper length etc.
qr_image = generate_qr(serializer.validated_data.get("note_name"))
# attributes provided here will bypass validation
# and will be injected directly to model create method
serializer.save(
owner=request.user,
qr_image=qr_image
)
return Response(serializer.data, status=status.HTTP_201_CREATED)
Im not sure that your generate_qr function should save image in the given path because Note should do it for you on create.
Tip: check the viewsets.GenericViewSet class - it will properly split your view into methods and makes the life easier.

Upload in Django

I was trying to understand how to upload files using Django, so I used the example (latest version, upload is working):
https://github.com/axelpale/minimal-django-file-upload-example
I have a few Questions now:
How do I set a max file size? (I have checked the documentation of Django, but I don't get it)
Is there a way for me to read the file before the user uploads it?
(i.e a program that checks certain things and if they are ok, it can be uploaded)
Here is some code...
model.py:
class Document(models.Model):
name= models.CharField(max_length=500)
docfile= models.FileField(upload_to='documents/%Y/%m/%d', verbose_name="", validators=[validate_file_size])
def __str__(self):
return self.name + ": " + str(self.docfile)
validators.py:
def validate_file_size(value):
filesize= value.size
if filesize > 20971520:
raise ValidationError("File too big")
else:
return value
views.py:
def uploadView(request):
message = 'Upload your .csv-File'
if request.method == 'POST':
form = documentForm(request.POST, request.FILES)
if form.is_valid():
newDoc = Document(docfile=request.FILES['docfile'])
newDoc.save()
return redirect(uploadView)
else:
message = 'The form is not valid.'
else:
form = documentForm()
documents = Document.objects.all()
context = {'documents': documents, 'form': form, 'message': message}
return render(request, 'upload.html', context)

How to get file path from user uploaded images, for sending IDs to stripe api not for storing in a database?

I am not too sure if this is possible or not. Using stripes API singing up a user requires an ID picture, front and back, so here is my form for that:
class IDuploadForm(forms.Form):
id_front = forms.ImageField()
id_back = forms.ImageField()
here is an example of creating a file in stripe from the API:
with open("/path/to/a/file.jpg", "rb") as fp:
stripe.File.create(
purpose="dispute_evidence",
file=fp
)
My goal is to not have to store the users images on my own server, as they are ID documents, and just be able to send them right to the stripe API, but I have tried this and get errors from stripes side of things
Here is the view I have wrote but does not work(think i am not handling file correctly):
class CreateStripeAccount_ID(View):
form = IDuploadForm
template_name = 'id_upload.html'
def get(self, request, *args, **kwargs):
form = self.form()
return render(request, self.template_name, {'form':form})
def post(self, request, *args, **kwargs):
form = IDuploadForm(request.POST, request.FILES)
if form.is_valid():
krop = Krop.objects.get(owner=self.request.user)
str_acc_id = krop.stripe_acc_id
id_front = form.cleaned_data['id_front']
id_back = form.cleaned_data['id_back']
stripe.api_key = settings.STRIPE_TEST_SEC_KEY
#file_id_front = stripe.File.create(
# purpose='identity_document',
# file=id_front
# )
#file_id_back = stripe.File.create(
# purpose='identity_document',
# file=id_back
# )
return redirect('home')
return redirect('home')

How to upload file larger than 2.5MB to django?

I my goal is to upload file larger than 2.5MB to django server. I can upload file, if it is smaller than 2.5MB, if file is bigger then 2.5MB I get 413 Payload too large in browser. And I do not understand why.
I set MAX_UPLOAD_SIZE = 429916160 MEDIA_ROOT = os.path.join(BASE_DIR, 'files')
MEDIA_URL = '/files/' and FILE_UPLOAD_MAX_MEMORY_SIZE = MAX_UPLOAD_SIZE in my settings.py. Currently I use django development server without apache or nginx.
My models.py:
def validate_file_extension(value):
ext = os.path.splitext(value.name)[1] # [0] returns path+filename
valid_extensions = ['.vsdx']
if not ext.lower() in valid_extensions:
raise ValidationError(u'Unsupported file extension.')
class UpLoadFile(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
file = models.FileField(upload_to=path, validators=[validate_file_extension])
uploaded_at = models.DateTimeField(default=timezone.now)
def __str__(self):
return self.user.username + '/' + self.file.name
class UploadFileForm(forms.ModelForm):
file = forms.FileField(required=True, label="")
class Meta:
model = UpLoadFile
fields = ('file',)
views.py:
if request.method == 'GET':
upload_file_form = UploadFileForm()
all_files = UpLoadFile.objects.select_related("user").filter(user__username=request.user).all().order_by("-uploaded_at")
return render(request, 'interface/files.html', {'page_title': 'Datoteke',
'files': all_files,
'upload_file_form': upload_file_form})
elif request.method == 'POST':
if "upload-file" in request.POST:
file_name = request.FILES.get("file")
username = request.user
if bool(os.path.exists(f'files/{username}/{file_name}')):
messages.error(request, "Datoteka s tem imenom že obstaja!")
return redirect('files')
else:
upload_file_form = UploadFileForm(request.POST, request.FILES)
upload_file_form.instance.user = username
if upload_file_form.is_valid():
upload_file_form.save()
messages.success(request, "Datoteka je uspešno dodana!")
return redirect('files')
messages.error(request, "Te vrste datoteke ni mogoče naložiti na server. Preverite če ima datoteka .vsdx končnico.")
return redirect('files')
Were and what should I set to be able to upload file larger than 2.5MB?
I would appreciate any advice on how to handle this kind of file.
Include this in your settings.py file
DATA_UPLOAD_MAX_MEMORY_SIZE = 50242880

FIle upload with chunks: avoid saving it twice

I use a custom function to upload a file splitting it in chunks, as documented here.
My problem is that calling save() after handle_uploaded_file() uploads my file twice, one into "MEDIA_URL/my_path" dir and one into "MEDIA_URL".
But I would like to have only one upload, the one with chunks.
It is possible to force save() to make 'chunked' upload?
Or should I use different approaches?
Thank you.
models.py
class ShapeFile(models.Model):
name = models.CharField(max_length=100)
srid = models.ForeignKey(SpatialRefSys)
user = models.ForeignKey(User)
color_table = models.ForeignKey(ColorTable)
file = models.FileField(upload_to="my_path")
class Meta:
unique_together = ('name', 'user')
forms.py
class UploadForm(ModelForm):
class Meta:
model = ShapeFile
fields = ('name','user','srid','file','color_table')
widgets = {'srid': TextInput(),
'user': HiddenInput()
views.py
def handle_uploaded_file(fileName, filePath):
with open(filePath, 'wb+') as destination:
for chunk in fileName.chunks():
destination.write(chunk)
#login_required
def shapeIng(request):
if request.method == 'POST':
form = UploadForm(request.POST, request.FILES)
if form.is_valid():
req = request.POST
# Split uploaded file into chunks
fileName = request.FILES['file']
filePath = ShapeFile(file=fileName).file.path
handle_uploaded_file(fileName, filePath)
form.save()
messages.success(request, 'Shapefile upload succesful!')
return redirect('shapeCreated')
else:
messages.error(request, 'Something went wrong uploading Shapefile.')
else: # request.method == 'GET'
form = UploadForm(initial={'user': request.user})
return render_to_response('my_app/base_shapeIngestion.html',
{'form': form},
context_instance=RequestContext(request))
change your view function to this:
def testupload2(request):
if request.method == 'POST':
file_name=request.FILES['file']
form = SomeForm(request.POST, request.FILES)
if form.is_valid():
dest_file = open('C:/prototype/upload/'+ str(file_name), 'wb+')
path = 'C:/prototype/upload/'+ str(file_name)
for chunk in request.FILES['file'].chunks():
dest_file.write(chunk)
dest_file.close()
t = get_template("testupload2.html")
lst = os.listdir('C:/downloads/prototype/prototype/upload/')
html = t.render(Context({'MEDIA_URL':'http://127.0.0.1:8000/site_media/'}))
return HttpResponse(html)