how to write File Download with django Rest framework? - django

I have a model with filefield with xls and xlsx and person who uploaded it i need to write api view in DRF that returns download on front end how can my view be?
models.py
class FileuploaderView(BaseModel):
file = models.FileField(
upload_to='',
validators=[FileExtensionValidator(['xls', 'xlsx'])],
)
created_by = models.ForeignKey(
'other model',
related_name= '',
null=True,
on_delete=models.SET_NULL,
)
views.py:
def DownloadView(APIView):
def get(self, request, id, format=None):
queryset = Model.objects.get(id=id)
file_handle = queryset.file.path
document = open(file_handle, 'rb')
response = HttpResponse(FileWrapper(document), content_type='')
response['Content-Disposition'] = 'attachment; filename="%s"' % queryset.file.name
return response
Is it the

You might want this:
file_path = file_url
FileData = open(file_path,"r")
response = HttpResponse(FileData,content_type='application/msword')
response['Content-Disposition'] = 'attachment; filename=NameOfFile'
return response
also checkout this

Related

Django downloading excel file return object name instead of excel file

I have a website where we download a xl file i have my view as below instead of returning the excel file its returning the text file with name of the object inside it how do i solve this
views.py:
def my_view(request):
obj = model.objects.first()
response = HttpResponse(file, content_type='
application/vnd.ms-excel',
)
return response
urls.py:
path('temo/fill',views.my_view,name = 'my-view')
models.py
class Model(BaseModel, SingletonModel):
file = models.FileField(
upload_to='',
validators=[FileExtensionValidator([''])]
)
person_uploaded = models.ForeignKey(
'somemodel',
related_name='s',
null=True,
on_delete=models.SET_NULL,
)
admin.py:
#admin.register(tTemplate)
class TemplateAdmin(admin.ModelAdmin):
list_display = ('file','person_uploaded',)
readonly_fields = ('person_uploaded',)
def save(self, request):
if not self.id:
self.person_uploaded = request.user
super().save()
obj = Plate.objects.first() # this will return you object
in objects there are multiple attributes there you've to get only your file attribute like this
#api_view(['GET',])
def my_view(request):
obj = Plate.objects.first()
response = HttpResponse(obj.file, content_type='
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,
application/vnd.ms-excel')
return response
file = model.objects.first() # here you are returning the entire object
instead of a file so you'll obviously get the object name instead of a xl file.
Mos importantly is the xl file inside your object

How to use data posted for one view into another view in django rest

I am working on a project in which user enters some ranges like (starting_date, ending_date, starting_roll_num, ending_roll_num, and subject) and it queries the DB and returns a csv file
but i want to add another feature which enables the user to also get the remaining data after he has entered the ranges and downloaded the first file but for this I have to make an other function, the problem is how will I use the data posted on the first function.
Here is my code:
serializer.py
class DatasetGeneratorSerializer(serializers.Serializer):
start_roll = serializers.IntegerField()
end_roll = serializers.IntegerField()
start_date = serializers.DateField()
end_date = serializers.DateField()
subject = serializers.IntegerField()
def create(self, validated_data):
pass
views.py
#api_view(['POST'])
#authentication_classes([SessionAuthentication, BasicAuthentication, TokenAuthentication])
#permission_classes([IsAuthenticated])
def attendance_datasetgenerator(request):
serializer = DatasetGeneratorSerializer(request.data)
start_roll = serializer.data['start_roll']
end_roll = serializer.data['end_roll']
start_date = serializer.data['start_date']
end_date = serializer.data['end_date']
subject = serializer.data['subject']
att= Attendance.objects.filter(date__range=(start_date,end_date), student__pk__range=(start_roll,end_roll), subject__exact=subject)
df1 = DataFrame(att.values())
path = 'attendance_dataset.csv'
csv1 = df1.to_csv('attendance_dataset.csv')
response = HttpResponse(csv1, content_type='text/csv')
response['Content-Disposition'] = 'attachment; filename=file1.csv'
return response

How to save Audio file to django model from the server itself with REST API

I am:
Sending .wav file with API Class
Converting to .mp3 with pydub
Saving converted file to MEDIA_ROOT
I want:
Save the converted file (.mp3) to my model.
I have:
AWS S3 bucket on production, everything saved in my models lands there.
I have model with FileField:
def content_file_name(instance, filename):
filename = "{}_".format(today.strftime("%y-%d-%m")) + filename
return os.path.join('content', "{}".format(instance.user.email), 'tracks', filename)
class Track(models.Model):
user = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE, null=True
)
# ...
file = models.FileField(
upload_to=content_file_name, null=True, blank=True)
I am using MultiPartParser and audio gets saved correctly but the original one in .wav. I want to save mp3 once I convert it.
from django.core.files.storage import FileSystemStorage
class TrackAPIView(UpdateAPIView):
serializer_class = FileSerializer
permission_classes = (permissions.IsAuthenticated,)
parser_classes = [MultiPartParser, ]
queryset = Track.objects.all()
lookup_field = 'uid'
def put(self, request, *args, **kwargs):
file_obj = request.data
# Using File storage to save file for future converting
fs = FileSystemStorage()
file_name = fs.save(audio_file.name, audio_file)
audio_file_url = fs.url(file_name)
# Preparing paths for convertion
upstream = os.path.dirname(os.path.dirname(os.path.dirname(
os.path.abspath(__file__))))
path = os.path.join(upstream, 'media', audio_file.name)
mp3_filename = '.'.join([audio_file.name.split('.')[0], 'mp3'])
new_path = os.path.join(
upstream, 'media', mp3_filename)
# Converting to mp3 here
wma_version = AudioSegment.from_file(path, "wav")
wma_version.export(new_path, format="mp3")
user_id = self.request.user.id
# I was trying to create a Track instance, the mp3 get's saved but it is not being saved using location specified in models.
track = Track.objects.create(user_id=user_id)
track.file.name = mp3_filename
track.save()
serializer = FileSerializer(track, data={})
if not serializer.is_valid():
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
WHen I am trying to use this solution:
https://docs.djangoproject.com/en/3.1/topics/files/#using-files-in-models
I am getting error:
{
"file": [
"No file was sent."
]
}
Any idea what I might be doing wrong? I want to save the converted mp3 file as it was an incoming file in request.FILES['file']
But I am not sure How to prepare it and if I should use the serialiser.
Thank you for any ideas

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.
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)
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.

