how to download a filefield file in django view - django

I have filefield in my django model:
file=models.FileField(verbose_name=u'附件',upload_to='attachment/%Y/%m/%d',max_length=480)
This file will display in the web page with link "http://test.com.cn/home/projects/89/attachment/2012/02/24/sscsx.txt"
What I want to do is when user click the file link, it will download the file automatically;
Can anyone tell me how to do this in the view?
Thanks in advance!

You can try the following code, assuming that object_name is an object of that model:
filename = object_name.file.name.split('/')[-1]
response = HttpResponse(object_name.file, content_type='text/plain')
response['Content-Disposition'] = 'attachment; filename=%s' % filename
return response
See the following part of the Django documentation on sending files directly: https://docs.djangoproject.com/en/dev/ref/request-response/#telling-the-browser-to-treat-the-response-as-a-file-attachment

https://docs.djangoproject.com/en/dev/ref/models/fields/#django.db.models.FileField.storage
All that will be stored in your database is a path to the file (relative to MEDIA_ROOT). You'll most likely want to use the convenience url function provided by Django. For example, if your ImageField is called mug_shot, you can get the absolute path to your image in a template with {{ object.mug_shot.url }}.

Related

python django url shows old image when exachanging

when running the Django server and hitting the URL http://127.0.0.1:8000/media/pictures/h2.jpg, I was getting the requested image (jpg).
Now I exchange the jpg by a file, which is also called h2.jpg but when I call the same URL again
it still shows the old picture.
How to handle that?
I need to do it automatically by the backend or somehow --> without user action
Django version 2.1.7
You can use this middleware
from django.utils.cache import add_never_cache_headers
class NoCachingMiddleware(object):
def process_response(self, request, response):
add_never_cache_headers(response)
return respons
from this question:
https://stackoverflow.com/a/13489175/11027652
So, now the new file has a timestamp included in the filename. By this I can first read all files available in the folder and then take the first one to create a NEW dynamic filepath.

Is it possible to swap FileField's filename during download/referencing on FE?

