How to override password_change error messages in django? - django

I have spent ages on the net how to override the change_password form in django. I created my forms and I can change my passwords successfully. Now I want to display my errors on the page.
(By the way , I'm using django-registration.)
The problem is I have to change error messages. In my template I'm using this function to display new_password1 errors :
{% if form.new_password1.errors %}
<div class="error_message"> blah </div>
{% endif %}
However it consists of all new_password1 errrors. I looked the docs and found that CharField has only reqiured, max and min. I need to check each specific errors of the new_password1 (confirmation error, required error and min,max) and produce my own error messages. Since the CharField doesn't have a matching keyword, I tried a clean method in my forms.py which looks like :
def clean_password2(self):
if 'new_password1' in self.cleaned_data and 'new_password2' in self.cleaned_data:
if self.cleaned_data['new_password1'] != self.cleaned_data['new_password2']:
raise forms.ValidationError(_(u"no match"))
return cleaned_data
Finally, I don't know how to check this clean_password2 validation in my template. When I wrote registration page, I can display all my errors by looping the errors. And it displays all overrided errors. This time it doesn't work. So my quesstions are:
1- How can i check all specific errors in my templates ? like if form.new_password1.required.errors
2- How can i display this clean_password2 messages ?

In django-speak, what you're referring to as the view is the template. It's rather confusing!
Update: I see that you define a clean_password2 function but you are checking for fields called new_password1, new_password2.
Unless you have a field called password2, that is the field that your clean method is validating.
The messages for clean_password2 are generated in {{ form.password2.errors }}, but to me, it sounds like you don't have a field called password2.
Change the name of your method to clean_new_password2.
{% if form.new_password1.errors %}{{ form.new_password1.errors }}{% endif %}
{% if form.new_password2.errors %}{{ form.new_password2.errors }}{% endif %}
Form field cleaning works per field.. you access the errors off the field object.

Like #Yuji said, use {% if form.non_field_errors %} in your template.
Now just a bit on usability. Concerning the user registration and password change form, the only non-field errors your can expect will be mismatching passwords, so unlike other forms where your going to print the non-field errors at the very beginning, for these forms it makes sense to print the one non-field error before the two password input fields, possibly wrapping them in a parent that has a red background, to make it more obvious that the values of the two fields are related and that the error concerns the two fields, not the form in general.

Related

How can i add a "like" button in a Django class ListView

I am pulling my hair out trying to add a "like" button in my siteĀ“s post app, but as i want to add it in a ListView that contains the rest of the posts entries and everyone has the option to be commented I have added a Formixin to do so, so, now i cannot add another form for the like button as it would mean two posts requests....so I am not finding a clear solution... I have read here and there about using AJAX or Json techs but as im new programing im kind of stuck in it... has anyone any tip to offer?
While using AJAX (javascript XHR requests) would be the proper way so the page doesn't need to be refreshed when just clicking a like button, you can do it without AJAX.
HTML
On the HTML side of things, you can have multiple forms (<form>), one for each post, which have a hidden input field that's the post's id. You have set that explicitly in the HTML template, e.g.
{% for post in post_list %}
<h3>{{ post.title }}</h3>
<p>{{ post.summary }}</p>
<form method="post">
{% csrf_token %}
<input type="hidden" value="{{ post.id }}" name="{{ form.id.html_name }}">
<input type="submit">Like</input>
</form>
{% endfor %}
So basically you're reusing the form multiple times, changing the "value" attribute to match the post.
Django Form
Adding the FormMixin to your view is the right step, just use the form_class to a custom LikeForm with just one field that's an IntegerField called id.
View
By adding the FormMixin you get the form_valid() method, which you'll want to override to save the like:
def form_valid(self, form):
id = form.cleaned_data['id']
try:
post = Post.objects.get(id=id)
except Post.DoesNotExist:
raise Http404
post.likes.add(self.request.user) # assuming likes is a m2m relation to user
return redirect('post_list') # this list view
Hopefully I am not so late, I had similar challenges trying to implement the same functionalities on my website.
I came to realize that each button id should be unique (Preferably the post id if blog), but the classes can be the same.
I was able to solve it. Here is an article I wrote on medium recently on the steps I followed to so get this working you can check it out here

If views catches error, reload page and display error

I don't know if this is possible with Django or not, but here's my question.
I have a form where users submit some stuff, and I want to know if I can catch an error in my views and then reload the page using the original template and throw the error in there, so the user can see it?
I have some code that returns the error I want to display, but is it possible to redirect to the original template of my view and insert this error code into there IF the form fails?
Bear in mind that roundup isnt value a user submits, but a value that is calculated from some other python code.
if roundup >= 1:
return HttpResponse("Price too low!")
You could add the error to your form in this way
if roundup >= 1:
form.add_error(None, "Price too low!")
return render(request, 'your_template', {'form': form})
and to show it the error in your template
{% for error in form.non_field_errors %}
<div class='alert alert-danger' role='alert'>
{{ error }}
</div>
{% endfor %}

How do I look in a list of items, find the user and see if it exists in a different table and change the template as a result?

I have a simple follow/following setup running.
When a user (request.user) see's an object she likes, she can click the follow button and follow that user.
When she returns I want that button on the object to now not be enabled cause she is already following that user.
What is happening is that in the background, the follower/followee record is being made. The object in question has the id of the followee. I just can't figure out how to add that representation to the object_list.
In REST I would add a field to the serializer and that would take care of it. I could then evaluate the truthiness of the new field.
Any ideas on how to accomplish this?
You should do it as a separate query and make the test in the template.
view:
def objects_list(request):
...
return render(request, "the_template_path.html", {
'objects': ObjectName.objects.all()[0:100],
'followed_object_ids': ObjectName.objects.filter(follower=request.user).values_list('id', flat=True)
})
template:
{% for object in objects %}
{% if object.id in followed_object_ids %}
...
{% else %}
...
{% endif %}
{% endfor %}
That will get you started. Obviously you don't want to use generic names like object.
It would then probably be better to move the followed_object_ids query in a middleware so you don't always do it (really useful if you have featured objects widgets everywhere for instance).

Authentication using Email and resulted routing problems

I'm trying to Authenticate users by their emails instead of username.
I'm using django-userena and by using its Docs,etc. I set almost anything that is needed. Something like : USERENA_WITHOUT_USERNAMES = True in its setting, etc.
But after signing up, I've faced a chain of problems. like trying to pass my username in the url for authentication, signup completion problems, etc.
I changed some view functions that need username as an argument, but this method neither solved my problem , nor is a correct (and maybe secure) way to do it.
for instance, by routing to this URL http://127.0.0.1:8000/accounts/signup/complete/ (after $ ./manage.py check_permissions ) I get this error:
global name 'username' is not defined
/userena/views.py in directto_user_template
user = get_object_or_404(User, username_iexact=username)
Is there anything that I'm missing ??
UPDATE:
Here is the output that I get:
Caught NoReverseMatch while rendering: Reverse for 'userena_activate'
with arguments '('xyz#xyz.com',
'70b60d1d97015e03ba8d57f31e4c7ff14d6ab753')' and keyword arguments
'{}' not found.
It's clear that userena tries to the email as username with URL :
userena/templates/userena/emails/activation_email_message.txt, error at line 8
1 {% load i18n %}{% autoescape off %}
2 {% if not without_usernames %}{% blocktrans with user.username as username %}Dear {{ username }},{% endblocktrans %}
3 {% endif %}
4 {% blocktrans with site.name as site %}Thank you for signing up at {{ site }}.{% endblocktrans %}
5
6 {% trans "To activate your account you should click on the link below:" %}
7
8 {{ protocol }}://{{ site.domain }}{% url userena_activate user.username activation_key %}
9
10 {% trans "Thanks for using our site!" %}
11
12 {% trans "Sincerely" %},
13 {{ site.name }}
14 {% endautoescape %}
UPDATE 2:
Alright . by reading the source code for SignupFormOnlyEmail class form, it says that a random username is generated automatically.
class SignupFormOnlyEmail(SignupForm):
"""
Form for creating a new user account but not needing a username.
This form is an adaptation of :class:`SignupForm`. It's used when
``USERENA_WITHOUT_USERNAME`` setting is set to ``True``. And thus the user
is not asked to supply an username, but one is generated for them. The user
can than keep sign in by using their email.
"""
def __init__(self, *args, **kwargs):
super(SignupFormOnlyEmail, self).__init__(*args, **kwargs)
del self.fields['username']
def save(self):
""" Generate a random username before falling back to parent signup form """
while True:
username = sha_constructor(str(random.random())).hexdigest()[:5]
try:
User.objects.get(username__iexact=username)
except User.DoesNotExist: break
self.cleaned_data['username'] = username
return super(SignupFormOnlyEmail, self).save()
UPDATE :
I finally solved the problem. I was also using django-email-as-username beside to django-userena. This was the cause of my problem. Apparently, they have some conflicts. WATCH OUT
You've defined url route userena_activate with keyword arguments (username and activation_key), but you call it just with arguments, change template to keyword arguments:
{% url userena_activate username=user.username activation_key=activation_key %}
edit due to comment:
I'm not sure if I understand your problem corectly, but I think there's a problem elsewhere. Yours error message says:
Caught NoReverseMatch while rendering: Reverse for 'userena_activate' with arguments '('xyz#xyz.com', '70b60d1d97015e03ba8d57f31e4c7ff14d6ab753')' and keyword arguments '{}' not found.
It seems you pass valid arguments to function, but you pass them wrong way. URL route in urls.py is defined in a way to expect kwargs, but you pass just args, which mismatch its definition. That is why you get this error message. Simple pass arguments as kwargs (that means each argument is passed with its name and value as showed above).
urls.py difference between argument and keyword argument:
url(r'^(?P<username>[\.\w]+)/activate/(?P<activation_key>\w+)/$', userena_views.activate, name='userena_activate'),
^ this is _keyword argument_ 'username', expects value with argument value AND name
and
url(r'^page/(.*)/$', userena_views.ProfileListView.as_view(), name='userena_profile_list_paginated'),
^ this is argument, expects only value, not argument name
A really simple alternative for using the email address as the username (effectively) is django-easy-userena - this is an upward compatible fork of Userena that adds a few nice features:
use email address as effective user ID - generates a random numeric
username that is hidden in forms and confirmation emails
fewer dependencies - doesn't require django-guardian or easy-thumbnails
terms of service agreement field is built in, displays as checkbox
I've had good results with this - installation was manual for some reason (copy userena dir to site-packages) but it worked without hassles.
I like the overall Userena approach, but easy-userena is a better fit for what I need.

