Django form not rendered by auth_views.LoginView - django

I have a problem that is that Django is not rendering one of the fields of my Login form. I'm using the auth_views.LoginView view for user authentication, and even if I put my template, one of the fields does not appear in my html.
Url.py:
from django.urls import path, re_path
from django.contrib.auth import views as auth_views
from Turnos import views
urlpatterns = [
path('', views.home, name='home'),
with views.login view it works perfectly
#path('login/', views.login, name='login'),
with auth_views.LoginView.as_view(template_name='login.html') doesn't render the email field
path('login/', auth_views.LoginView.as_view(template_name='login.html'), name='login'),
]
views.py:
from django.shortcuts import render, redirect
from django.contrib.auth.models import User
from django.contrib.auth import login as auth_login
from Turnos.forms import loginForm
def login(request):
if request.method == 'POST':
form = loginForm(request.POST)
if form.is_valid():
user = form.save()
auth_login(request, user)
return redirect('nuevoTurno.html')
else:
form = loginForm()
return render(request, 'login.html', {'form': form})
forms.py:
from django import forms
from django.contrib.auth.models import User
class loginForm(forms.ModelForm):
email = forms.EmailField(required=True, widget=forms.EmailInput())
password = forms.CharField(widget=forms.PasswordInput())
class Meta:
model = User
fields = ['email', 'password']
Html:
<form action="/login/" method="post" novalidate>
{% csrf_token %}
<div class="form-group">
<label for="{{ form.email.label }}" class="">Email</label>
{% render_field form.email class+="form_control form-control-lg" placeholder="Email" %}
</div>
<div class="form-group">
<label for="{{ form.password.label }}" class="">Password</label>
{% render_field form.password placeholder="Password" class+="form_control form-control-lg" %}
</div>
<div class="form-group">
<button type="submit" class="btn btn-outline-light btn-block">
Enviar
</button>
</div>
<div class="form-group">
Lost password?
</div>
</form>
the email field is not displayed with auth_views.loginview
sorry for my English.

It looks like you're using a third part plugin to render individual form fields (I assume you have used {% load widget_tweaks %} in your base.html template.
Perhaps try:
<form action="/your-name/" method="post">
{% csrf_token %}
{{ form }}
<input type="submit" value="Submit">
</form>
...or...
{% for field in form %}
<div class="fieldWrapper">
{{ field.errors }}
{{ field.label_tag }} {{ field }}
</div>
{% endfor %}
Or even...
{{ form.non_field_errors }}
<div class="form-group">
{{ form.email.errors }}
<label for="{{ form.email.id_for_label }}">Email</label>
{{ form.email }}
</div>
If the above doesn't work, then it is time to debug why email isn't pulling through. Not sure if it's an ordering thing (unlikely):
email = forms.EmailField(widget=forms.EmailInput(), attrs={'class': "form_control form-control-lg", 'placeholder': "Email"}, required=True, )
^ I've also added the Django way of passing in attributes to your form fields.

Related

How do I use Django generic updateviews to update my model using individual form field values?

models.py:
from django.db import models
class Location(models.Model):
name = models.CharField(max_length=20)
is_source = models.BooleanField(default=False)
is_destination = models.BooleanField(default=False)
def __str__(self):
return self.name
views.py
from django.shortcuts import render
from django.urls import reverse_lazy
from django.views import generic
from .models import Location
class LocationsListView(generic.ListView):
model = Location
template_name = 'locations/list.html'
context_object_name = 'locations'
class LocationUpdateView(generic.edit.UpdateView):
model = Location
fields = ['name', 'is_source', 'is_destination']
context_object_name = 'location'
template_name = 'locations/update.html'
success_url = reverse_lazy('locations:list')
class LocationDeleteView (generic.edit.DeleteView):
model = Location
template_name = 'locations/confirm_delete.html'
context_object_name = 'location'
success_url = reverse_lazy('locations:list')
locations/update.html
{% extends 'base.html' %}
{% block title %}Location Update{% endblock %}
{% block content %}
<section>
<div class="container">
<h1>Location Update</h1>
<div class="form-container">
<form method="post">
{% csrf_token %}
{% if form.errors %}
<div class="p-3 mb-3 border border-danger border-3 rounded">{{ form.errors }}</div>
{% endif %}
<div class="mb-3">
<label for="" class="form-label">Name</label>
<input type="text" class="form-control" value="{{ form.name.value }}">
</div>
<div class="mb-3">
<input type="checkbox" class="form-check-input" {% if form.is_source.value %} checked {% endif %}>
<label for="">Source</label>
</div>
<div class="mb-3">
<input type="checkbox" class="form-check-input" {% if form.is_destination.value %} checked {% endif %}>
<label for="">Destination</label>
</div>
<input type="submit" class="btn btn-success mb-3" value="Save">
</form>
</div>
</div>
</section>
{% endblock %}
locations.urls.py
from django.urls import path
from . import views
app_name = 'locations'
urlpatterns = [
path('', views.LocationsListView.as_view(), name='list'),
path('update/<int:pk>/', views.LocationUpdateView.as_view(), name='update'),
path('delete/<int:pk>/', views.LocationDeleteView.as_view(), name='delete'),
]
When I try to update my model, individually rendering the form fields using {{form.name.value}}, I get an error that my name field is required, and yet it is filled. I do not get the error if I render the form as a whole using {{form.as_p}} for example. What am I doing wrong?
I tried using {{form.as_p}} and it worked. But I need individual field rendering so I can style my form.
You need to provide the name attribute for each of your field <input> tags. The field's html_name attribute should be used if rendering manually
<input name="{{ form.name.html_name }}" type="text" class="form-control" value="{{ form.name.value }}">

