I have a problem that I solved but the fact that I don't understand how tells me that there is something basic I'm missing. Hope somebody can help me.
So I have a class based update view with inline formsets. I use crispy forms to render the view. The code below was first working, then for some reason it started giving me Management form missing error when just trying to load the update page in my browser.
#views.py:
class CaveUpdateView(UpdateView):
model=Cave
form_class=CaveForm
template_name='caves/cave_form.html'
def get_context_data(self,**kwargs):
context = super(CaveUpdateView, self).get_context_data(**kwargs)
entrance_helper = EntranceFormSetHelper()
context['entrance_helper'] = entrance_helper
if self.request.GET:
context['entrance_formset']=EntranceInlineFormSet(instance=self.object)
else:
context['entrance_formset']=EntranceInlineFormSet(self.request.POST, instance=self.object)
After wrecking my brains out, I changed the last 4 lines of the get_context_data function to this and everything was solved:
if self.request.POST:
context['entrance_formset']=EntranceInlineFormSet(self.request.POST, instance=self.object)
else:
context['entrance_formset']=EntranceInlineFormSet(instance=self.object)
So my question is, how are these two expressions not equivalent? Is there another type of request I somehow make my browser send by refreshing?
if self.request.GET doesn't mean "if the request is a GET" - and if self.request.POST doesn't mean "if the request is a POST". They are using boolean operators on the GET and POST dictionaries respectively - and in Python, dicts are boolean False if they're empty and True otherwise.
So, your calls are actually asking "does the request have some querystring parameters", which may or may not be true whether or not the request is a GET, and "does the request have a body", which will not be true with an empty POST.
If you actually want to check the type of the request,you should explicitly check if request.method == 'GET' (or 'POST').
Related
I've been messing around with django and I have this django view:
def handle_results(request):
if request.method == "POST" and request.is_ajax():
# Do something with the post request
elif request.method == "GET" and request.is_ajax():
# Do something with the get request
else:
# First time in this view, render first element to display
return render(
request, "result_page.html", context={"display": arr[0]}
)
The main idea is, this is supposed to be a Same Page Application, and the first time I'm in this view, I need to render the contents of the array to display to the user, after that, the user can interact with said array via the html (think of it as upvoting or downvoting stuff that's shown). Depending on the user's choice, I get a GET or POST request and need to deal with said request.
However, the way I'm implementing this seems not that elegant and I was wondering if there'd be another better way to accomplish what I'm doing.
Thank you so much!
I would suggest using a class based view
I am trying to build code that allows people to pay for the services that they get from my website. I have built the form using the forms.Form model available in django. I have also used the following pattern to build my view.
if request.method == 'POST'
form = ContactForm(request.POST)
if form.is_valid(): # All validation rules pass
conn = urllib2.Request(payment_gateway_url,urllib.urlencode(my_dat_in_dict))
f= urrlib2.urlopen(conn)
all_results=f.read()
return HttpResponseRedirect('/thanks/') # Redirect after POST
else:
form = ContactForm() # An unbound form
return render(request, 'contact.html', {
'form': form,
})
The problem i am facing is that my forms get submitted OK and the payment gateway responds back to me with a whole bunch of html that helps the user to choose the credit card details etc in the response to this form POST(details that i am not collecting on my website). I can see this in the all_results (f.read()).
My question is that how do i show the user this page, since i get this as a result of my form POST. Should i save this response in a html file and HTTPResponseredirect to that page. I am assuming that HTTPResponseRedirect is more for a complete transaction and not the intermediate responses.
So, basically how do i handle the situation where the user will get sent to the payment gateway site and then after completing the proceedings come back to my site?
thanks
First off, I would say, if you live in the US, check out Stripe (or something similar). The way you are describing your payment process seems a bit overly complicated.
With that said, if (and I doubt this is the case), the HTML returned from the most is in the correct format for display on your website, you can just stick it in to an HttpResponse (must be a sprint)
return HttpResponse(html)
Otherwise, use something like BeautifulSoup, Scrape.py, or something similar to format it IN RAM, and then use HttpResponse. I would not write it to the file system for modification.
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)
Are forms that use the POST method required to have CSRF protection? I'm following a book and the code examples throw 403 errors. I did some searching and it seems as if I need to enable CSRF in all my forms.
My questions are:
Does Django now require that all POST forms be protected from CSRF?
All I need to do to accomplish this is add 'django.middleware.csrf.CsrfViewMiddleware', return render_to_response(template,dictionary,context_instance=RequestContext(request), and add '{% csrf_token %}' in the corresponding form? Am I missing anything here?
When I do this, the form works fine. When any of these pieces are missing, it fails to 403. I just want to make sure I'm doing it RIGHT. :)
Thanks in advance.
edit:
For some reason this code doesn't make sense to me but it doesnt return any error. Please ignore the primitive validation as I haven't gotten to the section of the book where it shows the more efficient way to do it yet.
def contact(request):
errors = []
if request.method == 'POST':
if not request.POST.get('subject',''):
errors.append('Enter a subject')
if not request.POST.get('message',''):
errors.append('Enter a message')
if request.POST.get('email', '') and '#' not in request.POST['email']:
errors.append('Enter a valid email address')
if not errors:
send_mail(
request.POST['subject'],
request.POST['message'],
request.POST.get('email', 'noreply#example.com'), ['siteownder#example.com'],)
return HttpResponseRedirect('/contact/thanks/')
return render_to_response('contact_form.html', { 'errors': errors }, context_instance=RequestContext(request))
My issue is with the very last line of this view function. It is only called if the request.method != POST. This seems completely wrong to me. Shouldn't I be calling "context_instance=RequestContext(request)" when it's doing a POST?
POST should be used for sensitive information, such as passwords, and django requires securing it with csrf_token; GET should be used for bookmarkable stuff which doesn't need to be secured, like searches. You ARE doing it RIGHT.
EDIT
You shouldn't be calling context_instance=RequestContext(request) when it's doing a POST, you should be calling it regardless of the request type. Look at it like this:
Is it a POST? this means the form was submitted. we validate the form, and redirect the user to another page if the form is OK, or show the form again to the user, with the errors.
Is it a GET? this means the form was not submitted, but other stuff is happening which we don't care about (some referrer link or other stuff). Show the form anyway
Actions in italic are done by the last return, regardless of the if.
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