How to handle uploaded files in webapp2 - python

Google appengine's webapp2 has a very cryptic documentation regarding the handling of uploaded files.
Uploaded files are available as cgi.FieldStorage (see the cgi module) instances directly in request.POST.
I have a form which makes a POST request of JSON files which I want to store in an NDB.JsonProperty.
Can anyone offer a short example of how do I read the file from the request object?

You can use enctype="multipart/form-data" in your form, and then get file content by using in your handler:
raw_file = self.request.get('field_name')
Then, pass raw_file as input to your model's property.

Google's document just sucks. I've spent about two hours experimenting with webapp2's request object and finally figures out a way to do this.
Check https://stackoverflow.com/a/30969728/2310396.
The basic code snippets is here:
class UploadHandler(BaseHandler):
def post(self):
attachments = self.request.POST.getall('attachments')
_attachments = [{'content': f.file.read(),
'filename': f.filename} for f in attachments]
We use self.request.POST.getall('attachments') instead of self.request.POST.get('attachments'), since they may be multiple input field in HTML forms with the same name, so if you just use self.request.POST.get('attachments'), you'll only get one of them.

Instead of using the solution described in How does cgi.FieldStorage store files?, I used enctype="multipart/form-data" in the form, and
in the handler method for the post I accessed the files via:
file_content = self.request.POST.multi['myfieldname'].file.read()
it worked!

Related

Django: Search via GET request, POST request or in the URL?

I am implementing a search form in Django. I can do a POST or a GET request. Each has their use-cases (POST request, if I want to change data on the server, GET request, if I just want to get data from the server).
Via POST request (the search keywords are not visiable in the URL, but rather in a dict in request.POST); cons: I cannot bookmark the search
via GET request (the search keywords are visible in the URL, for intance localhost:8000/books/?author=schultz); cons(?): the part ?author=schultz cannot be processed by the URL handler (see [2] below). I need to read the data from request.GET.get("author", None) in my view function.
or directly in the URL like so: localhost:8000/books/search/author/schultz ?
The author in [1] says, that Django's preferred way to handle a URL is not via GET (like so: /category_check_view/?item_id=2, but rather like so /category_check_view/2)
If I would like to implement search like this: localhost:8000/books/author/schultz, then I would have to process a GET request, read the params ?author=schultz via request.GET.get("author", None) and in my view do a redirect from this URL localhost:8000/books (in which I have a form and a GET request) to this localhost:8000/books/author/schultz.
Does this approach make sense? Or am I overcomplicating things? Just leave it at a GET request to implement my search form?
[1] Yuval Adam says in this post that
GET params are not processed by the URL handler, but rather passed
directly to the GET param dict accessible in a view at request.GET.
The Django (i.e. preferred) way to do handle URLs is the first one.
[2] Django docs: What the URLconf searches against
First things first, GET is for reading data and POST is for creating. Since search is a form of reading data, you will use GET!
Which takes us to the matter of the urls. There are as you mention 2 distinct ways to pass parameters via a url in Django:
Parameters as part of url:
Your url regex must look like this:
url(r'^books/author/(?P<author>\w+)/$',
'yourviewname',
name='author_search'
)
Your URLs will have the shape: /books/author/author_name_here
GET Parameters:
Your url regex can look like this:
url(r'^books/$',
'yourviewname',
name='book_search'
)
Your URLs will have the shape: /books/?author=author_name_here&other=other_param
It is a matter of choice mostly on what you want to use. To quote a great answer:
Don't obsess over the beauty of your URIs, they are a tool not a piece of art.
- #Quentin -
For a short implementation example of both the above mentioned ways, take a look at this link
Also usable is:
from django.urls import path
import <your_view> from views.py
path('news/<str:author>/', <your_view>.as_view())

Flask Uploads Photo class

Trying to write a website that will allow users to upload photos, and so far, I've been using the Flask-Uploads library (docs here)
Used in the example in the docs is a class Photo that seems fairly critical:
rec = Photo(filename=filename, user=g.user.id)
rec.store()
...
photo = Photo.load(id)
Problem being that the name Photo doesn't exist in flask.ext.uploads and I'm not sure where to upload it from.
Has anyone else experienced the same issue?
Photo is a model class that you'd need to define. If you take a look at the example application you'll see a class named Post.
post = Post(title=title, caption=caption, filename=filename)
post.id = unique_id()
post.store()
This particular example was made using Flask-CouchDB, but you can use any data store you'd like. You'll just need to replace the lines that save the Photo or Post with however you save references to uploaded files in your application.