How to retain two forms data in the same view/template/page?

I have two forms and two views using the same profile.html template. When I GET/POST to the ProfileUpdateView, all of the users profile data is present. However, when I post to UserDeleteView and not select the "accountActivation" box the page renders but the user profile data which is above is empty.
# urls.py
from django.contrib import admin
from django.urls import include, path
from apps.iam.views import ProfileUpdateView, UserDeleteView
urlpatterns = [
path("accounts/profile", ProfileUpdateView, name="profile_detailupdate"),
path("accounts/delete", UserDeleteView, name="user_delete"),
]
# views.py
import zoneinfo
from django.contrib.auth import get_user_model
from django.contrib.auth import logout as auth_logout
from django.contrib.auth.decorators import login_required
from django.shortcuts import HttpResponseRedirect, get_object_or_404, render
from django.utils import timezone
from django.views.decorators.http import require_http_methods
from django.views.generic import TemplateView, UpdateView
from .forms import ProfileForm
from .models import Profile
User = get_user_model()
# Homepage
class HomeDetailView(TemplateView):
template_name = "home.html"
# Profile
## Update
#login_required
#require_http_methods(["GET","POST"])
def ProfileUpdateView(request):
# dictionary for initial data with field names as keys
context = {}
# fetch the object related to passed id
profile_object = get_object_or_404(Profile, id=request.user.id)
# pass the object as instance in form
profile_form = ProfileForm(request.POST or None, instance=profile_object)
# save the data from the form
if profile_form.is_valid():
profile_form.save()
# add form dictionary to context
context["profile_form"] = profile_form
# activate the new timezone in case changed
request.session["django_timezone"] = request.user.profile.timezone
timezone.activate(zoneinfo.ZoneInfo(request.user.profile.timezone))
return render(request, "profile.html", context)
## Delete
#login_required
#require_http_methods(["POST"])
def UserDeleteView(request):
# dictionary for initial data with field names as keys
context = {}
# fetch the object related to passed id
user_object = get_object_or_404(Profile, id=request.user.id)
# pass the object as instance in form
userdelete_form = ProfileForm(request.POST or None, instance=user_object)
# add form dictionary to context
context["userdelete_form"] = userdelete_form
# user verified account deletion
if request.POST.get("accountActivation") == "on":
User = get_user_model()
user_pk = request.user.pk
auth_logout(request)
User.objects.filter(pk=user_pk).delete()
return render(request, "home.html", context)
else:
return render(request, "profile.html", context)
{% extends 'base.html' %}
{% load static %}
{% load widget_tweaks %}
{% block head_title %} {{ title }} {% endblock %}
{% block body %}
<div class="container-xxl flex-grow-1 container-p-y">
<div class="row">
<div class="col-md-12">
<div class="card mb-4">
<h5 class="card-header">Profile Details</h5>
<!-- Account -->
<div class="card-body">
<div class="d-flex align-items-start align-items-sm-center gap-4">
<img src="{% static 'img/avatars/1.png' %}" alt="user-avatar" class="d-block rounded"
height="100" width="100" id="uploadedAvatar" />
<div class="button-wrapper">
<label for="upload" class="btn btn-primary me-2 mb-4" tabindex="0">
<span class="d-none d-sm-block">Upload new photo</span>
<i class="bx bx-upload d-block d-sm-none"></i>
<input type="file" id="upload" class="account-file-input" hidden
accept="image/png, image/jpeg" />
</label>
<button type="button" class="btn btn-outline-secondary account-image-reset mb-4">
<i class="bx bx-reset d-block d-sm-none"></i>
<span class="d-none d-sm-block">Reset</span>
</button>
<p class="text-muted mb-0">Allowed JPG, GIF or PNG. Max size of 800K</p>
</div>
</div>
</div>
<hr class="my-0" />
<div class="card-body">
<form id="formAccountSettings" method="POST" action="{% url 'profile_detailupdate' %}">
<!-- Security token by Django -->
{% csrf_token %}
<!-- form -->
{% for hidden in profile_form.hidden_fields %}
{{ hidden }}
{% endfor %}
<div class="row">
{% for field in profile_form.visible_fields %}
<div class="mb-3 col-md-6">
<label for="{{ field.id_for_label }}">{{ field.label }}</label>
{% if field.field.widget.input_type == "select" %}
{{ field|add_class:'form-control form-select' }}
{% else %}
{{ field|add_class:'form-control' }}
{% endif %}
{% for error in field.errors %}
<span class="help-block">{{ error }}</span>
{% endfor %}
</div>
{% endfor %}
<div class="mt-2">
<button name="profile" type="submit" class="btn btn-primary me-2">Save changes</button>
<button type="reset" class="btn btn-outline-secondary">Cancel</button>
</div>
</form>
</div>
<!-- /Account -->
</div>
<div class="card">
<h5 class="card-header">Delete Account</h5>
<div class="card-body">
<div class="mb-3 col-12 mb-0">
<div class="alert alert-warning">
<h6 class="alert-heading fw-bold mb-1">Are you sure you want to delete your account?</h6>
<p class="mb-0">Once you delete your account, there is no going back. Please be certain.</p>
</div>
</div>
<form id="formAccountDeactivation" method="POST" action="{% url 'user_delete' %}">
<!-- Security token by Django -->
{% csrf_token %}
<!-- form -->
{% for hidden in deleteuser_form.hidden_fields %}
{{ hidden }}
{% endfor %}
<div class="form-check mb-3">
<input class="form-check-input" type="checkbox" name="accountActivation"
id="accountActivation" />
<label class="form-check-label" for="accountActivation">I confirm my account
deactivation</label>
</div>
<button name="delete" type="submit" class="btn btn-danger deactivate-account">Deactivate Account</button>
</form>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
The issue was in the view which is shared below. I added logic to save the form if valid or read from the database if not. If anyone has suggestions to simply the below that would be great.
"""
file : views.py
reference : https://docs.djangoproject.com/en/4.1/topics/http/views/
https://docs.djangoproject.com/en/4.1/topics/class-based-views/
"""
import re
import zoneinfo
from django.contrib import messages
from django.contrib.auth import get_user_model
from django.contrib.auth import logout as auth_logout
from django.contrib.auth.decorators import login_required
from django.http.response import HttpResponseForbidden, HttpResponseRedirect
from django.shortcuts import HttpResponseRedirect, get_object_or_404, render
from django.utils import timezone
from django.views.decorators.http import require_http_methods
from django.views.generic import TemplateView, UpdateView
from django.views.generic.base import ContextMixin, TemplateResponseMixin
from django.views.generic.edit import ProcessFormView
from .forms import DeleteUserForm, ProfileForm
from .models import Profile
User = get_user_model()
# Homepage
class HomeDetailView(TemplateView):
template_name = "home.html"
# # Profile
#login_required
#require_http_methods(["GET","POST"])
def ProfileUpdateView(request):
context = {}
profile_object = Profile.objects.get(user=request.user.id)
# display profile
if request.method == 'GET':
profile_form = ProfileForm(None, instance=profile_object)
user_form = DeleteUserForm(request.POST)
# update profile or delete account
if request.method == 'POST':
# associate request.POST to form
profile_form = ProfileForm(request.POST, instance=profile_object)
user_form = DeleteUserForm(request.POST)
# profile_form
if 'btn-profile-submit' in request.POST:
# validate form
if profile_form.is_valid():
# valid: update database
profile_form.save()
# activate the new timezone in case changed
request.session["django_timezone"] = request.user.profile.timezone
timezone.activate(zoneinfo.ZoneInfo(request.user.profile.timezone))
messages.error(request, 'Successful profile update.')
else:
# invalid: disgard and read from the database
profile_form = ProfileForm(instance=profile_object)
messages.error(request, 'Failed profile update.')
# user_form
if 'btn-accountdeactivation-submit' in request.POST:
profile_form = ProfileForm(instance=profile_object)
# validate form
if user_form.is_valid():
# valid: delete user from database
cd = user_form.cleaned_data
print(cd.get('accountdeactivation'))
User = get_user_model()
user_pk = request.user.pk
auth_logout(request)
User.objects.filter(pk=user_pk).delete()
messages.error(request, 'Successful account deactivation.')
return render(request, "home.html", context)
else:
# invalid: disgard and warn the user
messages.error(request, 'Failed account deactivation. You must confirm your account deactivation.')
context["profile_form"] = profile_form
context["user_form"] = user_form
return render(request, "profile.html", context)

