I have a form which sends a POST request and returns a page. The url of this page is defined like this
(r'^result/', 'main.views.eval_form'),
and in the browser the url looks like
mysite.com/main/result
But I also have the url working with a Get Request so the user could save the url and not have to use the form, ie:
mysite.com/main/result?name=Tom&color=blue&etc=etc
Now is there a way to alter the url in the browser after the user uses the form, to include the query string by default? So that the user can copy the url and always return to result?
Thank you!
Change the method attribute of the <form> tag:
<form action="/main/result/" method="GET">
...
</form>
You could do a HttpResponseRedirect to the url with the prefilled querystring from the Post view.
Make sure you don't submit it twice or create an infinite loop.
return HttpResponseRedirect("/result?name={}&color={}&etc={}".format(name, color, etc))
Another way would be to fill your querystring with jQuery or Javascript from the template.
Myself I would take catavaran's approach
If you want to achieve this, you should alter your view to deal with both post and get request.
code may be like this:
def result(request):
name = request.REQUEST.get("name")
but request.REQUEST is deprecated since django 1.7
def result(request):
if request.method == "GET":
name = request.GET.get("name")
if request.method == "POST":
name = request.POST.get("name")
Related
I have a question on my homepage that the user should answer through radio buttons. The user should press the submit button to send the answer, so basically it is a SELF PAGE submission. The user should not go to another page after submitting the answer but should remain on the same home page. Though I looked up some earlier questions, the code did not work out.
I have created the TEMPLATE DIRECTORY under the root folder and under this directory, there is a 'pages' folder that has the index.html (homepage) inside which I am invoking the form
The form code in the index.html page.
<form action = "?" method = "POST">
I want to know what function should I write in the views. Since the form action does not call a named view I am not able to figure out how I should define the view that updates the data.
def WHAT NAME SHOULD I GIVE HERE(request):
.....other code
I am adding the following code as of 3rd May. When I use this code I get the error. I would like to state that in the form the questions.id is coming from the questions model (or table) but in the function in the views, I want to update the question.id in the questionid field in the answers model
ValueError at /updateans/updateans
Cannot assign "''": "Answers.questionid" must be a "Questions" instance.
The relevant code in the form is
<form action = "{% url 'updateans' %}" method = "POST">
<input type = "hidden" name ="questionid" value = "{{Questions.id}}">
The function in the views file is (as of now I am just trying to update one field but still getting an error - see above)
def updateans(request):
if request.method == 'POST':
questionid = request.POST["questionid"] 'variable questionid defined
print(questionid) --> even the print command shows a blank
myans = Answers(questionid=questionid)
'questionid is a field in the Answers model
myans.save()
Thanks
After Form Submission redirect the user to the same page
def answer_submit(request):
if request.method == 'POST':
name = request.POST["name"]
subject = request.POST["subject"]
email = request.POST["email"]
message = request.POST["message"]
con = Contact(name=name,subject=subject,email=email,message=message)
con.save()
# If u use messages module of django then the next line will work
messages.success(request,"Thank you for contacting us, We will get to you as soon as possible")
return redirect("home.html")
The is some thing like this u just need to redirect the user to same page
in my URL for the createview, I want there to be a '?', from where I can pass an argument to the nect page. I am using class based views. For example:
www.site.com/appname/appointment/add/?Name=1
And my HTML would be:
href={% url 'People:appointment-create' Patient.id %}
Currently my URL is like so:
re_path(r'appointment/add/$', views.appointmentCreate.as_view(), name='appointment-create'),
and my view is:
class appointmentCreate(LoginRequiredMixin, CreateView):
model = appointment
form_class = AppointmentForm
def get_initial(self):
patient = self.request.GET.get('patient')
return {
'Patient': patient,
}
How would i go about doing this?
You can try something like this:
href={% url 'People:appointment-create' %}?patient_id={{ Patient.id }}
(so just pass the query arguments after the url as normally).
Also, if you want a more general solution on this problem (automatically generate the form's initial values from query parameters) take a look at this section https://spapas.github.io/#configure-the-form-s-initial-values-from-get-parameters from by article on CBVs.
So here's the basics:
first of all I would like to let you know about below line you just wrote:
{% url 'People:appointment-create' Patient.id %}
to match above url you will need to include below url:
path(r'appointment/add/<int:patient>', views.appointmentCreate.as_view(), name='appointment-create'),
This is the difference between request parameters and kwargs here you pass patient id as kwargs and access in Class base view in self.kwargs
The constructed url will be like below:
www.site.com/appname/appointment/add/1/
Next thing is that if you want to post request parameter (which don't require to add any additional url in your urls.py) you can use as below:
href="{% url 'People:appointment-create' %}?patient={{Patient.id}}"
Note that the parameter you use here will be available in view if you use name in request parameter then you need to access it as self.request.GET.get('name') and if you want to use patient as request parameter then you can access it as self.request.GET.get('patient').
I am using django-allauth for local account management. I have customized templates ,login.html and signup.html. Both of these templates are placed in templates/account/ dir and both are accessible properly.
site root i.e localhost:8000 points to index.html which includes using {% include%} both the templates on main page.
form action for signup form in signup.hmtl is set to action="{% url 'account_signup' %}" and that of login.html is set to "{% url 'account_login' %}"
Both the templates appears OK on the main page. The problem arises when I try to use these forms for sigin/login. Instead processing the POST for signup or login I am redirected to locahost:8000/accounts/signup/ for signup and localhost:8000/accounts/login/ for login. I guess I am using the right urls that is account_signup and account_login
I have all settings for allauth. Is this is the default behaviour or I'm missing some thing out? Thanking in anticipation
Well I managed to get rid of the problem after spending some hours. Just in case that some one else caughtup in the same situation I would like to share my solution. The problem was forms have been instantiated by View by using prefix SignUpForm(prefix=signupform) and for that reason allauth class AjaxCapableProcessFormViewMixin(object) (which I don't know how it works) was unable to get data from the fields and its if form.is_valid() was always false as the form has error messages dictionary was containing this field is required for all the fields in the form. Jus to test I removed Prefixing from the form instantiation and it worked but make me feel strange as these kind of hidden errors can take upto indefinite time to resolve especially for some niwbie like me
class AjaxCapableProcessFormViewMixin(object):
def post(self, request, *args, **kwargs):
form_class = self.get_form_class()
form = self.get_form(form_class)
if form.is_valid():
response = self.form_valid(form)
else:
response = self.form_invalid(form)
return _ajax_response(self.request, response, form=form)
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.
On my Django-powered site, I have a search page with several optional fields. The search page is a Django form, and my view function is the typical:
def search(request):
form = SearchForm(request.GET or None)
if form.is_valid():
return form.display_results(request)
return render(request, 'search.html', {'form': form})
Form.display_results() uses the fields that are provided to query the DB and render a response. My search.html includes:
<form action="/search/" method="get">{% csrf_token %}
<!-- Render the form fields -->
<input type="submit" value="Search" />
<input type="reset" value="Reset form" />
</form>
Since most searches will have several blank fields, I'd like not to include them in the GET request emitted by the submit button on search.html. Current searches look something like:
http://mysite/search/?csrfmiddlewaretoken=blah&optional_field1=&optional_field2=&optional_field3=oohIWantThisOne
And I'd like them to look like:
http://mysite/search/?csrfmiddlewaretoken=blah&optional_field3=oohIWantThisOne
Of course, I have a several more fields. This would be nice to have because it would make search URLs more easily human-parsable and sharable.
You could use jQuery with an button trigger. Give the form and submit button ids.
$("#button_id").click(function(){
$("input").each(function(){
if($(this).val() == '') {
$(this).remove();
}
});
$("#form_id").submit();
});
That (or something similar) should remove all the empty fields before the submit.
You could also POST the form. Then build the search url and redirect with empty values removed.
See Hide empty fields from GET form by Bill Erickson:
jQuery(document).ready(function($){
// Remove empty fields from GET forms
// Author: Bill Erickson
// URL: http://www.billerickson.net/code/hide-empty-fields-get-form/
// Change 'form' to class or ID of your specific form
$("form").submit(function() {
$(this).find(":input").filter(function(){ return !this.value; }).attr("disabled", "disabled");
return true; // ensure form still submits
});
// Un-disable form fields when page loads, in case they click back after submission
$("form").find(":input").prop("disabled", false);
}
disclaimer: This is a very old question, and the only one I could find that matches the problem I ran into. It's entirely possible that my solution didn't exist at the time, and an even better way has since been added.
I'm using Django 3.2. I didn't want to use js/jQuery, nor did I want to use a POST form, so here's what I came up with. In a nutshell, it just checks the GET data to see if there are any default values present, and simply redirects to a URL that doesn't have them.
In your view:
from django.shortcuts import redirect
def myView(request):
if not is_clean_form(request.GET):
return redirect(whatever_url_path + clean_url_parameters(request.GET))
else:
# whatever your view does normally
Helper functions (consider making these static methods of your Form class, to keep all that type of stuff together):
from urllib.parse import urlencode
# fields and their default value (eg. empty string)
default_form_values = [
("some_field_name", ""),
# ...
]
def is_clean_form(form_dict):
for field, default_value in default_form_values:
if field in form_dict and form_dict[field] == default_value:
return False
return True
def clean_url_parameters(form_dict):
return "/?" + urlencode([
(field, form_dict[field]) for (field, default_value) in default_form_values
if field in form_dict and form_dict[field] != default_value
])