Customized django all-auth form not submitting - django

I am using the django all-auth login form. I wanted to customize the look of the form fields so I changed login.html within the account folder to look like this:
<form class="login" method="POST" action="{% url 'account_login' %}">
{% csrf_token %}
{% for field in form.visible_fields|slice:'2' %}
<div class="row form-group">
{% if field.name == 'login' %}
<input type="text" placeholder="Email"><i class="fas fa-at"></i>
{% else %}
<input type="password" placeholder="Password"><i class="la la-lock"></i>
{% endif %}
</div>
{% endfor %}
Forgot Password?
<button type="submit">Sign In</button>
</form>
The form renders exactly how I would like it to, however nothing happens when I click on submit. What is strange to me is that the form submits perfectly fine if in place of my for loop I simply type {{ form.as_p }}, it just doesn't look how I want. Can anyone see an error in my loop, or is there something else wrong here. I have been looking for a solution online but so far been unsuccessful

You need to specify the names of the fields in your input tags otherwise the POST dictionary will be empty. You are using {% if field.name == 'login' %} but you forgot to specify the name attribute. Same applies for the password input.
<form class="login" method="POST" action="{% url 'account_login' %}">
{% csrf_token %}
{% for field in form.visible_fields|slice:'2' %}
<div class="row form-group">
{% if field.name == 'login' %}
<input name='login' type="text" placeholder="Email"><i class="fas fa-at"></i>
{% else %}
<input name='password' type="password" placeholder="Password"><i class="la la-lock"></i>
{% endif %}
</div>
{% endfor %}
Forgot Password?
<button type="submit">Sign In</button>
</form>

Related

Django Allauth Customized Login Template Not Working

