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!!
Related
So i'm trying to build something, so that users would be able to report something on site. Here's the model,
class Report(models.Model):
reporting_url = models.URLField()
message = models.TextField()
Here's the view,
def report(request):
url_report = ???
if request.method == 'POST':
form = ReportForm(request.POST or None)
if form.is_valid():
new_form = form.save(commit=False)
new_form.reporting_url = url_report
new_form.save()
I can't use something like,
url_report = request.get_full_path()
since I need to create/edit several views & repeat things in that case.
When I'm using something like,
url_report = request.META.get('HTTP_REFERER')
it's returning the URL of same page from where the from is written. I'm using something like,
Report
to reach the Report form from several different apps/html_pages.
How can I get the URL of previous page from where user has pressed the "Report" button?
Please help me with this code!
You could store the referer in the session whenever the Report button is pressed:
def report(request):
if request.method == 'GET':
request.session['report_url'] = request.META.get('HTTP_REFERER')
# ...
if request.method == 'POST':
form = ReportForm(request.POST or None)
if form.is_valid():
new_form = form.save(commit=False)
new_form.reporting_url = request.session.get('report_url')
new_form.save()
You have to persist this referer beyond one request-response cycle. The session is the designated way to do that. Another option would be to render that url as a hidden form field, but that can be easily tampered with.
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.
I have a user sign up and login template set to send information to the same view (detail). They were both working fine before, however now the redirect on user creation is no longer going to the correct URL (http://127.0.0.1:8000/accounts/login/?next=/accounts/21/) the "accounts/login?next=" portion of the URL is being added for some reason and I cannot understand where it came from as it was not there before.
I'm using stronghold which makes every view login_required unless noted otherwise with #public above it.
I have found some posts about LOGIN_URL needs to be set in setting.py or a next key. However this was working fine before so I do not think that is the problem. let me know if you need more code posted and I will put it up.
Thanks,
-the route I want to hit is
url(r'^accounts/(?P<user_id>\d+)/$', views.detail, name='detail')
-my register view is below
#public
def register(request):
if request.method == 'POST':
form = EmailUserCreationForm(request.POST)
if form.is_valid():
new_user = form.save()
playthrough = PlayThrough(user_id=new_user.id)
playthrough.save()
request.session['user_id'] = new_user.id
return HttpResponseRedirect('/accounts/{}/'.format(new_user.id))
else:
form = EmailUserCreationForm()
return render(request, 'dep_server/register.html', {
'form': form,
})
-this is he view that is supposed to render the user info
def detail(request, user_id):
if request.session['user_id'] == int(user_id):
user = EmailUser.objects.get(id=user_id)
module_list = ModuleRef.objects.all()
return render(request, 'dep_server/detail.html', {
'user': user,
'module_list': module_list
})
else:
return HttpResponseRedirect('/accounts/auth/')
I figured out the problem, I was not logging in the user on creation. Which is why the login worked and the sign up did not. below is the code that I added to the register view, which got it to work.
user = authenticate(
email = form.cleaned_data['email'],
password = form.cleaned_data['password2']
)
login(request, user)
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.
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.