Serve raw, dynamic html content from file in Django? - django

I can generate html from a file on the fly and return like this:
from django.http import HttpResponse
response = HttpResponse(mimetype="text/html")
content = "".join(open(filename).readlines())
response._set_content(content)
return response
but is there a better, built in way, in Django 1.5?

The following code is a better method for making a file available for download or viewing, short of streaming (which has some downsides, such as not having a known size).
from django.http import HttpResponse
def serve_file(filename):
response = HttpResponse(mimetype="text/html")
for line in open(filename):
response.write(line)
return response

Django is an MVC framework (well, arguably it's MTV, but the basic principle is similar), so you should be creating templates for that kind of task.

You should configure your webserver to serve static files directly.
If you absolutely have to do it through django you could use static views.

Related

How to dump into files request/response pairs in Django?

I want to store (in files) all request/response pairs of views in a Django app.
How to do this?
I could probably use tcpflow, but would prefer to use a Python solution in Django itself rather than external programs like tcpflow (which also requires root privileges, what I dislike).
You can create a middleware, something like (adapted the example from the doc):
def simple_middleware(get_response):
def middleware(request):
response = get_response(request)
# SAVE REQUEST AND RESPONSE HERE
return response
return middleware
And adding it to the MIDDLEWARE setting.

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.

Get Django views.py to return and execute javascript

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

jQueryUI autocomplete with url as source (am using Django)

I am using Django web-framework for database, page generation etc.
jQueryUI / javascript side of the code
I want to use jQueryUI's autocomplete widget, as my data set will contain about 1,000 entries I wanted to query the database. On the link above it claims you can simply provide a url that returns JSON data:
Autocomplete can be customized to work
with various data sources, by just
specifying the source option. A data
source can be:
* an Array with local data
* a String, specifying a URL
* a Callback
I have taken the default example from the website, which works on my system.
However if I change the following:
$( "#tags" ).autocomplete({
source: availableTags,
});
to
$( "#tags" ).autocomplete({
source: "/search/", // url that provides JSON data
});
the autocomplete functionality doesn't work at all.
I've tried making the url actually return an error (to see if it uses it) and putting in the full url http://localhost:8000/search/, nothing works.
Django part of the code
In url.py
...
(r'^search/$', 'search'),
...
In views.py
from django.http import HttpRequest, HttpResponse
from django.utils import simplejson
...
def search(request):
HttpResponse(simplejson.dumps(["hello", "world"]))
# Will implement proper suggestions when it works.
There must be something wrong with my code and I would greatly appreciate any help you can offer :)
EDIT SOLUTION:
Thanks to #Thierry realised it didn't have a return statement before, have added that so I now looks like so:
def search(request):
output = ["hello", "world"]
return HttpResponse(simplejson.dumps(output))
And it actually works!
(It always seems to be the really small bugs that waste the most of of my time, grrr)
I return my ajax response like the following:
def search(request):
output = ["hello", "world"]
return HttpResponse(output, mimetype="application/javascript")
If you access the url http://localhost:8000/search/, you should see the output. Once you see the output, the autocomplete should work.
There are some changes in json serialization API in later versions
For django 1.6 use
import json
from django.http import HttpResponse
....
return HttpResponse(json.dumps(my_data_dictionary))
For django 1.7+ do it like here

Allow users to play mp3 files but don't expose them directly on the web

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.