I have customized the login template of allauth with bootstrap styles and widget_tweaks. When I try logging in with that template, It doesn't redirect me to the home page but remains in the same login.html template. However, when I log in with the original template from allauth in /account/login.html/ everything works well and it redirects me to my homepage. There is something that I'm not customizing right in my custom login.html template.
Below is django-allauth login.html and my custom login.html
django-allauth login.html
{% extends "account/base.html" %}
{% load i18n %}
{% load account socialaccount %}
{% block head_title %}{% trans "Sign In" %}{% endblock %}
{% block content %}
<h1>{% trans "Sign In" %}</h1>
{% get_providers as socialaccount_providers %}
{% if socialaccount_providers %}
<p>{% blocktrans with site.name as site_name %}Please sign in with one
of your existing third party accounts. Or, sign up
for a {{ site_name }} account and sign in below:{% endblocktrans %}</p>
<div class="socialaccount_ballot">
<ul class="socialaccount_providers">
{% include "socialaccount/snippets/provider_list.html" with process="login" %}
</ul>
<div class="login-or">{% trans 'or' %}</div>
</div>
{% include "socialaccount/snippets/login_extra.html" %}
{% else %}
<p>{% blocktrans %}If you have not created an account yet, then please
sign up first.{% endblocktrans %}</p>
{% endif %}
<form class="login" method="POST" action="{% url 'account_login' %}">
{% csrf_token %}
{{ form.as_p }}
{% if redirect_field_value %}
<input type="hidden" name="{{ redirect_field_name }}" value="{{ redirect_field_value }}" />
{% endif %}
<a class="button secondaryAction" href="{% url 'account_reset_password' %}">{% trans "Forgot Password?" %}</a>
<button class="primaryAction" type="submit">{% trans "Sign In" %}</button>
</form>
{% endblock %}
my custom login.html
{% comment %}
{% extends "layouts/base-fullscreen.html" %}
{% load i18n %}
{% block title %} Login {% endblock %}
{% load widget_tweaks %}
{% block content %}
<div class="auth-wrapper">
<div class="auth-content">
<div class="auth-bg">
<span class="r"></span>
<span class="r s"></span>
<span class="r s"></span>
<span class="r"></span>
</div>
<div class="card">
<div class="card-body text-center">
<div class="mb-4">
<i class="feather icon-unlock auth-icon"></i>
</div>
<h3 class="mb-4">Login</h3>
<span class="mb-0 text-muted">
{% if msg %}
{{ msg | safe }}
{% else %}
Add your credentials
{% endif %}
</span>
<br />
<br />
<form method="post" action="{% url 'account_login' %}">
{% csrf_token %}
<div class="md-form mb-2">
{% render_field form.login class="form-control" placeholder=form.login.label %}
</div>
<span class="text-error">{{ form.login.errors }}</span>
<div class="md-form mb-2">
{% render_field form.password class="form-control" placeholder=form.password.label %}
</div>
<span class="text-error">{{ form.password.errors }}</span>
<p class="mb-0 text-muted"><a class="button secondaryAction" href="{% url 'account_reset_password' %}">Forgot password?</a>
</p>
<div class="form-group text-left">
<div class="checkbox checkbox-fill d-inline">
<!-- <input type="checkbox" name="checkbox-fill-1" id="checkbox-fill-a1" checked=""> -->
{% render_field form.remember class="form-control" placeholder=form.remember.label type="checkbox"%}
<label for="id_remember" class="cr"> Remember me</label>
</div>
</div>
{% if redirect_field_value %}
<input type="hidden" name="{{ redirect_field_name }}" value="{{ redirect_field_value }}" />
{% endif %}
<button type="submit" name="login" class="btn btn-primary shadow-2 mb-4">Login</button>
</form>
<p class="mb-0 text-muted">Don’t have an account? <a href="{% url 'account_signup' %}" >Signup</a></p>
<br />
</div>
</div>
</div>
</div>
{% endblock content %}
allauth settings in settings.py
LOGIN_REDIRECT_URL = '/'
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
SITE_ID = 1
ACCOUNT_LOGOUT_REDIRECT_URL = '/' #couterpart to Django's LOGIN_REDIRECT_URL
ACCOUNT_LOGOUT_REDIRECT = '/'
ACCOUNT_USERNAME_REQUIRED = False
ACCOUNT_AUTHENTICATION_METHOD = 'email'
ACCOUNT_EMAIL_REQUIRED = True
ACCOUNT_UNIQUE_EMAIL = True
ACCOUNT_EMAIL_VERIFICATION = 'optional'
The other change I've made is to customize the allauth signup form to take extra two fields (first_name and last_name). That one works fine and redirects to the login url
you might be getting an error from the form validator. keep the original form on the page to check if its giving any errors. copy the {{ form.as_p }} from the original page 'accounts/login.html' and paste it in your custom template. if there are any errors, it'll display it.
this right here is your problem
{% extends "account/base.html" %}
If you have all the boostrap, jquery and widget_tweaks in your local base.html, then thats what you need to extend. The default accounts/base.html provided by django-allauth, does not come customized with bootstrap.
Use:
{% extends "base.html" %} instead

Django hiding an item if object == None

In my template i'm trying to hide a paypal button if the email item is None.
{% if object.email == None %}
<h1>Nothing here </h1>
{% else %}
<form action="https://www.paypal.com/cgi-bin/webscr" method="post" target="_top">
<input type="hidden" name="business" value="{{ object.email }}">
</form>
{% endif %}
After testing by not entering the email in my form, the button still shows and the 'Nothing here' is not showing.
Try this
{% if not object.email %}
<h1>Nothing here </h1>
{% else %}
<form action="https://www.paypal.com/cgi-bin/webscr" method="post" target="_top">
<input type="hidden" name="business" value="{{ object.email }}">
</form>
{% endif %}

Django login not showing errors

