Modifying django-allauth error messages on a signup form - python

I'm currently building a website that makes use of django-allauth and I've come across a problem regarding error messages while using a custom User model.
My custom User model is called CustomUser, I've noticed that when django-allauth handles errors regarding the username, it uses the name of the user model as the starting word to the error message's sentence. Example image is linked below.
Image of the error message
How can I change this error message? I'd like to stay away from overriding any django-allauth views if possible, though I'd be happy with any solution!
This is my Django form code that makes use of django-crispy-forms:
<form class="signup" id="signup_form" method="post" action="{% url 'account_signup' %}">
{% csrf_token %}
<div class="row">
<div class="col-12 col-lg-7">
{{ form.email|attr:"autofocus"|as_crispy_field }}
</div>
<div class="col-12 col-lg-5">
{{ form.username|as_crispy_field }}
</div>
<div class="col-6 col-lg-4">
{{ form.first_name|as_crispy_field }}
</div>
<div class="col-6 col-lg-4">
{{ form.last_name|as_crispy_field }}
</div>
<div class="col-12 col-lg-4">
{{ form.birthday|as_crispy_field }}
</div>
<div class="col-12 col-sm-6">
{{ form.password1|as_crispy_field }}
</div>
<div class="col-12 col-sm-6">
{{ form.password2|as_crispy_field }}
</div>
<div class="col-12 text-center">
{{ form.captcha|as_crispy_field }}
{% for error in form.captcha.errors %}
{% if error %}
<style>
#div_id_captcha {
margin-bottom: 0px !important;
}
</style>
<span class="invalid-feedback d-block mb-3">
<strong>
You must complete the captcha to register
</strong>
</span>
{% endif %}
{% endfor %}
</div>
</div>
{% if redirect_field_value %}
<input type="hidden" name="{{ redirect_field_name }}" value="{{ redirect_field_value }}" />
{% endif %}
<button type="submit" class="btn btn-primary btn-light mb-3">Register <i class="fa fa-user-plus fa-fw"></i></button>
<p>Already have an account?<br /><small>Login here</small></p>
</form>

Related

Django: Form submit button not loading blog post {{ post.slug }} value in second form

My Django template renders the post.slug value in the first 'edit' form button correctly but on the modal pop up for the 'delete' it does not.
This was working a week or so ago. The 'Edit' button works perfectly, yet with almost identical code, under a Bootstrap modal (for confirmation of the post deletion) the 'Delete' button does not load the value="{{ post.slug }}"
my template:
{% extends "base.html" %}
{% block content %}
<div class="post-opinion">
<h3>{{ user }}'s Posts</h3>
</div>
<div class="container-fluid">
<div class="row">
<!-- Blog Entries Column -->
<div class="col-12 mt-3 left">
<div class="row">
{% for post in post_list %}
<div class="col-md-4">
<div class="card mb-4">
<div class="card-body">
<div class="image-container">
{% if "placeholder" in post.featured_image.url %}
<img class="card-img-top"
src="https://codeinstitute.s3.amazonaws.com/fullstack/blog/default.jpg">
{% else %}
<img class="card-img-top" src=" {{ post.featured_image.url }}">
{% endif %}
<div class="image-flash">
<p class="author">Author: {{ post.author }}</p>
</div>
</div>
<a href="{% url 'post_detail' post.slug %}" class="post-link">
<h2 class="card-title">{{ post.title }}</h2>
<p class="card-text">{{ post.excerpt }}</p>
</a>
<hr />
<p class="card-text text-muted h6">{{ post.created_on}} <i class="far fa-heart"></i>
{{ post.number_of_likes }}</p>
<div>
<form method="post">
{% csrf_token %}
<button type="submit" class="btn btn-primary mt-3" value="{{ post.slug }}" name="edit">Edit</button>
<button type="button" class="btn btn-danger mt-3" data-toggle="modal" data-target="#delete-confirmation">
Delete
</button>
</form>
</div>
</div>
</div>
</div>
{% if forloop.counter|divisibleby:3 %}
</div>
<div class="row">
{% endif %}
{% endfor %}
</div>
</div>
</div>
{% if is_paginated %}
<nav aria-label="Page navigation">
<ul class="pagination justify-content-center">
{% if page_obj.has_previous %}
<li>« PREV </li>
{% endif %}
{% if page_obj.has_next %}
<li> NEXT »</li>
{% endif %}
</ul>
</nav>
{% endif %}
</div>
<div class="modal fade" id="delete-confirmation" tabindex="-1" role="dialog" aria-labelledby="deleteConfirmationModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Are you sure you want to delete this post?</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<form method="post" class="d-inline">
{% csrf_token %}
<button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
<button type="submit" class="btn btn-danger" value="{{ post.slug }}"
name="delete">Delete</button>
</form>
</div>
</div>
</div>
</div>
{% endblock %}