I'm using Django+DRF to allow upload/keep/serve user uploaded asset files. I need to let users to download the uploaded assets later. Upon a file upload I need to md5-hash its real name and save it to filesystem with that hash as the filename. Then, when the user wants to download/view it on FE, say he's uploaded a file 'cute_cat.jpg', I want him to get the file named 'cute_cat.jpg' and not 3c808e77fc1b0aee4435533690be458d (the name is one problem, the other one is that browser serves files w/o extensions as application/octet-stream and I want it to render '.jpg' (originally) files as images)
I feel that I need to inject a HTTP header with 'Content-Disposition: attachment; filename=cute_cat.jpg' (I'm storing the real filename in DB) somewhere on the way to DRF's Response(), but I'm not sure at which point I'm to do this and even if it's possible...
I've tried a bunch of stuff, mainly implementing custom fields for the serializer and injecting a custom URL there, but obviously that's not the way to it, because there's nowhere to inject headers to a text URL and there's no point trying to output a Request object with headers in an API view...
This is my model:
def get_full_path(instance, filename):
return '/'.join([
instance.user.name,
hashlib.md5(filename.encode()).hexdigest()
])
class CustomAsset(models.Model):
file = models.FileField(blank=False, null=False, upload_to=get_full_path)
real_file_name = models.CharField(max_length=255, blank=False, null=False)
user = models.ForeignKey(...)
Nothing is overriden in serializer/API view.
Thanks a lot in advance.
First you need to understand in the API, all you can return is the URL.
Now it's the browser duty to handle the file formatting and content type management.
What you will need to do here is to manage the file through your application controller. When you return the url you return the url something like.
http://example.com/file/<md5>
And this url when accessed serves the file via a controller, with modified content disposition header and returns the file as response.
A simple example would look like.
In your urls.py , Add a new route.
url(r'^file/(?P<identifier>[\w\d\-_]+)$', custom_file_server, name="custom_file_server"),
And then serve the file according to your needs.
A simple example would something like this.
def custom_file_server(request, identifier):
## Get the file name from db by querying from identifier
file_name = "abc.jpg"
absolute_file_path = os.path.join(settings.BASE_DIR, "media/"+identifier)
response = FileResponse(open(absolute_file_path, 'rb'))
response['Content-Disposition'] = "attachment; filename={}".format(file_name)
response['Content-Type'] = 'image/jpeg'
return response
The above code is not tested but the concept remains this.
Let me know if you have any questions.

django reportlab attach pdf to email, save pdf to server, show pdf in browser

There are 3 questions I have about a generated pdf using report lab in django which I can't seem to find a good answer for. The documentation on the django site only covers how to generate a pdf for download. But how do I attach the generated pdf to an email and send it instead of downloading it? How do I save the pdf to a directory on the server instead of downloading it? How do I display the pdf in the browser window instead of downloading it? Just use the django documentation example:
from reportlab.pdfgen import canvas
from django.http import HttpResponse
def some_view(request):
# Create the HttpResponse object with the appropriate PDF headers.
response = HttpResponse(content_type='application/pdf')
response['Content-Disposition'] = 'attachment; filename="somefilename.pdf"'
# Create the PDF object, using the response object as its "file."
p = canvas.Canvas(response)
# Draw things on the PDF. Here's where the PDF generation happens.
# See the ReportLab documentation for the full list of functionality.
p.drawString(100, 100, "Hello world.")
# Close the PDF object cleanly, and we're done.
p.showPage()
p.save()
return response
To display de PDF on your browser instead of downloading it you just have to remove the word attachment from
response['Content-Disposition'] = 'attachment; filename="somefilename.pdf"'
you would have something like this
response['Content-Disposition'] = 'filename="somefilename.pdf"'
You can pass a regular filename to Canvas() instead of a file-like object. You should generally pass in as the next parameter the pagesize - default is A4.
For all the details, download the user's guide & reference guide from ReportLab:
http://www.reportlab.com/docs/reportlab-userguide.pdf
See page 10.

Django: Get ImageField url in view

I am trying to get ImageField absolute path in Django view so I can open the image, write on it something and then serve it to user.
I have problem getting absolute path for the image which is saved in media folder.
item = get_object_or_404(Item, pk=pk)
absolute_url = settings.MEDIA_ROOT + str(item.image.path)
I get error, that item.image does not have path (The 'banner' attribute has no file associated with it.). item.image is ImageField and I'd like to know how to get absolute path of the image saved in image field (within Django view).
When configured correctly, use .url: item.image.url. Check the docs here.
Maybe this way?
#property
def get_absolute_image_url(self):
return "{0}{1}".format(settings.MEDIA_URL, self.image.url)
see How can I get a list of absolute image URLs from a Django QuerySet?
I just figured out what was the problem... absolute image path is saved in file variable.
Example (in view):
item = Item.objects.get(pk=1)
print item.file # prints out full path of image (saved in media folder)

How do I serve a text file from Django?

I am writing a Django based website, but need to serve a a simple text file. Is the correct way to so this by putting it in the static directory and bypassing Django?
If the file is static (not generated by the django app) then you can put it in the static directory.
If the content of this file is generated by Django then you can return it in a HttpResponse with text/plain as mimetype.
content = 'any string generated by django'
return HttpResponse(content, content_type='text/plain')
You can also give a name to the file by setting the Content-Disposition of the response.
filename = "my-file.txt"
content = 'any string generated by django'
response = HttpResponse(content, content_type='text/plain')
response['Content-Disposition'] = 'attachment; filename={0}'.format(filename)
return response
I agree with #luc, however another alternative is to use X-Accel-Redirect header.
Imagine that you have to serve big protected (have to login to view it) static files. If you put the file in static directory, then it's access is open and anybody can view it. If you serve it in Django by opening the file and then serving it, there is too much IO and Django will use more RAM since it has to load the file into RAM. The solution is to have a view, which will authenticate a user against a database, however instead of returning a file, Django will add X-Accel-Redirect header to it's response. Now since Django is behind nginx, nginx will see this header and it will then serve the protected static file. That's much better because nginx is much better and much faste at serving static files compared to Django. Here are nginx docs on how to do that. You can also do a similar thing in Apache, however I don't remember the header.
I was using a more complex method until recently, then I discovered this and this:
path('file.txt', TemplateView.as_view(template_name='file.txt',
content_type='text/plain')),
Then put file.txt in the root of your templates directory in your Django project.
I'm now using this method for robots.txt, a text file like the original asker, and a pre-generated sitemap.xml (eg, change to content_type='text/xml').
Unless I'm missing something, this is pretty simple and powerful.
I had a similar requirement for getting a text template for a form via AJAX. I choose to implement it with a model based view (Django 1.6.1) like this:
from django.http import HttpResponse
from django.views.generic import View
from django.views.generic.detail import SingleObjectMixin
from .models import MyModel
class TextFieldView(SingleObjectMixin, View):
model = MyModel
def get(self, request, *args, **kwargs):
myinstance = self.get_object()
content = myinstance.render_text_content()
return HttpResponse(content, content_type='text/plain; charset=utf8')
The rendered text is quite small and dynamically generated from other fields in the model.