I know there are multiple questions like this around, but none of them contain a clear answer. I am using the default authentication from Django, but have trouble displaying something like 'Your username/password combination is incorrect'. Is it possible to fix this without making a custom view function?
My urls.py looks like this:
url(r'^login/$', auth_views.login, {'template_name': 'login.html'},
name='mysite_login')
Then my login.html has the following code:
{% block content %}
<section class="content">
<div class="container block">
<div class="row">
<div class="col-md-12"></div>
<form action="{% url 'mysite_login' %}" class="form-control" method="post" accept-charset="utf-8">
{% csrf_token %}
{% for field in form %}
<p>
{{ field.label_tag }}<br>
{{ field|addcss:'form-control' }}
{% if field.help_text %}
<small style="color: grey">{{ field.help_text|safe }}</small>
{% endif %}
{% for error in field.errors %}
<p style="color: red">{{ error }}</p>
{% endfor %}
</p>
{% endfor %}
<button type="submit" class="btn btn-dark">Login</button>
<input class="form-control" type="hidden" name="next" value="{{ next }}"><br>
</form>
</div>
</div>
</div>
</section>
{% endblock %}
So this all works, except for displaying the error messages. I've seen answers where you can write a custom view function and form to fix this, but I assume it should be also possible while using the build-in login functionality right? Thanks a lot.
The built-in login form doesn't display errors at an individual field level; it's a security risk to say that just the password is wrong, because it confirms the existence of a particular username. So the errors are raised in the general clean() method and are displayed in the template via {{ form.non_field_errors }}.

django delete model entry from selected form option