django imagekit: set ProcessedImageField from image url

I have got an image url and I want to set a ProcessedImageField attribute from it during object saving. So far I have got this:
class Video(Media):
url = models.URLField('url', max_length=256, default='')
embed_url = models.URLField('embed url', max_length=256, default='')
thumbnail = ProcessedImageField(upload_to='uploads',
processors=[ResizeToFit(width=1024, height=1024, upscale=False)],
format='JPEG',
options={'quality': 75})
def save(self, *args, **kwargs):
from django.core.files.temp import NamedTemporaryFile
import shutil
import requests
import re
params = {
'url': self.url,
'autoplay': 1,
'format': 'json',
}
try:
data = requests.get('http://www.youtube.com/oembed', params=params).json()
embed_url = re.search('src=[\'"]([^\'"]*)[\'"]', data['html']).group(1)
thumbnail_url = data['thumbnail_url']
except:
pass
response = requests.get(thumbnail_url, stream=True)
img_temp = NamedTemporaryFile(delete=True)
shutil.copyfileobj(response.raw, img_temp)
# now image data are in img_temp, how to pass that to ProcessedImageField?
super(Video, self).save(*args, **kwargs)
You should be able to save directly to that property at that point.
self.thumbnail.save("filename.ext", img_temp)
This is the resulting code (without error handling) of mine. In the end, I did in in a simpler manner by avoiding a temporary file and using ContentFile instead.
class Video(Media):
url = models.URLField('url', max_length=256, default='')
embed_url = models.URLField('embed url', max_length=256, default='')
author = models.CharField('author', max_length=64, default='', blank=True)
thumbnail = ProcessedImageField(upload_to='uploads',
processors=[ResizeToFit(width=1024, height=1024, upscale=False)],
format='JPEG',
options={'quality': 75})
def save(self, *args, **kwargs):
from django.core.files.base import ContentFile
import requests
import re
params = {
'url': self.url,
'format': 'json',
}
data = requests.get('http://www.youtube.com/oembed', params=params).json()
embed_url = re.search('src=[\'"]([^\'"]*)[\'"]', data['html']).group(1)
thumbnail_url = data['thumbnail_url']
author = data['author_name']
title = data['title']
image_data = requests.get(thumbnail_url, stream=True).raw.data
self.thumbnail.save(title, ContentFile(image_data), save=False)
self.embed_url = embed_url
self.author = author
self.title = title
super(Video, self).save(*args, **kwargs)
Ok, i've ended with this code for Python 3 :)
it has built-in retries with timeouts between them and support for downloading large files
def save_image_from_url(self, image_url):
s = requests.Session()
retries = Retry(total=5,
backoff_factor=0.1,
status_forcelist=[500, 502, 503, 504])
s.mount('https://', HTTPAdapter(max_retries=retries))
response = s.get(image_url, stream=True, timeout=9)
# here just use whatever name you want, I've just retrieve the path from my custom field
folder_name = Artist.image.field.upload_to.sub_path
random_name = uuid.uuid4().hex + ".png"
# creating folder if it doen't exist
try:
os.makedirs(os.path.join(settings.MEDIA_ROOT, folder_name))
except OSError as e:
if e.errno != errno.EEXIST:
raise
# loading image to tmp location and saving it, it's for large files because we can't handle them in memory
tmp = tempfile.NamedTemporaryFile(delete=True)
try:
tmp.write(response.raw.read())
with open(tmp.name, 'rb') as f:
self.image.save(random_name, f)
finally:
tmp.close()
Where self.image is ProcessedImageField