How to display data resulting from POST in django view? - django

I have a form that takes a path as input, analyzes files and subfolders in that directory, stores information in a database, then displays some statistics to the user about the files just parsed. This is done currently using a Django view and render_to_response.
According to everything I have read, it's incorrect to use anything other that HttpResponseRedirect when dealing with a POST, as a page generated with POST data would resubmit the form if the page were refreshed.
My issue here is that there's a large amount of summary data ultimately displayed as a result of analyzing files on the provided path. How can I display that data with an httpResponseRedirect? Sending it as GET parameters using django.core.urlresolvers.reverse seems infeasible due to the amount of data.

You could put the data on request.session
http://www.djangobook.com/en/beta/chapter12/#cn36
http://docs.djangoproject.com/en/1.2/topics/http/sessions/

I assume that your POST handle creates some databse object out of a submitted form data, is this correct? If so, then you can do something like this (:
my_obj = MyModel.objects.create(**form.cleaned_data) # This is the part yuo already have, most probably expressed with some other code, but still..
return HttpResponseRedirect('/url/to/redirect/?id=%d' % obj.id)
The redirect like should in fact use reverse() function, and I think that you should have an URL for editing MyModel objects. Then you could do:
return HttpResponseRedirect(reverse('edit-mymodel', (), {'id': obj.id}))
The relevant URL would look like:
url('^edit/mymodel/(?P<id>\d+)$', 'apps.myapp', name='edit-mymodel')

A rough but simple solution is to write your data in a json text file and then read it in your redirect page (this will also save you from rebuilding data on refreshing the page)

Related

Is there an HTML sanitizer library for django to block injection attacks?

I'm trying to find something that will return an exception upon finding anything that even remotely looks like HTML or Javascript. I've figured out how to do it for individual views, but it's not a scalable solution, and ultimately I need to prevent code from being saved to the database no matter what view gets targeted by the injection attack.
Here is the functionality I'm looking for.
ILLEGAL_CHARS = '<>[]{}():;,'.split()
# bunch of code in between
for value in [company_name, url, status, information, lt_type, company_source]:
if any(char in value for char in ILLEGAL_CHARS):
raise Exception(f"You passed one of several illegal characters: {ILLEGAL_CHARS}")
I'm using django rest framework so I have to handle it on the backend. Thanks.
actually you don't nead to sanitize any user input because when you show them int the template the jinja {{object}} will make sure that no html or java script will be executed until you mark them as safe {{object|safe}} but if you want want not to save them in database that might help Sanitizing HTML in submitted form data

Ember-Data 1.13.X : How to request included resources?

I'm converting my app over to the new version of ember-data (1.13.5).
I'd like to be able to request a set of resources (e.g. this.store.findAll('post')), maintain the background reloading behaviour that comes out of the box, but also request that a set of related resources be included from the server.
i.e. something like:
this.store.findAll('post', { include: ["comments"] }
This can obviously be done with a query, but I'm assuming that kills all of the background reloading stuff?
I think what you are trying to do is sideload your comments together with the post.
I don't know how your server code for that is written, for instance in my case where I use laravel for the serverside,
I would check for the include parameter in the controller code for retrieving the post. If include comments directive has been specified, then I would take advantage of a builtin mechanism that laravel provides where you specify whether you want a model with its related models, i.e return post->with('comments');
And then with the help of a custom json serializer, you can extract the comments and add to the json for the post .
But outside of laravel, an algorithm like this would do in the serverside code for retrieving posts
Retrieve all the posts.
Check for the include parameter. If it's specified, retrieve the comments that belong to each post.
Then write code that creates a json result merging the json result for post with its comments together.

Removing query string from url in django while keeping GET information

I am working on a Django setup where I can receive a url containining a query string as part of a GET. I would like to be able to process the data provided in the query string and return a page that is adjusted for that data but does not contain the query string in the URL.
Ordinarily I would just use reverse(), but I am not sure how to apply it in this case. Here are the details of the situation:
Example URL: .../test/123/?list_options=1&list_options=2&list_options=3
urls.py
urlpatterns = patterns('',
url(r'test/(P<testrun_id>\d+)/'), views.testrun, name='testrun')
)
views.py
def testrun(request, testrun_id):
if 'list_options' in request.GET.keys():
lopt = request.GET.getlist('list_options')
:
:
[process lopt list]
:
:
:
:
[other processing]
:
:
context = { ...stuff... }
return render(request, 'test_tracker/testview.html', context)
When the example URL is processed, Django will return the page I want but with the URL still containing the query string on the end. The standard way of stripping off the unwanted query string would be to return the testrun function with return HttpResponseRedirect(reverse('testrun', args=(testrun_id,))). However, if I do that here then I'm going to get an infinite loop through the testrun function. Furthermore, I am unsure if the list_options data that was on the original request will still be available after the redirect given that it has been removed from the URL.
How should I work around this? I can see that it might make sense to move the parsing of the list_options variable out into a separate function to avoid the infinite recursion, but I'm afraid that it will lose me the list_options data from the request if I do it that way. Is there a neat way of simultaneously lopping the query string off the end of the URL and returning the page I want in one place so I can avoid having separate things out into multiple functions?
EDIT: A little bit of extra background, since there have been a couple of "Why would you want to do this?" queries.
The website I'm designing is to report on the results of various tests of the software I'm working on. This particular page is for reporting on the results of a single test, and often I will link to it from a bigger list of tests.
The list_options array is a way of specifying the other tests in the list I have just come from. This allows me to populate a drop-down menu with other relevant tests to allow me to easily switch between them.
As such, I could easily end up passing in 15-20 different values and creating huge URLs, which I'd like to avoid. The page is designed to have a default set of other tests to fill in the menu in question if I don't suggest any others in the URL, so it's not a big deal if I remove the list_options. If the user wishes to come back to the page directly he won't care about the other tests in the list, so it's not a problem if that information is not available.
First a word of caution. This is probably not a good idea to do for various reasons:
Bookmarking. Imagine that .../link?q=bar&order=foo will filter some search results and also sort the results in particular order. If you will automatically strip out the querystring, then you will effectively disallow users to bookmark specific search queries.
Tests. Any time you add any automation, things can and will probably go wrong in ways you never imagined. It is always better to stick with simple yet effective approaches since they are widely used thus are less error-prone. Ill give an example for this below.
Maintenance. This is not a standard behavior model therefore this will make maintenance harder for future developers since first they will have to understand first what is going on.
If you still want to achieve this, one of the simplest methods is to use sessions. The idea is that when there is a querystring, you save its contents into a session and then you retrieve it later on when there is no querystring. For example:
def testrun(request, testrun_id):
# save the get data
if request.META['QUERY_STRING']:
request.session['testrun_get'] = request.GET
# the following will not have querystring hence no infinite loop
return HttpResponseRedirect(reverse('testrun', args=(testrun_id,)))
# there is no querystring so retreive it from session
# however someone could visit the url without the querystring
# without visiting the querystring version first hence
# you have to test for it
get_data = request.session.get('testrun_get', None)
if get_data:
if 'list_options' in get_data.keys():
...
else:
# do some default option
...
context = { ...stuff... }
return render(request, 'test_tracker/testview.html', context)
That should work however it can break rather easily and there is no way to easily fix it. This should illustrate the second bullet from above. For example, imagine a user wants to compare two search queries side-by-side. So he will try to visit .../link?q=bar&order=foo and `.../link?q=cat&order=dog in different tabs of the same browser. So far so good because each page will open correct results however as soon as the user will try to refresh the first opened tab, he will get results from the second tab since that is what is currently stored in the session and because browser will have a single session token for both tabs.
Even if you will find some other method to achieve what you want without using sessions, I imagine that you will encounter similar issues because HTTP is stateless hence you will have to store state on the server.
There is actually a way to do this without breaking much of the functionality - store state on client instead of server-side. So you will have a url without a querystring and then let javascript query some API for whatever you will need to display on that page. That however will force you to make some sort of API and use some javascript which does not exactly fall into the scope of your question. So it is possible to do cleanly however that will involve more than just using Django.

Disable caching for a view or url in django

In django, I wrote a view that simply returns a file, and now I am having problems because memcache is trying to cache that view, and in it's words, "TypeError: can't pickle file objects".
Since I actually do need to return files with this view (I've essentially made a file-based cache for this view), what I need to do is somehow make it so memcache can't or won't try to cache the view.
I figure this can be done in two ways. First, block the view from being cached (a decorator would make sense here), and second, block the URL from being cached.
Neither seems to be possible, and nobody else seems to have run into this problem, at least not on the public interwebs. Help?
Update: I've tried the #never_cache decorator, and even thought it was working, but while that sets the headers so other people won't cache things, my local machine still does.
from django.views.decorators.cache import never_cache
#never_cache
def myview(request):
# ...
Documentation is here...
Returning a real, actual file object from a view sounds like something is wrong. I can see returning the contents of a file, feeding those contents into an HttpResponse object. If I understand you correctly, you're caching the results of this view into a file. Something like this:
def myview(request):
file = open('somefile.txt','r')
return file # This isn't gonna work. You need to return an HttpRequest object.
I'm guessing that if you turned caching off entirely in settings.py, your "can't pickle a file object" would turn into a "view must return an http response object."
If I'm on the right track with what's going on, then here are a couple of ideas.
You mentioned you're making a file-based cache for this one view. You sure you want to do that instead of just using memcached?
If you really do want a file, then do something like:
def myview(request):
file = open('somefile.txt','r')
contents = file.read()
resp = HttpRespnse()
resp.write(contents)
file.close()
return resp
That will solve your "cannot pickle a file" problem.
You probably did a per site cache, but what you want to do now is a per view cache. The first one is easier to implement, but is only meant for the case of 'just caching everything'. Because you want to choose for every view now, just switch to the fine grained approach. It is also very easy to use, but remember that sometimes you need to create a second view with the same contents, if you want to have the result sometimes cached and sometimes not, depending on the url.
So far to the answer to your question. But is that an answer to your problem? Why do you return files in a view? Normally static files like videos, pictures, css, flash games or whatever should be handled by the server itself (or even by a different server). And I guess, that is what you want to do in that view. Is that correct? The reason for not letting django do this is, because starting django and letting django do its thing also eats a lot of resoruces and time. You don't feel that, when you are the only user in your test environment. But when you want to scale to some thousand users or more, then this kind of stuff becomes very nasty. Also from a logical point of view it does not seem smart, to let a program handle files without changing them, when the normal job of the program is to generate or change HTML according to a state of your data and a user-request. It's like letting your accountant do the programming work. While he might be able to do it, you probably want somebody else do it and let the accountant take care of your books.

Can you iterate over chunks() with request.POST in Django?

I'm trying to optimize a site I'm building with Django/Flash and am having a problem using Django's iterate over chunks() feature. I'm sending an image from Flash to Django using request.POST data rather than through a form (using request.FILES). The problem I foresee is that if there is large user volume, I could potentially kill memory.
But it seems that Django only allows iterating over chunks with request.FILES. Is there a way to:
1) wrap my request.POST data into a request.FILES (thus spoofing Django)
or
2) use chunks() with request.POST data
The chunks() method is only available to an django.core.files.uploadedfile.UploadedFile object, which itself is a child of django.core.files.base.File. From the documentation for handling uploaded files:
The final piece of the puzzle is
handling the actual file data from
request.FILES. Each entry in this
dictionary is an UploadedFile object
-- a simple wrapper around an uploaded file.
So if you can create your own UploadedFile object, then you could feasibly work some magic with chunks(). I recommend snooping around on DjangoSnippets, which might have some code you can use as an example on how to do this.