Django. Show error message on current page - python

Help me please! I'm trying to show error message:
In forms:
def clean_form(self):
url = self.cleaned_data['text']
if url == 'qwe':
raise ValidationError("Error")
return self.cleaned_data
In view:
def main_site(request):
if request.method == 'POST':
form = Form(request.POST or None)
if form.is_valid():
form.clean_form()
link = form.cleaned_data['text']
...
But when I send 'qwe' in form:
And press 'send'. Take:
But I want to see Error on same page. What's I should be do?
Thank you!

You are only checking the text field, therefore you should override the clean_text method.
def clean_text(self):
url = self.cleaned_data['text']
if url == 'qwe':
raise ValidationError("Error")
return url
Remove the clean_form() line from your code. Django will automatically call the clean_text method for you when you check if form.is_valid().
See the docs on cleaning a specific field for more info.
If you were checking multiple fields at the same time, then you would override clean. See the docs on cleaning fields that depend on each other for more information about that.

Related

Django: User Reporting Some URL on Website

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()
I created Form for this Model including 'message' field only because 'reporting_url' is something it needs to populate by itself depending upon the specific page from where user has clicked "Report" button.
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 was wondering How can I pass the specific url to 'reporting_url' field in form depending on the Page from where user has clicked "Report" button? (Much like s we see on social Networks).
Am I doing this correctly, Or is there a better way for doing this?
Please help me with this code. Thanks in Advance!
If there is a report button on that specific page then I believe you could write custom context processor.
More info: Django: get URL of current page, including parameters, in a template
https://docs.djangoproject.com/en/1.11/ref/templates/api/
Or maybe just write it directly in the views.py in your function and set
url_report = request.get_full_path()
I think you can use the form on the same page of the URL and use:
url_report = request.get_full_path()
in the view, to get the current URL.
Else if you want to create a separate view for the reporting form. You can use
url_report = request.META.get('HTTP_REFERER')
to get the previous or refering URL which led the user to that page.
request.META.get('HTTP_REFERER') will return None if it come from a different website.

How do you make a url that passes a parameter work in Django?

I'm working on registration logic and I can't seem to make the parameter pass in to work properly. The error I get is a 404 page not found. Previously, I also got a “The view didn't return an HttpResponse object" error. Any help is appreciated.
Here is my url from urls.py:
url(r'^accounts/confirm/(?P<activation_key>\d+)/$', 'mysite.views.confirm', name='confirm'),
This is my views.py:
def confirm(request, activation_key):
if request.user.is_authenticated():
HttpResponseRedirect('/home')
user = Hash.objects.filter(hash_key = activation_key)
if user:
user = Hash.objects.get(hash_key = activation_key)
user_obj = User.objects.get(username= user.username)
user_obj.is_active = True
user_obj.save()
HttpResponseRedirect('/home')
I send the url with a string that looks like:
"Click the link to activate your account http://www.example.com/accounts/confirm/%s" % (obj.username, activation_key)"
So the link looks like this:
http://www.example.com/accounts/confirm/4beo8d98fef1cd336a0f239jf4dc7fbe7bad8849a127d847f
You have two issues here:
Remove the trailing / from your pattern, or make it /? so it will be optional.
/d+ will only match digits, and your link also contains other characters. Try [a-z0-9]+ instead.
Complete pattern:
^accounts/confirm/(?P<activation_key>[a-z0-9]+)$
Remove / from end of your url:
url(r'^accounts/confirm/(?P<activation_key>\d+)$', 'mysite.views.confirm', name='confirm'),
or add / to end of your link:
http://www.example.com/accounts/confirm/4beo8d98fef1cd336a0f239jf4dc7fbe7bad8849a127d847f/

Why Django test with blank data post does not work?

I'd like to understand why this testing case does not work: I'm testing that my signup form in my view returns errors when I try to submit an empty form.
In tests.py:
class SignupViewTestCase(TestCase):
def test_signup_post_blank(self):
resp = self.client.post(reverse(signup), {}) # blank data dictionary
self.assertFormError(resp, form='signup_form', field='email',
errors='Ce champ est obligatoire') # French version of "This field is mandatory"
In views.py:
def signup(request):
signup_form = SignupForm(request.POST or None)
if signup_form.is_valid():
ema = signup_form.cleaned_data['email']
raw_pwd = signup_form.cleaned_data['password']
try:
BizProfile.create(ema, raw_pwd)
except IntegrityError:
signup_form.errors['__all__'] = signup_form.error_class([
ERR_USER_EXISTS])
else:
messages.success(request, SUC_ACC_CREA)
messages.info(request, INF_CONN)
return redirect(signin)
return render(request, 'sign_up.html', locals())
When testing manually in my browser, I can see there IS actually an error on the email field when I submit it without data.
But test result says:
AssertionError: The field 'email' on form 'signup_form' in context 0 contains no errors
Any idea of what is happening? Thanks.
Actually, the problem is related to the or None.
That's because an empty dictionary is false. In an "or" condition, Python always returns the second value if the first is false. That means your form is being instantiated just with "None", rather than an empty dictionary: which means it is not being bound at all. A non-bound form does not have any errors.
Changing your test is not a good solution, because a browser would never submit the "email" key without a value: fields without values are simply not send in the POST data, which is why an empty dictionary is the right way to test this. Instead of changing your test, you should use the canonical view pattern, and remove that broken shortcut.
if request.method == 'POST':
signup_form = SignupForm(request.POST)
if signup_form.is_valid():
...
else:
signup_form = SignupForm()
return...

