I am looking at this example.
This is search_form.html
<html>
<head>
<title>Search</title>
</head>
<body>
<form action="/search/" method="get">
<input type="text" name="q">
<input type="submit" value="Search">
</form>
</body>
<html>
Urls.py
urlpatterns = [
# ...
url(r'^search-form/$', views.search_form),
url(r'^search/$', views.search),
# ...
]
And views
from django.http import HttpResponse
from django.shortcuts import render
from books.models import Book
def search(request):
if 'q' in request.GET and request.GET['q']:
q = request.GET['q']
books = Book.objects.filter(title__icontains=q)
return render(request, 'search_results.html',{'books':books,'query':q})
else:
return HttpResponse('Please submit a search term.')
When GET data is passed into the query string,
/search/?q=paris
what really happens?
The form in HTML is bound or unbound at this point?
I am newbie to Django, it would be nice if someone can explain.
The form is an element in the browser, so Django does not know anything about the form at all. In the <form> tag it is specified what to do in case somebody clicks on the submit button (or the form is submitted in another way, for example by a JavaScript call).
When the form "fires" it depends on the method what will be done. Here the method is GET, so that means that the content of the form is wrapped in the URI (the ?q=paris part). The webbrowser will normally make a new HTTP GET request, but now with the new URI.
Django will listen to the request, and it sees the querystring (the ?q=paris part) and will turn it into a QueryDict. A QueryDict is some sort of dictionary (except that a key can contain multiple values), this will then be the request.GET part. Django will look at the other parts of the URI to determine to which view the request should be "routed" (that is specified in the urls.py file).
Then the view thus will query the request.GET to obtain the string that matches with the 'q' key (here 'paris') and perform the proper logic. In this case it will make a database query and look for Books with 'paris' as a substring in the title. It will then render a HTTP response (probably the template will render the results of the query, so a list of books where for every book, some details are displayed).
The browser thus obtains the response, and then will render this on the screen of the user, so HTML in the response is then translated to a visual page. It can result in extra queries (for example if the page contains <img> tags, the the corresponding images are fetched).
The method of a <form> can also be a POST (and some browsers even support other methods). In that case a HTTP POST request is made, and then the data in the form is encoded in the headers of the HTTP request (so it is not visible in the URI, which can be useful if it for example contains sensitive information). In that case the view can query request.POST, which is a QueryDict as well, to obtain the parameters.
Regardless of the specifics of the form, the idea is that the browser makes a request, and unless the information of the "old" webpage is stored in some form element or in the header, Django has no means to "see" what the state of the page was. In fact it is not necessary to make the request at a certain page. You could for example have requested your.site.com/?q=paris immediately.
Related
I am trying to make a button redirect the user to a new url after they submit a form. This is how it is right now, and it works properly and all the data gets sent to the django database.
<form method='POST' action='' class="col-md-6 col-md-offset-7" style="background-color: lightgreen; border-radius: 10px">
However, when I change the action to
action="{% url 'ridesharing:request-success' %}",
the redirect works, but the data does not go to my django database.
What is going on here?
You seem to have some confusion here. The action of the form is where the browser will send the data. Obviously, if you don't point that at the view which actually processes the data, then it won't be saved.
To redirect after a post, your view should return a redirect.
When you declare a form with an empty action attribute:
<form method='POST' action=''>
the POST data will be sent to the same URL. This is useful because if there is some error in the form, it's easy to re-display it with all fields filled with values entered by the user. Then, when the form becomes valid, a redirect is done to the confirmation page.
When you declare your form that way:
<form method='POST' action='{% url 'ridesharing:request-success' %}'>
The data entered by the user in the form will be sent to the view request-success. But this view probably only render the template of the confirmation page. If you want to correctly handle data from the form, you have to set action attribute of your <form> to the same view, or easier, keep it empty.
I do not understand why Daniel Roseman's post isnt accepted as the answer. It helped me when I wanted to redirect a create form to its update form.
Basically in the view of the app I defined the get_success_url to reverse_lazy to the data-update.
def get_success_url(self):
return reverse_lazy('app_name:data-update')
Just replace the 'app_name:data-update' with the appropriate url.
How do I pass information from an HTML form to my Python code, without having to specify a url mapping? For example, the following code sends data from the form in my 'index.html' template, to the 'myview' mapping, which then calls the 'myview' view function, which finally renders the 'mypage' template...
index.html
<form method="get" action="{% url 'myview' %}">
urls.py
urlpatterns = patterns('',
url(r'^mypage/$', views.myview, name='myview'),
)
views.py
def myview(request):
return render(request, 'myapp/mypage.html')
However, do I really have to have a url mapping for this? What if I do not want to reload another webpage, and I just want to stay in the same 'index.html' page?
I'm just a little confused over how views are actually called, in the case when I want the view to act more like a traditional function, to process some data, rather than to necessarily render a new template.
Thank you!
You always need a URL if you want your browser to call a view. How else would the server know which view to call? The only way is through the URL mapping. Remember that there is no persistent relationship between the browser and the server: the only way they can communicate is through requests to URLs.
You don't always need to render a template, though. A view can return anything, including raw text or JSON.
I don't understand what you mean about not reloading another page. Posting data to the server is a request for another page: that's just how HTTP works. You can certainly choose to post to the same page you're currently on; and in fact that's exactly how forms are processed in the recommended Django pattern. But you still need a URL mapping pointing at that page, in order to get it in the first place as well as to process the submitted dat.
Besides understanding and accepting Daniel Roseman's answer you could also look at these two packages:
Django Rest Franework
jQuery Form Plugin
I have read a lot of tuts and documentation on form creation and handling in Django but I still am confused on certain aspects of the implementation. Specifically, I cannot understand where I should handle the data sent by the form. Is it on the view that is using the form template or is it on another view?
For example, assume an index template with a single form:
*index.html*
{% load url from future %}
<form action="{% url 'Directories:_results'%}" method="post">
Name: <input type="text" name="txtField" />
<input type="submit" name="submit" />
</form>
So now for my view i have two versions:
#1 version (1 view): The same view displays and handles the form
def index(request):
if request.method == 'POST': # If the form has been submitted...
form = dbForm(request.POST) # A form bound to the POST data
if form.is_valid(): # All validation rules pass
field = form.cleaned_data['txtField']
#doSomething
else:
form = dbForm() #unbound form
return render(request, 'Directories/index.html', {'form': form})
#2 version (2 views): One view to display the form and one view to handle the form data
#the view that creates the form (unbound)
def index(request):
form = dbForm()
return render(request, 'Directories/index.html', {'form':form})
#the view that handles the data sent during form submission in the index template.
def results(request):
if request.method == 'POST':
form = dbForm(request.POST) # A form bound to the POST data
if form.is_valid(): # All validation rules pass
field = form.cleaned_data['txtField']
#doSomething
else:
form = dbForm() #unbound form
return render(request, 'Directories/index.html', {'form': form})
and here is my urls.py:
from django.conf.urls import patterns, url
from Directories import views
urlpatterns = patterns('',
url(r'^$', views.index, name='_index'),
url(r'^results$', views.results, name='_results'),)
As you can see data handling is performed differently in each version and as a result I want to know if any of these is wrong and if both are correct then which one is considered the best practice.
Generally a form will post to the same view it is being displayed on.
You can simplify the view logic like so:
def index(request):
form = dbForm(data=request.POST or None)
if form.is_valid(): # All validation rules pass
field = form.cleaned_data['txtField']
#doSomething
return redirect(success_url)
return render(request, 'Directories/index.html', {'form': form})
Note that it is usually good if you redirect after a successful form post, even if you redirect back to the same view. This prevents the user from being prompted to 'resend form data' if they refresh the page.
You should look at the docs for rendering a form in the template:
https://docs.djangoproject.com/en/dev/topics/forms/#looping-over-the-form-s-fields
If you don't render the field errors, for example, the user will never know what the problem was.
An example of a form that would post to a different view is if say your base template has a 'search' form which appears on every page. When you post this form you don't want to come back to the current view, you want to go to the 'search results' view.
Generally, one view corresponds to one url. Also, same url should show the form and accept the submitted form. With this logic, your first approach is better. One view shows and accepts the form.
However, there are cases where view to show form is different than the one accepts it. For example, a page that has multiple forms. Each form can be submitted to different view. But a different view can be implemented to handle that url and show such forms.
There's nothing wrong with either, it depends on what you want to do. By default forms send the data to the same request but you can send the data to a different view if that's more convenient
For most cases it's usually simpler to use the same view. Using two views is good if you're using an external tool\app\whatever or if you want tighten your security (having the second view only accept requests with post data for example etc.), but will require extra steps (error handling, succesful redirect)
The first thing to understand is that the view that processes the form is usually also the one that shows the form in the first place -- because it has to show the form again in case of errors.
In your template, you build the form HTML entirely by hand. That's unusual, because in case of errors (usually a required field that wasn't filled in) you want to render the form again, with all the values already entered present, and with a nice error message. Django's form rendering ( {{ form.as_p }} and the like) do that for you, you don't get it if you write the HTML by hand like this. In fact your view misses an else: clause on the is_valid(), leading it to
So usually the view does both, except for the second thing to understand: after a successful POST, you always redirect to a succes page, or possibly to the same page (which will show an empty form again). Mostly so the user can't accidentally re-submit the form with the refresh button then.
So your 1st is typical, except that you also need to finish with returning a ResponseRedirect in the is_valid() case, and should render more of the form in your template. No need for a second view.
I have a django app and implemented payment gateway functionality.
Now what i was trying is
After successful transation, need to do redirect user to another page that shows the response details so i am using HttpresponseRedirect to redirect the page, but i have the variable response in the view that contains reponse details, so i need to send this variable as the context to the redirecting url that renders template, so that i can use that response variable to display the results.
so for the above functionality, i got three methods
Sending the variable as the query parameter(which is not safe in this method because it is sensitive credit card transaction details)
Using session framework, which is not working in my case, the code is below
Django messaging framework(which is not so useful in this case)
views.py
def payment(request):
amount = 1
if request.method == 'POST':
form = CreditCardForm(request.POST)
if form.is_valid():
data = form.cleaned_data
...........
...........
response = stripe.payment_purchase(amount,data)
request.session['response'] = response
return HttpResponseRedirect(reverse('paygate:payment_success'))
else:
form = CreditCardForm(initial={'number':'4242424242424242'})
return render_to_response('payment/stripe_payment_form.html',{'form': form,
'response':response,},
context_instance=RequestContext(request))
payment_success url view
class PaymentSuccess(TemplateView):
template_name = 'payment/payment_success.html'
I tried to access response variable in the template, but displaying nothing
payment_success.html
{% extends "base.html" %}
{% block main_title %}Payment{% endblock %}
{% block title %}Success{% endblock %}
{% block content %}
<h1>Response Details</h1>
<p>Your status is <span>{{ request.session.response }}</span></p>
{% endblock %}
So can anyone please let me know the various different safe and secure ways to send context variables(in this case credit card payment details) to redirecting url using HttpResponseRedirect method
I think there is a 4. possible item in your list, that I suggest to use.
The safest and most pragmatic way of accomplish what you want is to have a successful view showing the actual results stored in your database.
The idea behind this is:
payment view is an action that a user performs on your database.
payment_success view is a way of telling the user that the action was performed successfully and with the the input the user desired.
Likewise, the best way of showing that the action is correct is to show its result on the database, i.e. what it is now stored on the database regarding that action.
Say you already have a complex HTML form, possible from a designer, front end dev, etc. Is it common practice to not use dynamic forms (based on a Django form) for complicated forms?
I want to do something like this:
1.) Create custom HTML form.
2.) Catch form data through POST request, put it in an object/dictionary.
3.) Do some manipulations with that data to get it in a format acceptable by a Django form.
4.) Pass the manipulated data in to a form object, validate it, etc...
What is a clear solution to this problem? Should I be using Django's dynamic forms for everything? If not - how do I implement the above?
EDIT:
Part of my question has to do with using the forms ONLY for validation. I don't think I made this clear. Here is what I'm trying to do:
template.html
<form method="post">
{% csrf_token %}
<input class="foo" name="bar" type="text" value=""/>
<!-- Some more fields, not rendered through Django form -->
<button type="submit">Create Object</button>
</form>
As you can see, other than the csrf_token there is no Django code here. What I am trying to do in my view is catch the data in the POST in my view, make some changes to the data, then try to bind the new data to a form (not sure if it's possible):
views.py
def my_view(request):
# Some GET code
if request.method == 'POST':
form = ImportedForm(request.POST)
form.data['foo'] = "newValue"
# Now after changing the data, validate it...
If the form and model match nicely then I'll take advantage of the ModelForm functionality.
But most of the time it is not so tidy so, most typically, I do things in about this order:
create a django form with all the field definitions
create django GET view to serve the empty form
create an html template which serves the default html/form
test the blank form
create the POST routine to call validation and reserve the validated (erroneous) form
modify the django form to validate the fields
modify the html form to serve the error messages
test the validation and error messages
modify the POST routine to handle a valid form and do whatever it should do as a result (might involve a redirect and 'thanks' view/template)
Test the whole lot
let the designer loose on the templates
In truth the designer will be involved at some points earlier along the way but in theory I just get it all to work as a "white" then add all the fancy stuff after. That includes javascript validation (ie after all the above).
I ended up doing something like this. It is ugly, and may not be the proper way to do it, but it works...
if request.method == 'POST':
try:
# Create dictionary from POST data
data = {
'foo': request.POST['foo'],
'foobar': request.POST['foobar'],
}
except:
# Handle exceptions
form = ImportedForm(data)
if form.is_valid:
# Continue to validate and save