Django Admin automatically logout after get data from user

I am facing an problems in django admin panel. My django admin panel autumatically logout When any user submitting contact-form. How to stop automatically logout? I am facing this problems after add session in my views.py. here is my code:
#views.py
from django.shortcuts import render,HttpResponseRedirect,redirect
from contact.forms import ContactForm
from contact.models import Contact
from django.views.decorators.csrf import csrf_exempt
from django.urls import reverse
# Create your views here.
#csrf_exempt
def home_view(request,*args,**kwargs):
name = None
obj = None
if request.method == "POST":
contact_form = ContactForm(request.POST)
if contact_form.is_valid():
name = request.POST['name']
email = request.POST['email']
subject = request.POST['subject']
message = request.POST['message']
save_details = Contact(name=name,email=email,subject=subject,message=message)
save_details.save()
request.session['name'] = name
request.session.set_expiry(1) #if I remove this line then it fix the logout problems but not clearing the session after refresh.
return redirect(home_view)
#return render(request, 'index.html',{'message_name':name})
else:
print("not submitted")
else:
contact_form = ContactForm()
return render(request, 'index.html',{'form':contact_form,'message_name':obj})
#urls.py
from django.urls import path
from pages import views
urlpatterns = [
path('', views.home_view, name="home"),
]
root urls.py
from django.contrib import admin
from django.urls import path,include
from pages import urls
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('pages.urls')),
]
#index.html
{% if request.session.name %}
<div class="centerTest">
<h1> Thanks {{ request.session.name }} for your message. We will get back to you very soon</h1>
</div>
{% else %}
<div class="contact__container bd-grid">
<form action="#contact" method = "POST" class="contact__form">
{% for error in form.non_field_errors %}
<div class="alert alert-danger" role="alert">
{{ error }}
</div>
{% endfor %}
<label>Name:</label>
{{ form.errors.name }}
<input type="text" placeholder="Name" name="name" class="contact__input" {% if form.is_bound %}value="{{ form.name.value }} {% endif %}">
<label>Email:</label>
{{ form.errors.email }}
<input type="mail" placeholder="Email" name="email" class="contact__input" {% if form.is_bound %}value="{{ form.email.value }} {% endif %}">
<label>Subject:</label>
{{ form.errors.subject }}
<input type="text" placeholder="optional" name="subject" class="contact__input" {% if form.is_bound %}value="{{ form.subject.value }} {% endif %}">
<label>Message:</label>
{{ form.errors.message }}
<textarea name="message" placeholder="message" id="" cols="0" rows="10" class="contact__input" >{% if form.is_bound %}{{ form.message.value }} {% endif %}</textarea>
<input type="submit" value="Send" class="contact__button button">
{% endif %}
</form>
my django madmin panel autuomatically logout when any user submitting contact-form. How to stop this? anyone please help
I'd avoid using session for this purpose, but if you want to do it, then remove it from the session at the moment when you are about to display the "thank you message"
def home_view(request,*args,**kwargs):
if request.method == "POST":
...
else:
# you are about to display the "thank you message", so remove it from session here
# check if name is in session
if 'name' in request.session:
# not sure from top of my head if session allows `pop`, if not then get value first and then remove it
thanks_name = request.session.pop('name')
else:
thanks_name = None
contact_form = ContactForm()
return render(request, 'index.html',{'form':contact_form,'message_name':obj, 'thanks_name': thanks_name})
how to do it without using session? Use Django Messages which is built exactly for such use-cases. First you Add Message in view, and then you display it in template:
from django.contrib import messages
if request.method == "POST":
messages.add_message(request, messages.INFO, 'Thanks for your message. We will get back to you very soon')
template:
{% if messages %}
<ul class="messages">
{% for message in messages %}
<li{% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
also why do you use #csrf_extempt? Add {% csrf_token %} into your form instead.

Flask/WTForms - how can I make a form inline?

Here is the code:
<form class="form-inline" action="" method="post">
{{ form.hidden_tag() }}
<fieldset class="form-group">
<legend class="border-bottom mb-4"></legend>
<div class="form-group">
... form fields here ...
</div>
</fieldset>
<div class="form-group-submit">
{{ form.submit(class="btn btn-outline-primary") }}
</div>
</form>
I am not sure how to make this field inline...bootstrap docs say to set class to .form-inline but that is not working here
In the following example, I will show you the use of form-inline to align fields horizontally:
Suppose we have a form login_form, which is used in the view function login, that in turn renders the HTML file login.html
The form model:
class login_form(FlaskForm):
some_hiden_field = HiddenField()
username = StringField('User Name :', validators=[DataRequired()])
password = PasswordField('Password :', validators=[DataRequired()])
submit_btn = SubmitField('Submit')
The view function:
#app.route('/', methods=['Get', 'post'])
def login():
# some code
my_form = login_form()
# some code
return render_template('login.html', form=my_form)
login.html:
{% extends "mybase.html" %}
{% import "bootstrap/wtf.html" as wtf %}
{% block page_content %}
<form class="form-inline" method="POST">
{{ form.hidden_tag() }}
<div class="form-group">
{{ form.username.label }} {{ form.username(class="form-control") }}
</div>
<div class="form-group">
{{ form.password.label }} {{ form.password(class="form-control") }}
</div>
<div class="form-group">
{{ form.submit_btn(class="btn btn-default") }}
</div>
</form>
{% endblock %}
Finnally, as you know, in the above HTML code if you replace <form class="form-inline" method="POST"> with <form method="POST"> you will get the vertical alignment style.
I will add more clarification based on the comments below.
import Flask-Bootstrap
import Flask-WTF
Take them copy and paste
Imports collection
from flask import Flask, render_template, session, redirect, url_for, flash, request
from flask_bootstrap import Bootstrap
from flask_wtf import FlaskForm
import wtforms
from wtforms import StringField, FloatField, SubmitField, IntegerField, TextAreaField, DateField, DateTimeField, PasswordField, BooleanField, SelectField, FileField, HiddenField, Field, FieldList, FormField, Form
from wtforms.validators import Optional, NumberRange, DataRequired, Length, Email, Regexp

Django Authentication (Custom Login Page)

Im trying to write my own django login page. Eveything is ok up to the point where I try to login and I just get redirected back to the main login view.
TEMPLATE
{% extends "bdayremind-maininput.html" %}
{% block main %}
<form class="form-horizontal" name="LoginForm" action="/login/" method="post">
{% csrf_token %}
{% if next %}
<input type="hidden" name="next" value="{{ next }}" />
{% endif %}
<div class="control-group">
<label class="control-label" for="username">Username</label>
<div class="controls">
<input type="text" id="username" value="{{username}}" placeholder="Username">
</div>
</div>
<div class="control-group">
<label class="control-label" for="password">Password</label>
<div class="controls">
<input type="password" name="password" id="password" placeholder="Password">
</div>
</div>
<div class="control-group">
<div class="controls">
<button type="submit" class="btn">Login</button>
</div>
</div>
</form>
{% endblock %}
URLS
urlpatterns = patterns('',
url(r'^bdayremind_maininput/$', 'birthdayreminder.views.main'),
# login / logout
(r'^login/$', 'birthdayreminder.views.login_user'),
#(r'^logout/$', logout_page),
)
VIEWS
import datetime
from django.http import *
from django.shortcuts import render_to_response
from django.template import RequestContext
from birthdayreminder.models import *
from django.contrib.auth.decorators import login_required
from django.contrib.auth import authenticate, login
def login_user(request):
username = password = ''
if request.POST:
username = request.POST.get('username')
password = request.POST.get('password')
user = authenticate(username=username, password=password)
if user is not None:
if user.is_active:
login(request, user)
return HttpResponseRedirect('birthdayreminder.views.main')
return render_to_response('login.html',{'username': username}, context_instance=RequestContext(request))
#login_required(login_url='/login/')
def main(request):
........
Any Ideas ?
You forgot to add redirect to the desired page after login.