I have created django form.py file :
from django import forms
from models import ResumeModel
class ResumeForm(forms.ModelForm):
username = forms.CharField(max_length = 200)
first_name = forms.CharField(max_length = 200)
last_name = forms.CharField(max_length = 200)
fathers_name = forms.CharField(max_length = 200)
email = forms.EmailField(required=True, label='Your e-mail address')
message = forms.CharField(widget=forms.Textarea)
class Meta():
model = ResumeModel
fields =('username','first_name','last_name','fathers_name','email','message')
views.py :
def save(request):
if 'submit' in request.POST:
form = ResumeForm(request.POST)
if form.is_valid():
form.save()
form = ResumeForm()
return render(request, '/success/', {'form': form})
else:
form = ResumeForm()
args = {}
args.update(csrf(request))
args['form'] =form
return render_to_response('create.html',args)
urls.py:
urlpatterns = patterns('',
url(r'^admin/', include(admin.site.urls)),
url(r'^save/', 'Resume.views.save'),
url(r'^success/$', TemplateView.as_view(template_name='success.html')),
)
Now all is working fine. problem is that as i submit form it moves to success page and when i go back to previous page that is /save/ page it holds all the values in fields that i submitted. How to clear the fields if i press back button to go back to that form page having url as "/save/ "
This is about the browsers behaviour. Browser shows u the page in its cache instead of calling a new page.
U may workaround this by using javascript.Unfortunately browser also dont run the javascript codes again.
But u may try :
$(window).bind("pageshow", function() {
// Clean form values
});
by JQuery
This is a browser implementation detail. You might be able to hack your way around it with JavaScript or break the cache etc. The subject is discussed in this stackoverflow question.
However a nicer UI approach might be to use AJAX to POST a serialised version of the form. If you successfully validate and process that form in your view (inserting a new row into your resume model table etc), you could then send a JSON response which might invoke some JavaScript to clear the form fields (maybe using .reset()). The user is then free to submit another form easily if that is the requirement.
Also note it is recommended that you use a HttpResponseRedirect after a successful POST (you have a render() response at the moment). This stops the users re-submitting the form again and potentially duplicating rows in your databases etc.
Related
I am trying to make a help section for my team. I have a form that the person that needs help will fill out, then that data will go to a page only my team my can view to see which one of us will tackle the problem. But, I am having trouble rendering the context of the form to the help page my team can view. right now I am using render(), but when the user clicks submit he/she gets redirected to the page only my team should be able to see. and the data doesn't stay on the page when it is reloaded.
here is the views.py
def help_form(request):
# if this is a POST request we need to process the form data
if request.method == 'POST':
# create a form instance and populate it with data from the request:
form = HelpForm(request.POST)
# check whether it's valid:
if form.is_valid():
# process the data in form.cleaned_data as required
name = form.cleaned_data['your_name']
room_number = form.cleaned_data['room_number']
email = form.cleaned_data['email']
when = form.cleaned_data['when']
subject = form.cleaned_data['subject']
description = form.cleaned_data['description']
context = {
'name': name,
'room_number': room_number,
'email': email,
'when': when,
'subject': subject,
'description': description,
}
# redirect to a new URL:
return render(request, 'website/asked_questions.html', context)
# if a GET (or any other method) we'll create a blank form
else:
form = HelpForm()
return render(request, 'website/help_form.html', {'form':form})
if you need to see forms.py or my template let me know, i feel like I am just missing a type of render method. Thanks Guys!!
I used Wagtail's contributed Form builder module to create a simple Contacts form in Wagtail Admin. The form has the dynamically added fields Name, Email, Subject and Message; the model ContactPage inherits from AbstractForm.
The problem:
I would like to use the entered name in the Name field to personalize the response message to the user who used the contact form. Wagtail's Read The Docs page on Form builder only states that form is part of the context for the form_page.html template, while the form_page_landing.html template is a standard template. Is it possible to access the form-submitted values through the context of the landing template out of the box somehow? If not, could anyone give an example how/what page function to override, in order to add the information I need to the context? Thanks!
Wagtail serves its forms pages through AbstractForm (https://github.com/wagtail/wagtail/blob/master/wagtail/contrib/forms/models.py#L296) and specifically its serve method. This method checks to see if the HTTP method is 'POST' so it either processes the form and returns the landing page or it renders the actual form. You can override this method to your custom form class so it updates the context of the landing page, something like this:
def serve(self, request, *args, **kwargs):
if request.method == 'POST':
form = self.get_form(request.POST, page=self, user=request.user)
if form.is_valid():
self.process_form_submission(form)
# Update the original landing page context with other data
landing_page_context = self.get_context(request)
landing_page_context['name'] = form.cleaned_data['name']
return render(
request,
self.get_landing_page_template(request),
landing_page_context
)
else:
form = self.get_form(page=self, user=request.user)
context = self.get_context(request)
context['form'] = form
return render(
request,
self.get_template(request),
context
)
Now the landing page context will have a name context variable containing the value of the name form field!
Im trying to learn how to use APIs in Django and I want to return some simple data from one within a web page in html. The API is Mozscape and when running it in a terminal one can obtain the score of a website out of 100 like so:
from mozscape import Mozscape
client = Mozscape(
'api_user_id',
'secret_key')
url = 'http://www.google.com'
get_da = client.urlMetrics(url, cols=68719476736)
print(get_da)
and this prints the following
{u'pda': 100}
the '100' is all I want there. I want a user to enter a url into a form in a page in Django and to get that score int back so I have made the following models, views and form
class DomainAuthority(models.Model):
url = models.URLField(max_length=300)
def __str__(self):
return self.url
class Meta:
verbose_name = 'Domain'
verbose_name_plural = 'Domains'
views.py
def DomainAuthorityView(request):
form = DomainAuthorityForm(request.POST or None)
if form.is_valid():
new_domain = form.save(commit=False)
new_domain.save()
return render(request, 'domain_authority.html', {'form': form})
forms.py
class DomainAuthorityForm(forms.ModelForm):
class Meta:
model = DomainAuthority
fields = ['url']
so I have the form working and when a url is entered in the html form its saved in the admin backend but what I dont know how to do now is how to pass that url into the Mozscape API so that I can get the score back.
I took a look at the Django rest framework and installed it and followed some quick tutorial videos on Youtube and other places but in those examples they were taking saved Django objects such as blog posts and returning them as JSON data which is not what I want to do.
I tried import the API into the views file and then adding this line into then view
get_da = client.urlMetrics(new_domain, cols=68719476736)
but then I get this error after entering the url into the form in the web page
<DomainAuthority: https://www.google.com> is not JSON serializable
what do I need to do here to pass the user inputted urls to the API and return the correct response in a web page?
thanks
EDIT - UPDATED VIEW as of 19th Aug
def DomainAuthorityView(request):
form = DomainAuthorityForm(request.POST or None)
if form.is_valid():
new_domain = form.save(commit=False)
new_domain.save()
response = requests.get(new_domain.url, cols=68719476736)
#response = requests.get(client.urlMetrics(new_domain.url, cols=68719476736))
json_response = response.json()
score = json_response['pda']
return render(request, 'domain_authority_checked.html', {'score': score})
else:
return render(request, 'domain_authority.html', {'form': form})
so now it should redirect after successful form completion with url and the url is passed to the API to get the score and the redirects to 'domain_authority_checked.html' with just this
{{ score }}
so I have two outcomes here, if I pass in 'client.urlMetrics' into response I can load the 'domain_authority.html' but after a url his input into the form an error page returns with this
InvalidSchema at /domainauthority/
No connection adapters were found for '{'pda': 100}'
if I dont pass 'client.urlMetrics' to response then Django doesn't know what 'cols' is and returns this
TypeError at /domainauthority/
request() got an unexpected keyword argument 'cols'
I suggest this approach:
import requests
response = requests.get(url)
json_response = response.json()
score = json_response['key_name']
You can then simply render a template, add the score to the template context and display the value using {{ }}.
You may also want to define a rest_framework serializer (otherwise you don't need django_rest_framework) and verify the response against this serializer in order to ensure that you've received what you expected:
serializer = MySerializer(data=json_response)
if serializer.is_valid():
score = json_response['key_name']
You can use:
return HttpResponse(json.dumps(data), content_type='application/json')
instead of render the form. Only you need to import json in the header and create an empty dict named "data".
I have a very simple index page view, from which the user can fill in a login popup, which sends a post request to /login
def index(request):
"""Shows list of studyspaces, along with corresponding 'busyness' score"""
context = {'study_space_list': StudySpace.objects.order_by('-avg_rating')}
if request.user.is_authenticated():
context['user'] = request.user
else:
context['login_form'] = LoginForm()
context['user_form'] = UserForm()
context['student_form'] = StudentForm()
return render(request, 'spacefinder/index.html', context)
If the login is valid it simply redirects to the index page, this works fine.
The login view looks as follows:
def user_login(request):
form = LoginForm(request.POST)
if request.method == 'POST' and form.is_valid():
user = form.login(request)
if user:
login(request, user)
return redirect(reverse('spacefinder:index'))
# Load the context all over again
context = {
'study_space_list': StudySpace.objects.order_by('-avg_rating')
}
context['login_form'] = form
context['user_form'] = UserForm()
context['student_form'] = StudentForm()
return render(request, 'spacefinder/index.html', context)
However when the login is incorrect I want to be able to refresh the page and show the login form errors inside the index template (in the login popup)
I'm actually able to achieve this with the above code, but I'm unhappy with the solution for the following reasons:
I have to manually fetch the context all over again, e.g user/student forms and studyspaces, this goes against the DRY principle
When the page is refreshed the url is localhost:8000/spacefinder/login
Screenshot of behaviour here
I'm wondering if there's somehow a way to use redirect to reload the index page and somehow pass errors from my login_form, e.g. something like:
return redirect('spacefinder:index', {'login_form': form})
I've looked into using messages to pass form validation errors, but struggled to get this working since Validation Errors are thrown inside forms.py, and I'm unable to fetch the request instance from inside a ModalForm to properly create a message
You are doing it the wrong way around.
Consider these prerequisites:
entry point to your page is the index view
the index view must only be accessible by authenticated users
the login view allows both methods GET and POST and is accessible to anonymous users only
The reason to use Django is to make use of all the features that it offers, and that includes handling of the above (because that is what most pages need, not only you).
To set it up correctly you need to define your urls.py like this:
from django.contrib.auth.decorators import login_required
urlpatterns = [
....
url('^login/$', user_login, 'login'),
url('^/$', login_required(index), 'index'),
....
]
In your settings/base.py (or settings.py if you have no environment differentiation) tell Django how to redirect users:
LOGIN_URL = reverse_lazy('login')
LOGIN_REDIRECT_URL = reverse_lazy('index')
https://docs.djangoproject.com/en/1.9/ref/settings/#login-url
https://docs.djangoproject.com/en/1.9/ref/settings/#login-redirect-url
Simplify your index view:
def index(request):
"""Shows list of studyspaces, along with corresponding 'busyness' score"""
context = {'study_space_list': StudySpace.objects.order_by('-avg_rating')}
if request.user.is_authenticated():
context['user'] = request.user
else:
return HttpResponseForbidden() # prevented by Django, should never happen
return render(request, 'spacefinder/index.html', context)
Let the user_login view deliver the empty login form:
#require_http_methods(["GET", "POST"])
def user_login(request):
params = getattr(request, request.method)
form = LoginForm(params)
if request.method == 'POST' and form.is_valid():
user = form.login(request)
if user:
login(request, user)
return redirect(reverse('spacefinder:index'))
# Load the context for new form or form with errors
context = {
'study_space_list': StudySpace.objects.order_by('-avg_rating')
}
context['login_form'] = form
context['user_form'] = UserForm()
context['student_form'] = StudentForm()
return render(request, 'spacefinder/index.html', context)
You have not presented any code that handles the UserForm or the StudendForm. You would need to add that to the user_login view, as well - if this is something that all users should fill in every time they login. Otherwise use a different view.
It's worth looking at modules like allauth. They might spare you some work when it comes to allowing users to login with their e-mail addresses, ascertain that e-mail addresses are unique in the system etc.
Hello I am working on a simple form. The form submits fine but if I refresh the page it resubmits the data. Seems the form is holding the data after submit and I assume since after the submit the request method is post. Question is what is the best way after the submit to clear the form in Django. After the submit the form variables should not be holding the values anymore. Thanks
def testimonials(request, template_name="testimonials.html"):
reviews = Reviews.objects.all()
if request.method == 'POST':
form = forms.ReviewsForm(data = request.POST)
# create a new item
if form.is_valid(): # All validation rules pass
# Process the data in form.cleaned_data
# ...
if form.is_valid():
nameIn = form.cleaned_data['name']
reviewIn = form.cleaned_data['review']
newReview = Reviews(name = nameIn, review = reviewIn)
newReview.save()
return render_to_response(template_name, locals(), context_instance=RequestContext(request))
else:
# This the the first page load, display a blank form
form = forms.ReviewsForm()
return render_to_response(template_name, locals(), context_instance=RequestContext(request))
Typically, you would issue a redirect after processing a form/POST request (this is common web development practice to avoid the resubmission issue you mentioned). So instead of a render_to_response, you might issue a HttpResponseRedirect like so:
if form.is_valid():
# Process form as desired here
# Simple example; use reverse() to avoid hard-coding URLs
return HttpResponseRedirect('/success/')
Check out the using a form in view for a skeleton of how forms are typically processed.
use reverse instead of render to response
if form.is_valid():
nameIn = form.cleaned_data['name']
reviewIn = form.cleaned_data['review']
newReview = Reviews(name = nameIn, review = reviewIn)
newReview.save()
return HttpResponseRedirect(reverse('app_name:url'))
You could also use the 'redirect' shortcut:
from django.shortcuts import redirect
...
return redirect(newReview)
This is assuming you have get_absolute_url defined in your Review Model.
See the docs for more info.