Flask WTForms not showing the data

I am new to python and flask and trying to understand "wtforms" but so far didn't find any tutorials that actually explains the complete functionality. Like in some places data is set in the "GET" request like
form.country = DBModel.country
some use it like
form.country.data = DBModel.country
other use it like
form.country.query = DBModel.country
The other thing I don't understand is "wtforms" functionality in "POST" request.
Where exactly data is extracted from the request?
I cannot see any data extraction from request in any example. They simply define the instance of "wtform" and starts adding the data to DB.
If You are new in Python and Flask read this blog :) It contains series of articles how to start and develop the flask project. It can be very useful.
About problems with wtforms try to find something useful in flask snippets.
In wtforms.Form you have properties data - it is a dict containing the data for each field. If You want to fill form with data from model there is populate_obj() method.

Web API and rendering template, should they in the same function call?

I am new on web development.
I am now implementing a simple create/edit user form with a submit button.
I would like to know the better practice to implement this.
I have already define this kind of web api
URL Method Description
/users/ GET Gives a list of all users
/users/ POST Creates a new user
/users/<id> GET Shows a single user
/users/<id> PUT Updates a single user
/users/<id> DELETE Deletes a single user
My first approach:
i create two new "/user/add" and "/usr/edit" function,
which similar to
app.route("/users/edit")
def edit_user(){
....
....
call the internal api /user/ with a "put" method
....
render_template("edit.html")
when I click the submit the button, the i call the above internal api /users/ ,method=PUT,
and render the final template.
My second approach:
in my internal api /user/, i try to read the http header to see if i want a html template or json text and return back to user
Say, again when i want to create a edit form, instead of calling /user/edit , i call /user/, with a PUT method
def put(self, id):
//see the header of that request
if header == html
render_template("edit.html", .....)
if header == json
update the record
#
my question , basically, i don't know if "/user/add" "/user/edit" route is necessary to make a form, or we can just simple embedded into /user/ api with different "post" or "put" method.
the idea is coming from here , from flask, pluggable view, which i am wondering how to make a better implementation
Or is that a better way to do it???
Thanks a lot.
I would choice your first approach because than your URLs are clear and logical. Also you split your frontend (Website with forms) and backend (API) which is in testing very helpful. A normal web browser makes only GET and POST requests to a website so it is very difficult to render template by a PUT request for the user because the user is normally not able to start a put request.

Passing static JSON to Django Template - best practices?

I have a JSON data file that is part of my application (version controlled, etc.), and several of our templates need the data in this file to render properly.
What are the pros and cons of various ways of making this JSON data available to the templates?
Let's start with the fairly simple option of storing the JSON data as a template, asking the template renderer to generate it, parsing that as JSON, and passing that as a template context param for each view that needs it:
'mydata': simplejson.loads(render_to_string('data/mydata.json'))
(This seems somewhat wasteful of CPU cycles and possibly disk access. Would the rendered JSON "template" at least be cached automatically?)
What are some other options? Is there any built-in feature of Django I'm missing that's designed for this type of use case?
The simplest and probably fastest thing to do is to just parse the json in your views.py outside of the actual view:
mydata = simplejson.loads(json_file)
def foo(request):
...
return render(request, 'template.html', {"mydata": mydata},
content_type="application/xhtml+xml")
The json will only be parsed the first time a view from the views.py file is requested, subsequent requests will not cause it to be parsed again. You could alternately use a context processor, as suggested.
If the data should be available on many/all pages, than a context_processor might be your best solution: https://docs.djangoproject.com/en/dev/ref/settings/#std:setting-TEMPLATE_CONTEXT_PROCESSORS
If you only need it on a couple of specific pages, than you can simply pass it to the template like you are doing now or make a template tag out of it.
As for saving cpu time, if you store it in a threadlocal variable than you don't have to parse it every time.

Categories

Resources