how can i display error messages when using the inbuilt reset password and password change in Django

I am working on some user forgot password as well as password reset using Django Built in functionality but I am making use of my template to render the page and form. I will like a way to render the messages either error or success messages so that the user understands what is going on in case the password is too short or so.
urls.py
from django.urls import path
from . import views
from django.contrib.auth import views as auth_views
urlpatterns = [
path('', views.Dashboard, name='dashboard'),
path('login/', views.Login, name='login'),
path('logout/', views.Logout, name='logout'),
path('register/', views.Register, name='register'),
path('forgetpassword/', views.ForgetPassword, name='forgetpassword'),
path('password_change/', auth_views.PasswordChangeView.as_view(
template_name='auth/password/change-password.html'), name='password_change'),
path('password_change/done/', auth_views.PasswordChangeDoneView.as_view(
template_name='auth/password/change-password-done.html'), name='password_change_done'),
change-password.html
{% extends 'auth/base.html' %}
{% load static %}
{% block content %}
<div class="page-wrapper" style="height: 100vh!important;">
<div class="page-content--bge5">
<div class="container">
<div class="login-wrap">
<div class="login-content">
<div class="login-logo">
<a href="#">
<img src="{% static 'images/icon/logo-new.png' %}" alt="CoolAdmin">
</a>
</div>
{% if messages %}
{% for message in messages %}
<div class="alert alert-{{message.tags}} with-close alert-dismissible fade show">
{{message}}
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
{% endfor %}
{% endif %}
<div class="login-form">
<form method="POST">
{% csrf_token %}
<div class="form-group">
<label>Current Password</label>
<input class="au-input au-input--full" type="password" name="old_password" id="id_old_password" placeholder="Current Password" required>
</div>
<div class="form-group">
<label>New Password</label>
<input class="au-input au-input--full" type="password" name="new_password1" id="id_new_password1" placeholder="New Password" required>
</div>
<div class="form-group">
<label>New Password</label>
<input class="au-input au-input--full" type="password" name="new_password2" id="id_new_password2" placeholder="New Password" required>
</div>
<button class="au-btn au-btn--block au-btn--green m-b-20" type="submit">Change Password</button>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
The form already has the errors in it's instance. For some reason people use the message framework for showing errors which is in fact more difficult than simply using the form in the template. The view passes the form instance to your template so you can use it to render the form and render it's errors. Try this in your template:
To render non-field errors:
{% for error in form.non_field_errors %}
{{ error }}
{% endfor %}
To render field errors use form.field_name.errors:
{% for error in form.new_password1.errors %}
{{ error }}
{% endfor %}
As a note Rendering the form manually (by writing the tags yourself <input ....>) increases the difficulty of making forms for no good reason. Perhaps one might not like using the default rendered forms but there are ways to customize that in the form's class or using some package. See django-widget-tweaks and django-crispy-forms two great packages to customize form rendering.
I was able to solve the problem by following the previous answer. I added the error tags in the HTML which made it work perfectly and displayed the error nicely using some styles.
{% for error in form.old_password.errors %}
<div class="alert alert-danger with-close alert-dismissible fade show">
{{error}}
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
{% endfor %}
{% for error in form.new_password1.errors %}
<div class="alert alert-danger with-close alert-dismissible fade show">
{{error}}
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
{% endfor %}
{% for error in form.new_password2.errors %}
<div class="alert alert-danger with-close alert-dismissible fade show">
{{error}}
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
{% endfor %}
<div class="login-form">
<form method="POST">
{% csrf_token %}
<div class="form-group">
<label>Current Password</label>
<input class="au-input au-input--full" type="password" name="old_password" id="id_old_password" placeholder="Current Password" required>
</div>
<div class="form-group">
<label>New Password</label>
<input class="au-input au-input--full" type="password" name="new_password1" id="id_new_password1" placeholder="New Password" required>
</div>
<div class="form-group">
<label>New Password</label>
<input class="au-input au-input--full" type="password" name="new_password2" id="id_new_password2" placeholder="New Password" required>
</div>
<button class="au-btn au-btn--block au-btn--green m-b-20" type="submit">Change Password</button>
</form>
</div>
I put an increment with {% if %}, to appear only when there is an error.
{% if form.new_password1.errors %}
{% for error in form.new_password1.errors %}
<div class="alert alert-danger with-close alert-dismissible fade show">
{{error}}
</div>
{% endfor %}
{% endif %}
{% if form.new_password2.errors %}
{% for error in form.new_password2.errors %}
<div class="alert alert-danger with-close alert-dismissible fade show">
{{error}}
</div>
{% endfor %}
{% endif %}

Populating input tags with data from Database

I have a form setup that is able to edit products inside of my database. What I would like to do is have the input fields be populated with the information of the product that a user is trying to edit, instead of having to manually enter in ALL the information (basically being able to highlight the information) I am using Flask along with Jinja2 and WTForms.
Here is my code for the form:
{% extends 'navbar.html' %}
{% block container %}
<link rel="stylesheet" href="{{url_for('static', filename='css/product-edit.css') }}">
<div class="top-pad" style="text-align: center;">
<div class="well">
<div class="row" id="product-form">
<h2 class="col-md-6" style="color: blue">Edit Product</h2>
</div>
<form method="POST" action="{{ url_for('my_view.product_edit', key=category_id) }}" role="form" id="product-form">
<div class="row">
<div class="form-group col-md-6">{{ form.brand.label }}: {{ form.brand() }}</div>
</div>
<div class="row">
<div class="form-group col-md-6">{{ form.name.label }}: {{ form.name() }}</div>
</div>
<div class="row">
<div class="form-group col-md-6">{{ form.price.label }}: {{ form.price() }}</div>
</div>
<div class="row">
<div class="form-group col-md-6">{{ form.rating.label }}: {{ form.rating() }}</div>
</div>
<div class="row">
<div class="form-group col-md-6">
<!-- Category Dropdown -->
<label for="category col-md-6" id="category-select">Categories: </label>
<select name="category" id="category">
{% for category in categories %}
<option value="{{ category[0] }}">{{ category[1] }}</option>
{% endfor %}
</select>
<!-- END Category Dropdown -->
</div>
</div>
<div class="row">
<div class="form-group col-md-6">{{ form.year.label }}: {{ form.year() }}</div>
</div>
<div class="row">
<div class="form-group col-md-6">{{ form.stock.label }}: {{form.stock() }}</div>
</div>
<div class="row">
<div class="form-group col-md-6">{{ form.image.label }}: {{ form.image() }}</div>
</div>
<div class="row">
<div class="col-md-6">
<button type="submit" class="btn btn-success">Submit</button>
</div>
</div>
</form>
</div>
</div>
I'm not even sure I am stating my question properly, please let me know if I need to clarify more. I will try my best.

Django include template tag in for loop only catches first iteration

I have a comments section on some pages on my site that I build with a {% for ... %} loop (and another nested loop for comment replies. The section was hacked together, and I am still learning web development and Django, so please forgive any frustrating sloppiness or weirdness. I am not concerned with efficiency at the moment, only efficacy, and right now it is not working quite right.
For each comment I have a Bootstrap dropdown button that will bring up the options Edit and Delete. Edit will open a modal to edit the comment. The modals are rendered with an {% include %} tag. Below I have included part of my code unmodified, rather than trying to simplify my example and risk leaving something crucial out:
<div class="panel panel-default">
{% for comment in spot.ordered_comments %}
<div class="panel-heading row">
<div class="col-sm-10">
<strong>{{ comment.poster.username }}</strong>
<em style="margin-left: 2em">{{ comment.created|date:'M d \'y \a\t H:i' }}</em>
</div>
<div class="btn-group col-sm-2" role="group">
{% if comment.poster == user %}
<form id="delete-comment-form" class="form"
method="post" action="{% url 'delete_comment' spot.id comment.id %}">
{% csrf_token %}
</form>
{% include 'topspots/editmodal.html' with edit_type='comment' %}
<div class="btn-group">
<button type="button" class="btn btn-default dropdown-toggle"
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<i class="fa fa-edit"></i> <span class="caret"></span>
</button>
<ul class="dropdown-menu">
<li>Edit</li>
<li role="separator" class="divider"></li>
<li>
Delete
</li>
</ul>
</div>
{% endif %}
{% if user.is_authenticated %}
{% include 'topspots/replymodal.html' %}
<button type="button" class="btn btn-default" data-toggle="modal"
data-target="#replyModal">
Reply
</button>
{% endif %}
</div>
</div>
<div class="panel-body">
<div class ="row">
<div class="col-sm-8">
{{ comment.comment_text }}
</div>
</div>
<br/>
<!-- Comment replies -->
{% if comment.commentreply_set %}
{% for reply in comment.commentreply_set.all %}
<div class="row" style="padding-left: 1em">
<div class="col-sm-8 well">
<p>{{ reply.reply_text }}</p>
<div class="row">
<div class="col-sm-4">
<p>
<strong>{{ reply.poster.username }}</strong>
<em style="margin-left: 2em">{{ comment.created|date:'M d \'y \a\t H:i' }}</em>
</p>
</div>
{% if reply.poster == user %}
{% include 'topspots/editmodal.html' with edit_type='reply' %}
<form id="delete-reply-form" class="form"
method="post" action="{% url 'delete_reply' spot.id reply.id %}">
{% csrf_token %}
</form>
<div class="col-sm-2">
<div class="btn-group">
<button type="button" class="btn btn-default dropdown-toggle"
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<i class="fa fa-edit"></i> <span class="caret"></span>
</button>
<ul class="dropdown-menu">
<li><a href="#" data-toggle="modal"
data-target="#editModal">Edit</a></li>
<li role="separator" class="divider"></li>
<li>
<a href="javascript:;"
onclick="$('#delete-reply-form').submit();">Delete</a>
</li>
</ul>
</div>
</div>
{% endif %}
</div>
</div>
</div>
{% endfor %}
{% endif %}
</div>
{% endfor %}
</div>
Here is the edit modal:
<!-- editmodal.html -->
{% load static %}
<div class="modal fade" id="editModal" tabindex="-1" role="dialog" aria-labelledby="editModalLabel">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span></button>
<h2 class="modal-title" id="editModalLabel">
Edit {{ edit_type }}:
</h2>
</div>
<form action="{% url 'edit_comment' spot.id comment.id %}" method="post">
<div class="modal-body">
<input class="form-control" name="text" value="{{ comment.comment_text }}" autofocus>
<input type="hidden" name="edit_type" value="{{ edit_type }}">
{% csrf_token %}
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-default">Finish editing</button>
</div>
</form>
</div>
</div>
</div>
<script>
$('.modal').on('shown.bs.modal', function() {
$(this).find('[autofocus]').focus();
});
</script>
and the reply modal:
<!-- replymodal.html -->
{% load static %}
<div class="modal fade" id="replyModal" tabindex="-1" role="dialog" aria-labelledby="replyModalLabel">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span></button>
<h2 class="modal-title" id="replyModaLabel">
Reply to <strong>{{ comment.poster.username }}'s</strong> comment
</h2>
</div>
<div class="modal-body">
<form action="{% url 'reply_comment' spot.id comment.id %}" method="post">
<input class="form-control" name="reply_text" placeholder="Write a reply..." autofocus>
{% csrf_token %}
</form>
</div>
</div>
</div>
</div>
<script>
$('.modal').on('shown.bs.modal', function() {
$(this).find('[autofocus]').focus();
});
</script>
The issue I am having is that my reply and edit modals (e.g. {% include 'topspots/editmodal.html' with edit_type='reply' %} or {% include 'topspots/replymodal.html' %} seem to be only rendered once with the context of the first iteration of my for loop. So even though all the questions are correctly rendered on the page, when I click reply, edit or delete, regardless of which button I click (i.e., whether I click the button for the first comment, or the fifth comment, etc.) I can only reply to, edit, or delete the very first comment. I have a feeling that this has something to do with closures and scope in a way I am not quite understanding (I have gotten into trouble in the past with unexpected results using lambda in Python loops because of this or this), but I am not sure.
I did a test with the following view:
def test(request):
spots = Spot.objects.all()
return render(request, 'test.html', {'spots': spots})
and templates:
<!-- test.html -->
<h1>Hello world</h1>
{% for spot in spots %}
{% include 'testinclude.html' %}
{% endfor %}
and
<!-- testinclude.html -->
<h3>{{ spot.name }}</h3>
And it printed out a list of unique spot names, so why the difference with the modals?
As emulbreh postulates, a modal is in fact rendered for every comment. However, all of the modals have the same ID, so regardless of which comment’s edit button was clicked, the first modal gets triggered every time. IDs are supposed to be unique across an HTML document.
How can you fix this? You can make the IDs of the modals unique to each comment. You can get a unique identifier by writing id="editModal-{{ comment.id }}" or just id="editModal-{{ forloop.counter }} (documentation here).
But then your editModal.html template is coupled very tightly with your ‘master’ template. A better solution would be to use classes instead of IDs and put the identification where it belongs: the container of each comment. You can try:
adding an ID to each comment’s container:
<div class="panel panel-default">
{% for comment in spot.ordered_comments %}
<div class="panel-heading row" id="comment-{{ comment.id }}">
...
using classes instead of IDs in your modal templates as so:
<!-- editmodal.html -->
{% load static %}
<div class="modal fade editModal" tabindex="-1" ...>
...
changing data-target in your buttons from:
<li>Edit</li>
to:
<li>Edit</li>
It looks like all your edit modals will have the same id id="editModal" as well as your reply modals id="replyModal" if you are showing them based on id probably you will always open the first DOM element with that id. You could try appending a unique identifier like forloop.counter
https://docs.djangoproject.com/en/1.9/ref/templates/builtins/#for

Django form input field styling

I have redefined form for contact us page, It's standard django-form stuff, but I'm struggling to understand how can I write description inside <inpout> field.
To be precise I want to write Name inside <input> field, so how can I do this. I define <input> field like {{ form.name }}, so how can I define it more like <input type="name" class="form-control" id="id_name" placeholder="Your Name">.
<div class="col-xs-12 col-sm-12 col-md-4 col-md-offset-2 col-lg-4">
{% if form.errors %}
<p style="color: red">
Please correct the error{{ form.errors|pluralize }} below.
</p>
{% endif %}
<form class="form-horizontal" action="." method="POST">
{% csrf_token %}
<div class="field form-group">
{{ form.name.errors }}
<label for="id_name" class="control-label"></label>
<div class="col-sm-10">
{{form.name}}
</div>
</div>
<div class="field form-group">
{{ form.email.errors }}
<label for="id_email" class="control-label"></label>
<div class="col-sm-10">
{{ form.email }}
</div>
</div>
<div class="field form-group">
{{ form.phone_number.errors }}
<label for="id_phone_number" class="control-label"></label>
<div class="col-sm-10">
{{ form.phone_number }}
</div>
</div>
<div class="field form-group">
{{ form.message.errors }}
<label for="id_message" class="control-label"></label>
<div class="col-sm-10">
{{ form.message }}
</div>
</div>
<div class="form-group">
<div class="col-sm-12">
<input type="submit" class="btn btn-primary btn-block" value="Submit"></button>
</div>
</div>
</form>
</div><!--/end form colon -->
If you want to modify the placeholder text, or other values of the field Django creates, it can be done in the form code using the widget's attrs:
class MyForm(forms.Form):
name = forms.CharField(
widget=forms.TextInput(
attrs={
'class': 'my-class',
'placeholder': 'Name goes here',
}))
If your intention is to keep all of the code in the template you will have to manually create each input field instead of using the ones Django renders. You can still access the values of the generated field in the template to help you do that though.
<input name="{{ form.name.name }}" type="text" placeholder="Name field">

Categories

Resources