How to hide success page in Django

I'd like to know if anyone knows:
For example, I have a form that user fills in, and when he submits, the page will redirect to "thank you" page. Everything works fine. In urls.py I had this line pointing that the page exists:
url(r'^thankyou/$', 'render_form'),
But then, when I type in url mysite.com/thankyou/, the page "Thank you" appears... But I need it to appear only when I submit a form and hide it when user tries to open it directly.
Please help. Thanks in advance!
You could put something in the session in your form handling view before redirecting, and check it in the thank-you URL: if it's not there, then return a 403 error. Something like:
def form_handling_view(request):
if request.POST:
form = MyForm(request.POST)
if form.is_valid():
... handle the form ...
request.session['form_posted'] = True
return redirect('thank_you')
def thank_you(request):
if not request.session.pop('form_posted', False):
return HttpResponseForbidden('not permitted')
... render thank_you page ...
Note I'm using pop in thank_you to ensure that the key is deleted from the session no matter what.

Problems raising a ValidationError on a Django Form

I'm trying to validate that a submitted URL doesn't already exist in the database.
The relevant parts of the Form class look like this:
from django.contrib.sites.models import Site
class SignUpForm(forms.Form):
# ... Other fields ...
url = forms.URLField(label='URL for new site, eg: example.com')
def clean_url(self):
url = self.cleaned_data['url']
try:
a = Site.objects.get(domain=url)
except Site.DoesNotExist:
return url
else:
raise forms.ValidationError("That URL is already in the database. Please submit a unique URL.")
def clean(self):
# Other form cleaning stuff. I don't *think* this is causing the grief
The problem is, regardless of what value I submit, I can't raise the ValidationError. And if I do something like this in the clean_url() method:
if Site.objects.get(domain=url):
raise forms.ValidationError("That URL is already in the database. Please submit a unique URL.")
then I get a DoesNotExist error, even for URLs that already exist in the Database. Any ideas?
django channel in IRC saved me here. The problem was that the URLField.clean() does two things I wasn't expecting:
If no URL scheme is present (eg, http://) the method prepends 'http://' to the url
the method also appends a trailing slash.
The results are returned and stored in the form's cleaned_data. So I was checking cleaned_data['url'] expecting something like example.com and actually getting http://example.com/. Suffice to say, changing my clean_url() method to the following works:
def clean_url(self):
url = self.cleaned_data['url']
bits = urlparse(url)
dom = bits[1]
try:
site=Site.objects.get(domain__iexact=dom)
except Site.DoesNotExist:
return dom
raise forms.ValidationError(u'That domain is already taken. Please choose another')
I do it this way. It's slightly simpler.
try:
a = Site.objects.get(domain=url)
raise forms.ValidationError("That URL is already in the database. Please submit a unique URL.")
except Site.DoesNotExist:
pass
return url
I think, you can return '' and fill _errors.
msg = u"That URL is already in the database. Please submit a unique URL."
self._errors["url"]=ErrorList([msg])
return ''
or
from django.contrib.sites.models import Site
class SignUpForm(forms.Form):
# ... Other fields ...
url = forms.URLField(label='URL for new site, eg: example.com')
def clean_url(self):
url = self.cleaned_data['url']
try:
a = Site.objects.get(domain=url)
raise forms.ValidationError("That URL is already in the database. Please submit a unique URL.")
except Site.DoesNotExist:
return url
return ''
def clean(self):
# Other form cleaning stuff. I don't *think* this is causing the grief
Well I logged in cause I found this via Google with a similar issue and wanted to add a comment to Carl Meyers post noting that using self._errors is totally valid as per the Django docs:
http://docs.djangoproject.com/en/1.2/ref/forms/validation/#cleaning-and-validating-fields-that-depend-on-each-other

Categories