Checking for content in Django request.POST - django

I am accepting data via request.POST like this:
if request.method == 'POST':
l = Location()
data = l.getGeoPoints(request.POST)
appid = settings.GOOGLE_API_KEY
return render_to_response('map.html',
{'data': data, 'appid': appid},
context_instance=RequestContext(request))
It accepts data from a bunch of text input boxes called form-0-location all the way up to form-5-location.
What I want to add in is a check to make sure that request.POST contains data in any of those input fields. I think my problem is that I do not know the correct terminology for describing this in Django.
I know how to do it in PHP: look inside $_POST for at least one of those fields to not be empty, but I can't seem to find the right answer via searching for google.
If I don't find any data in those input fields, I want to redirect the user back to the main page.

Have you thought about using Django's Forms?? You can mark fields as "required" when defining a form and Django will take care of validating if said fields have data in them upon submission. They also do other kinds of validation.

if request.method == 'POST' and request.POST:
# Process request
request.POST will be false if the request does not contain any data.

With Django request objects, the POST data is stored like a dictionary, so if you know the keys in the dictionary, you can search for them and check if they're empty or not. Check out these two links for more detail:
http://docs.djangoproject.com/en/dev/ref/request-response/#attributes
http://docs.djangoproject.com/en/dev/ref/request-response/#querydict-objects
And, for example, when you have your request object, and you know you have a key/var called 'form-0-location', you could do:
if request.POST.get('form-0-location'):
print 'field is not None >> %s' % request.POST.get('form-0-location'')

I second the suggestion to use Django Forms. Why not take advantage of Django Forms when you are using Django?
Design a quick form that matches the fields you currently have on the page. Load the form with request.POST data, and use form.is_valid() to determine whether the form is valid or not .

request.POST returns a type of QueryDict (which extends the Dictionary superclass).
This means you can iterate through the keys in this dictionary (all the parameters in POST) and return false when you see one that is empty
(for key in request.POST):
if key k has invalid value (i.e. None or something else):
return false
return true

You could also try try something like
if len(request.POST['data'])<1:
do something if empty
else:
do something if has data

Related

Sending form to another view django

I am building a website and I want various views that will ask the user to request a quote from our page. I want to keep the code as DRY as possible so I am writing a view quote which will receive the quote requests from various views and, if there is a validation error redirect back to the page that made the request. I managed to solve this using the super bad practice 'global variables'. I need a better solution, I would like redirecting to respective view with the current form so I can iterate through the form.errors. Here is my code:
def send_quote(request):
form = Quote(request.POST)
if form.is_valid():
# do stuff when valid
return redirect('Support:thanks', name=name or None)
quote_for = request.POST['for_what']
global session_form
session_form = form
return redirect('Main:' + quote_for) # Here I would like to send form instead of storing in global variable`
You can use the HttpResponseRedirect function, and pass as argument the page that made the request.
return HttpResponseRedirect(request.META.get('HTTP_REFERER'))
All the META data is store on a dictionary, if you want to learn more check the documentation.
https://docs.djangoproject.com/en/dev/ref/request-response/#django.http.HttpRequest.META
If you redirect to the referrer, form.errors will be empty, as redirection is always a GET request.
I can think of two solutions to your problem:
Submit forms asynchronously using JavaScript and so populate the errors
Make all the views containing the form support POST - one way to do this would be to create a base class that inherits from FormView
The second option is a typical way of handling forms in Django - you process both POST and GET inside the same view.
After two days of searching I finally found the answer. Instead of saving form in request.session I just save request.POST and then redirect. Here is the code:
def send_quote(request):
form = Quote(request.POST)
if form.is_valid():
# do stuff when valid
return redirect('Support:thanks', name=name or None)
quote_for = request.POST['for_what']
request.session['invalid_form'] = request.POST
return redirect('Main:endview')
def endview(request):
session_form = request.session.pop('invalid_form', False)
if session_form:
form = Quote(session_form)
# render template again with invalid form ;)
Now I can repeat this with all the views I want and just change the what_for input of each form to match the respective view (Like I intended).

Prevent Django forms highlighting correct fields

After submitting a form that contains errors, the incorrect fields get marked as such. Correctly submitted fields, however, also get marked.
Is there a way to prevent this from happening? I'd prefer it if Django were to only render the incorrect fields differently, and render the correctly submitted fields as normal.
I checked the API offered by the Form object, but there does not seem to be a property that lists these correctly submitted fields.
Django by default only marks the invalid fields, not the valid ones.
Be sure you are passing the POST data to the form in the view when POST.
(incomplete example below)
if request.method == 'POST':
form = YourForm(request.POST)
if form.is_valid():
# your code then redirect
else: #GET
form = YourForm()
You can take a look to this Django example in the docs for a full example.

Can I turn a Django form into a GET request string?

I want to take a ready-made form (i.e an object of a class derived from django.Forms.form with validated bound data) and urlencode it as though it were submitted with GET. Is there a built-in way?
To show why I'm asking this questino, and why I can't just call urlencode, the output from this should be "box=on".
from django import forms
from urllib import urlencode
class DemoForm(forms.Form):
box = forms.BooleanField(required=False)
instance = DemoForm({"box": True}) # it's irrelevant how this data is supplied
instance.is_valid()
print "encoded:", urlencode(instance.cleaned_data)
In fact it's "box=True", because urlencode isn't encoding the form it's encoding the cleaned values (and believe me, BooleanField is the simplest case).
So I'm asking for a way to encode the form as though it were a GET string. A correct GET string.
Calling urllib's urlencode on the form's cleaned_data won't work well in two cases:
If you are using a ModelChoiceField, the cleaned_data will contain the actual object(s), not the IDs. These will urlencode() to their string representations instead of their primary keys.
If you are using a field that can hold multiple values (such as MultiValueField, MultipleChoiceField or others), urlencode() will lose all but one value from that field. So {'mykey':[1,2,3]} becomes ?mykey=3 instead of ?mykey=1&mykey=2&mykey=3 the way django does it.
To deal with both of these problems, use the form's built-in urlencode function:
form = MyForm(request.POST) #or a dict or whatever
form.is_valid()
querystring = form.data.urlencode()
Note that this is called on data, not cleaned_data. If your form changes values as part of validation, those changes won't be reflected here.
I'm not fully sure what you mean with ready-made form, since a form will normally have no values associated. Or do you mean to take a form a user filled and have it posted as a get?
You can use urllibs encode to create a get-string:
import urllib
print urllib.urlencode({'key1': 'value1', 'key2': 'value2'})
# key1=value1&key2=value2
If you want to take a posted form and create a GET-string from this data:
form = MyForm(request.POST)
if form.is_valid():
print urllib.urlencode(form.cleaned_data)
# name=value&name=value etc
If you want to create a GET for an unbound form:
# this form contains intitial values
# which are shown when printing the form
form = MyForm()
print urllib.urlencode(form.initial)
# name=value&name=value etc

Django Overwrite form data saved

I've posted about this problem before, but I still haven't found a solution so I'm hoping I'll have better luck this time.
I have a form that takes inputted data by the user. In another page, I am creating the identical form that the user has populated (pre-filled with that information) for editing purposes. Users will come to this page to EDIT the information they have already put in. My problem is that it isn't overwriting the instance.
def edit(request):
a = request.session.get('a', None)
if a is None:
raise Http404('a was not found')
if request.method == 'POST':
form = Name_Form(request.POST, instance=a)
if form.is_valid():
j = form.save( commit=False )
j.save()
else:
form = Name_Form( instance = a )
For this form, I'm using "unique_together" for some of the values. I'm also calling on `{{ form.non_field_errors }} in the template.
What is happening is when I make changes in the editing view, if the fields changes involves those defined in "unique_together" then an error is returned telling me that the instance already exists. Otherwise it saves a new instance. It isn't OVERWRITING.
Note that the reason i am using unique_together is that I want to prevent users from initially inputting the same form twice (before the editing stage, in the initial inputting view).
Any ideas?
EDIT: note that "a" refers to a session that includes a drop down box of all the available instances. This carried forward will indicate which instance the user wants to edit.
`
Why not do a database lookup of the model your trying to save and pull the fields from the form to the model then save the model?
Instead to store model a in session you should store it on database. Then edit it:
def edit(request, pk):
a = A.objects.get( pk = pk)
...
pk it the a identifier, you can send it to view via urls.py. I encourage to you to use POST/Redirect/GET pattern.
You can add a 'state' field on your model to control workflow (draft, valid)
You should not save objects in the session. If you really need to use a session - save a PK there and retrieve object right before giving it to Form. But the better solution is to send it in GET or POST parameters or included in url. Sessions are unreliable, data inside it can be destroyed between user's requests.
And you can retrieve value from a session in a more pythonic way:
try:
a = request.session['a']
except KeyError:
raise Http404('a was not found')

Forms hierarchy issue in Django

I created a form for login, just like this:
class LoginForm(AuthenticationForm):
username = forms.CharField (label=_("Usuario"), max_length=30,
widget=forms.widgets.
TextInput(attrs={'id':'username','maxlength':'25'}))
password = forms.CharField (label=_("Password"), widget=forms.widgets.
PasswordInput(attrs={'id':'password','maxlength':'10'}))
I use it in this view:
def login(request):
if request.method == 'POST':
form = LoginForm(request.POST)
if form.is_valid():
...
After debugging I realize that the form.is_valid() method returns false cause the is_bound attr is false. Do I have to redefine something in my form or to modify my view???
Edit 1
I have followed this SO question about is_valid() method returning False:
form.is_valid() always returning false
but the problem is still there.
One issue to note about the currently accepted answer:
form = LoginForm(request=request, data=request.POST)
is that passing in request seems to enable Django's behavior of checking to see if a test cookie was successful before initiating a session. The problem is that if you haven't set the test cookie previously (it has to be set in a previous view request) it will fail and your login will fail. I recommend just passing the data keyword argument in like so:
form = LoginForm(data=request.POST)
Unless I'm missing something important (it didn't seem like the cookie check is absolutely necessary), this works better in most situations. You could alternatively call request.set_test_cookie() in the view that loads the login page, but that doesn't cover all scenarios.
The issue is actually similar to the one in the question you link to. The form you're inheriting from, django.contrib.auth.forms.AuthenticationForm, takes request as its first parameter, before the usual data param. This is why your form is reporting that it is not bound - as far as it's concerned, you're not passing in any data, so it has nothing to bind to.
So, in your view, you'll need to instantiate it like this:
form = LoginForm(request=request, data=request.POST)