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.
Related
I'm using DRF for backend and React for frontend.
In DRF I return link to my local saved file.
Django application takes 8080 port and react 8000.
And when I create Request from Frontend, DRF return path to file with localhost:8000/media/...
I need localhost:8080/media/...
enter image description here
This may be because your backend responded with /media/<file_name> because of this your frontend will add http://localhost:8000/ before the file response.
If you are working in the local environment then you have to change media response by joining your backend URL with file response.
for your solution:
Add BACKEND_URL in your DRF settings as http://localhost:8080/
in the model which stores media file add a #property
class TempModel(models.Model):
file = models.FileField()
#property
def get_file_url(self):
from urllib.parse import urljoin
from django.conf import settings
return urljoin(settings.BACKEND_URL, self.file.url
Add get_file_url in your serializer and use it as the source to the file. OR change your serializer as below so that the response will change in the file field automatically.
class TempModelSerializer(serializers.ModelSerializer):
file = serializers.URLField(sourc="get_file_url", read_only=True)
# other part of the serializer
NOTE: if you use the last option of serializer, make sure you can upload the file from the same API or for better reason change the API to add or update files only. but it is up to your system architecture.
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.
So I'm working with django and file uploads and I need a javascript function to execute after the file has been uploaded.
I have a file upload handler in my views.py which looks like this:
def upload_file(request):
form = UploadFileForm(request.POST, request.FILES)
if form.is_valid():
for f in request.FILES.getlist('fileAttachments'):
handle_uploaded_file(f)
return HttpJavascriptResponse('parent.Response_OK();')
else:
return HttpResponse("Failed to upload attachment.")
And I found a django snippet from http://djangosnippets.org/snippets/341/ and I put the HttpJavascriptResponse class in my views.py code. It looks as follows:
class HttpJavascriptResponse(HttpResponse):
def __init__(self,content):
HttpResponse.__init__(self,content,mimetype="text/javascript")
However, when I upload a file the browser simple renders "parent.Response_OK();" on the screen instead of actually executing the javascript. And Chrome gives me the warning: "Resource interpreted as Document but transferred with MIME type text/javascript"
Is there anyway to get views.py to execute the script?
A better way is to pass the mime to the HttpResponse Object.
See documentation: https://docs.djangoproject.com/en/3.2/ref/request-response/#django.http.HttpRequest.content_type.
return HttpResponse("parent.Response_OK()", content_type="application/x-javascript")
Note - Some previous versions of Django used mimetype instead of content_type:
return HttpResponse("parent.Response_OK()", mimetype="application/x-javascript")
I believe this will work.
return HttpResponse("<script>parent.Response_OK();</script>")
However, you might think about returning a success (200) status code in this case, and then having some javascript in parent attach to the load event of this child, and branch based on return status code. That way you have a separation of view rendering code and view behavior code.
Chase's solution worked for me, though I need to execute more javascript than I care to put in a python string:
from django.http import HttpResponse
from django.contrib.staticfiles.templatetags import staticfiles
...
return HttpResponse("<script src='{src}'></script>".format(
src = staticfiles.static('/path/to/something.js')))
I ended up here looking for a way to serve a dynamic js file using django.
Here is my solution :
return render(request, 'myscript.js', {'foo':'bar'},
content_type="application/x-javascript")
I have a web application which will return a user id based on the first segment of the url, much like Twitter:
http://www.myapplication.com/user-name-goes-here/
It can go deeper too, like so:
http://www.myapplication.com/user-name-goes-here/news/article_1/
In order to break the site down, I am using the following URL routing technique:
(r'^(?P<slug>\w+)/', include('myapp.sites.urls')),
This will then further route the user to the correct page, but as it stands I am having to query the database in every view in order to obtain the user_id based on the first url segment. I was hoping to somehow automate this so I don't have to bloat my views with the same code each time... my solution was to create some middleware which checks the url segment and returns a 404 if its not found:
from django.http import Http404
class DomainMiddleware(object):
def process_request(self, request):
from myapp.sites.models import Sites
dname = request.path.split('/')[1]
if not dname:
return
try:
d = Sites.objects.get(domain__exact=dname)
except Sites.DoesNotExist:
raise Http404
return
This works, but it's trying to parse EVERY request, even those to images, favicons etc.
My question is thus; Is there a way to run this query on every page load without clogging up my views with extra code? If middleware is the solution, how can I modify my code so that it doesn't include EVERY request, only those to successfully routed URLs?
Hope someone can help!
The Django server shouldn't be processing requests for static content URLs - certainly not in production anyway, where you'd have a different web server running to handle that, so this shouldn't be an issue there.
But if you say you'd like this to run for only sucessfully routed URLs, maybe you'd be better of using process_view rather than process_request in your middleware? http://docs.djangoproject.com/en/dev/topics/http/middleware/#process-view
process_view works at view level rather than request level, and provides a view_func argument which you can check so that your code doesn't run when it's the django.views.static.serve view used for serving static media during development.
Whatever happens you should defs be caching that database call if it's going to be used on every view.
I want to store some mp3s in a folder which is not public, can't be directly accessed through the web and allow users to hear/download the songs with a browser only if they are logged in.
How can I do that?
I do my web development with Django, but if I know how it works is enough.
You first need to setup authentication. The django tutorials thoroughly explore this.
You don't' link the mp3's directly, You link to a django script that checks the auth, then reads the mp3 and serves it to the client with a mp3 content type header.
http://yourserver.com/listen?file=Fat+Boys+Greatest+Hits
I assume you use django. Then you can try something like this:
from django.conf import settings
from django.contrib.auth.decorators import login_required
from django.http import HttpResponse
#login_required
def listen(request, file_name):
# note that MP3_STORAGE should not be in MEDIA_ROOT
file = open("%smp3/%s" % (settings.MP3_STORAGE, file_name))
response = HttpResponse(file.read(), mimetype="audio/mpeg")
return response
Note that you will get dramatic speed decrease. Using generator to read file in blocks may help to save memory.
Lazy Method for Reading Big File in Python?
File outside of public access (not in
MEDIA_URL folders)
Check if user logged in
Serve files only via a view, with
unique links for every user
Pseudocode:
class Mp3(models.Model):
file = models.FileField(upload_to=path_outside_of_public_access)
hash = models.CharField(unique=True)
def generate_link_hash(request, file):
return hashlib.md5("%s_%i_%s_%s" % (request.session.session_key, file.id, str(file.date_added), file.hash)) # or however u like
def files_list(request)
""" view to show files list """
for file in files:
file.link_hash = generate_link_hash(request, file)
#login_required
def download_file(request, file_hash, link_hash):
""" view to download file """
file = Mp3.objects.get(hash=file_hash)
if link_hash == generate_link_hash(request, file):
file = open(file.file)
return HttpResponse(file.read(), mimetype="audio/mpeg")
else:
raise Http404
Should do the job enough, but remember - what is once accessed, you have no control where it goes from now on. And that every file download needs reading the file through the app (it's not given statically), which will affect the performance of your app.