I have the following form displaying entries of a model for user settings. When selected, I would like that a button catches its pk and send it to a Delete view.Here is the current code but I am missing this part.
user_detail template html
<form id="SettingsListForm"><label>&nbsp Settings List : &nbsp &nbsp &nbsp</label>
{% if user.usersetting.first %}
<select class="form-control" name="settingslist" id = "settingslist" form="SettingsListForm" >
{% for settings in user.usersetting.all %}
<option value="{{ settings.file.url }}">{{ settings }}
</option>
{% endfor %}
</select>
{% else %}
<li class="list-group-item">NO SETTINGS YET</li>
{% endif %}
<button class="btn btn-outline-light btn-circle"><i class="glyphicon glyphicon-minus" href="{% url 'my_app:setting_delete' pk=user.usersetting.last.id %}"></i></button>
{% block delete_setting_confirm_block %}
{% endblock %}
</form>
setting_confirm_delete html template with delete_setting_confirm_block
{% extends 'login_app/user_detail.html' %}
{% block delete_setting_confirm_block %}
<h4>
ARE YOU <b>REALLY</b> SURE YOU WANT TO <b>DELETE</b> THIS SETTING ?
<form method="POST">
{% csrf_token %}
<button type="submit" class="btn btn-outline-light btn-danger" value="Delete">YES</button>
<a class="btn btn-outline-light btn-default" href="{% url 'login_app:user_detail' pk=user.id %}"><b>NO</b></a>
</form>
</h4>
{% endblock %}
my_app urls
url(r'^setting/(?P<pk>\d+)/$',views.UserSettingDeleteView.as_view(),name='setting_delete'),
UserSettingDeleteView in my_app views
class UserSettingDeleteView(DeleteView):
model = models.UserSetting
template_name = 'my_app/setting_confirm_delete.html'
def get_success_url(self):
return reverse('my_app:user_detail', kwargs={'pk': self.object.user.pk})
Somehow, a similar technique works fine when using listgroups:
working sample in user_detail html
<ul class="list-group">
{% if user.userdata.first %}
{% for data in user.userdata.all %}
<li class="list-group-item">{{ data }}<a class="btn btn-outline-light btn-circle" href="{% url 'my_app:data_delete' pk=data.pk %}"><i class="glyphicon glyphicon-remove"></i></a></i></li>
{% endfor %}
{% block delete_data_confirm_block %}
{% endblock %}
{% else %}
<li class="list-group-item">NOTHING RECORDED YET</li>
{% endif %}
</ul>
In your template.html, you should create a form for deletion, like this:
<form action="{% url 'my_app:setting_delete' pk=user.usersetting.last.id %}" method="post">
{% csrf_token %}
<input type="submit" value="Delete" class="btn btn-outline-light btn-circle">
</form>
Because in HTML you can not send directly PUT or DELETE, you should fake it via a POST request. It will be useful to read this, it is explained well.
Your UserSettingDeleteView can be as simple as that:
from django.views.generic.edit import DeleteView
from django.urls import reverse_lazy
class UserSettingDeleteView(DeleteView):
model = MyModel
# Replace with the model you want to delete (User)
success_url = reverse_lazy('my_app:setting_list')
# After deletion, possibly you will want to redirect the user to the list view
The built-in DeleteView cares itself to find your model by the pk parameter you pass through your url and delete it, you just have to configure the model and success_url fields.
Now if you click on your Delete button, you should expect your desired entry to be deleted and the user to be redirected to the list view.
EDIT:
I forgot that you want to get this entry via options. Here you will have to use some JavaScript in order to find the currently selected element and send it's pk to your DeleteView.
At first, add id's to your option tags, like this:
<select class="form-control" name="settingslist" id="settingslist" form="SettingsListForm">
{% for settings in user.usersetting.all %}
<option value="{{ settings.file.url }}" id="{{ settings.id }}">{{ settings }}</option>
{% endfor %}
</select>
And then add some jQuery:
var settingId = $('#SettingsListName').find(":selected").attr('id');
In the end, you need to send settingId to the corresponding url, but I am not very familiar with JavaScript.
Try putting a hidden input in your form. Right now, nothing is passing through the form.
<input type="hidden" name="del_setting" value="{{user.usersetting.last.id}}">
So your form would look like this
<form method="POST">
{% csrf_token %}
<input type="hidden" name="del_setting" value="{{user.usersetting.last.id}}">
<button type="submit" class="btn btn-outline-light btn-danger" value="Delete">YES</button>
<a class="btn btn-outline-light btn-default" href="{% url 'login_app:user_detail' pk=user.id %}"><b>NO</b></a>
</form>
You also probably should move this out of the current form in your user detail template so that you're not putting a form within a form:
{% block delete_setting_confirm_block %}
{% endblock %}
None of the previously mentioned solutions would work so I guess the problem is the nested bootstrap select item which is supposed to display the pk of the setting.
For simplicity I then removed the problem by using list-group instead
<ul class="list-group">
{% if user.usersetting.first %}
{% for settings in user.usersetting.all %}
<li class="list-group-item">{{ settings }}<a class="btn btn-outline-light btn-circle" href="{% url 'my_app:setting_delete' pk=settings.pk %}"><i class="glyphicon glyphicon-remove"></i></a></li>
{% endfor %}
<label>Create a new setting...</label>
<a class="btn btn-outline-light btn-circle"><i class="glyphicon glyphicon-plus"></i></a>
{% else %}
<li class="list-group-item">Create a new setting...<a class="btn btn-outline-light btn-circle"><i class="glyphicon glyphicon-plus"></i></a></li>
{% endif %}
{% block delete_setting_confirm_block %}
{% endblock %}
</ul>
As a workaround,this works well.

getting distinct values from inputs that share the same name

I have this form in my template:
<form method="POST" class="form" action="/groups/">
{% csrf_token %}
{% block hidden_debtors %}
{% for name, email in debtor_info.items %}
<input type="hidden" name="hidden-debtor" value="{{email}}">
{% endfor %}
{% endblock %}
<input type="text" name="new-debtor" id="round-input" placeholder="Select Debtor(s)"></input>
<button type="submit" name="add-debtor" class="btn btn-primary">Add Debtor</button>
</form>
As you can see the hidden type inputs all share the name "hidden-debtor" however they each have distinct email values. I was wondering how I would be able to access each one of these distinct values in my views.py through a loop or something
Thanks!
You can get a list of values in your view like this:
request.POST.getlist('hidden-debtor')
Documentation