Threadedcomments - csrf token and user_name

I am using django-threadedcomments. Everything works fine except 2 things: csrf token and user template tag.
Problem is, when user submits a comment, there is no csrf token for the form, so the form could not be validated server-side. Tried adding csrf token to the dictionaries that threaded-comments passes internal with no result; kept receiving errors (most of them telling that this-method takes only 2 arguments with 3 given). Tried to fix those methods to accept 3 arguments and just pass third one further; no success.
Did someone stumble upon the same problem in past and solved it? because this is not an acceptable solution for me:
MIDDLEWARE_CLASSES = (
#'django.middleware.csrf.CsrfViewMiddleware',
)
Second one - there is a HTML helper to get the user_id for the user who posted a comment. Is there an out of the box html helper to get the name of the user by id or would i have to write it myself?
http://code.google.com/p/django-threadedcomments/
Here is the code for the project, I cant really tell exactly which chunks of it should be posted here so I just give link to the entire project.
I am really stuck in here and any help would be welcomed.
Thanks in advance.
Tried adding csrf token to the
dictionaries that threaded-comments
passes internal with no result;
csrf_token is a template tag -- it shouldn't be passed as an argument somewhere.
I took a look at threadedcomments and it's based on contrib.comments with no html rendering, so it's up to you to insert the csrf_token in your template.
What does your TEMPLATE code look like that is displaying your form code?
If you have CsrfViewMiddleware enabled and you are using RequestContext in your view, you simply need to add {% csrf_token %} inside of your <form></form> tags.
As for getting the user name:
ThreadedComment is a subclasses of Comment which has a name property, or you could just access the User directly...
{% for comment in comments %
{{ comment.user.first_name }}
{{ comment.name }}
{% endfor %}
You should use {% csrf_token %} tag or #csrf_protect in a views
You can put your form in its own template and {% include %} it into your page template. As of Django 1.3, {% include %} can pass context variables to the included template. Here's what I'm using with django.contrib.comments instead of a templatetag:
...
{% include "comments/comment-form.html" with content_object=article user=request.user %}
...
{%csrf_token %} works in this included template because it's using your main view context.