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
Related
I can't seem to get my delete, edit and add review functionality working. The errors come as soon as I try to navigate to the urls I have set up. When I try and add a new review using my link on the reviews page I get the below message:
TemplateDoesNotExist at /reviews/add
I don't understand why because I have linked the url above to the template, which I have created.
The issue I have with my edit/delete views is that the url it searches for when I click the button is just /edit/ or /delete/ rather than reviews/edit/int:pk or reviews/delete/int:pk as per my urls.
I have pasted my code below, any help would be much appreciated! I have the feeling I am going to kick myself when I realise!
reviews.html:
{% extends "base.html" %}
{% load static %}
{% block content %}
<div class="container-fluid home-container">
<div class="row align-items-center">
<div class="col-sm-12 text-center mt-4">
<h2><strong>Reviews</strong></h2>
</div>
</div>
{% for review in reviews %}
<hr class="hr-1">
<div class="row featurette">
<div class="col-sm-12">
<h2 class="featurette-heading">{{ review.title }}</h2>
<p class="lead">{{ review.content }}</p>
<div class="row justify-content-between mx-1">
<p>By: {{ review.user }}</p>
<p>Created on: {{ review.created }}</p>
<p>Last Updated: {{ review.updated }}</p>
</div>
<!-- Add user authentication if -->
<div class="text-center">
<a href="edit/{{ review.id }}" class="mx-2">
<button class="positive-button mb-2">Edit</button></a>
<a href="delete/{{ review.id }}" class="mx-2 mb-2">
<button class="negative-button">Delete</button></a>
</div>
</div>
</div>
{% endfor %}
<div class="row">
<div class="col-sm-12 text-center py-4">
{% if user.is_authenticated %}
<a href="{% url 'home:add_review' %}">
<button class="positive-button-lg">Add a review</button>
</a>
{% else %}
<p>If you would like to add your own review, please login or sign up if you haven't already!</p>
{% endif %}
</div>
</div>
</div>
{% endblock %}
add_review.html:
{% extends "base.html" %}
{% load static %}
{% block content %}
<div class="container-fluid">
<div class="row justify-content-center">
<div class="col-auto text-center p-3">
<form method="post" style="margin-top: 1.3em;">
{{ review_form }}
{% csrf_token %}
<button type="submit" class="btn btn-primary btn-lg">Submit</button>
</form>
</div>
</div>
{% endblock %}
views.py:
from django.shortcuts import render
from django.views import View
from django.urls import reverse_lazy
from django.views.generic import UpdateView, DeleteView
from .models import Reviews
from .forms import ReviewForm
def home(request):
''' Returns the home page.'''
return render(request, 'home/index.html')
def reviews(request):
''' Returns the reviews page.'''
serialized_reviews = []
reviews = Reviews.objects.all()
for review in reviews:
serialized_reviews.append({
"title": review.title,
"content": review.content,
"user": review.user,
"created": review.created,
"updated": review.updated,
})
context = {
"reviews": serialized_reviews
}
print(serialized_reviews)
return render(request, 'home/reviews.html', context)
class AddReview(View):
'''View which allows the user to add a new review.'''
def get(self, request, *args, **kwargs):
review = Reviews
review_form = ReviewForm
context = {
'review': review,
'review_form': review_form,
'user': review.user,
'title': review.title,
'content': review.content,
}
return render(request, 'add_review.html', context)
def post(self, request, *args, **kwargs):
review_form = ReviewForm(data=request.POST)
if review_form.is_valid():
obj = review_form.save(commit=False)
obj.user = request.user
obj.save()
return redirect("home:reviews")
class DeleteReview(DeleteView):
'''View which allows the user to delete the selected review.'''
model = Reviews
template_name = 'delete_review.html'
success_url = reverse_lazy('reviews')
class EditReview(UpdateView):
'''View which allows the user to edit the selected review.'''
model = Reviews
template_name = 'edit_review.html'
fields = ['title', 'content']
urls.py:
from django.urls import path
from . import views
app_name = 'home'
urlpatterns = [
path('', views.home, name='home'),
path('reviews', views.reviews, name='reviews'),
path('reviews/add', views.AddReview.as_view(), name='add_review'),
path('reviews/delete/<int:pk>', views.DeleteReview.as_view(), name='delete_review'),
path('reviews/edit/<int:pk>', views.EditReview.as_view(), name='edit_review'),
]
The main difference is my app name, which is 'core'. Also, I forgot to add the content field to the model, but that is easily done, the form will just handle it as soon as you do the migration. (except on list.html)
models.py
from django.db import models
from django.contrib.auth import get_user_model
from django.utils import timezone
class Reviews(models.Model):
user = models.ForeignKey(get_user_model(), on_delete=models.CASCADE)
title = models.CharField(max_length=128)
created_at = models.DateTimeField(auto_now_add=timezone.now())
updated_at = models.DateTimeField(auto_now=timezone.now())
forms.py
from django import forms
from core.models import Reviews
class ReviewsForm(forms.ModelForm):
class Meta:
model = Reviews
fields = '__all__'
views.py
from core.models import Reviews
from core.forms import ReviewsForm
from django.shortcuts import render, redirect
def list_reviews(request):
reviews = Reviews.objects.all()
context = {
"reviews": reviews
}
return render(request, 'reviews/list.html', context)
def add_review(request):
if request.method == 'POST':
form = ReviewsForm(request.POST)
if form.is_valid():
form.save()
return redirect('/reviews/')
else:
form = ReviewsForm()
context = {
'form': form
}
return render(request, 'reviews/detail.html', context)
def edit_review(request, pk):
if request.method == 'POST':
form = ReviewsForm(request.POST)
if form.is_valid():
obj = Reviews.objects.get(id=pk)
obj.title = form.cleaned_data['title']
obj.user = form.cleaned_data['user']
obj.save()
return redirect('/reviews/')
else:
obj = Reviews.objects.get(id=pk)
form = ReviewsForm(instance=obj)
context = {
'form': form
}
return render(request, 'reviews/detail.html', context)
def delete_review(request, pk):
obj = Reviews.objects.get(id=pk)
obj.delete()
return redirect('/reviews/')
urls.py
from django.urls import path
import core.views as views
app_name = 'core'
urlpatterns = [
path('reviews/', views.list_reviews, name='list-reviews'),
path('reviews/add', views.add_review, name='add-review'),
path('reviews/edit/<int:pk>/', views.edit_review, name='edit-review'),
path('reviews/delete/<int:pk>/', views.delete_review, name='delete-review'),
]
list.html
{% extends "base.html" %}
{% load static %}
{% block content %}
<div class="container-fluid home-container">
<div class="row align-items-center">
<div class="col-sm-12 text-center mt-4">
<h2><strong>Reviews</strong></h2>
</div>
</div>
{% for review in reviews %}
<hr class="hr-1">
<div class="row featurette">
<div class="col-sm-12">
<h2 class="featurette-heading">{{ review.title }}</h2>
<p class="lead">{{ review.content }}</p>
<div class="row justify-content-between mx-1">
<p>By: {{ review.user }}</p>
<p>Created on: {{ review.created_at }}</p>
<p>Last Updated: {{ review.updated_at }}</p>
</div>
<!-- Add user authentication if -->
<div class="text-center">
<a href="{% url 'core:edit-review' pk=review.id %}" class="mx-2">
<button class="positive-button mb-2">Edit</button></a>
<a href="{% url 'core:delete-review' pk=review.id %}" class="mx-2 mb-2">
<button class="negative-button">Delete</button></a>
</div>
</div>
</div>
{% endfor %}
<div class="row">
<div class="col-sm-12 text-center py-4">
{% if user.is_authenticated %}
<a href="{% url 'core:add-review' %}">
<button class="positive-button-lg">Add a review</button>
</a>
{% else %}
<p>If you would like to add your own review, please login or sign up if you haven't already!</p>
{% endif %}
</div>
</div>
</div>
{% endblock %}
detail.html
{% extends "base.html" %}
{% load static %}
{% block content %}
<div class="container-fluid">
<div class="row justify-content-center">
<div class="col-auto text-center p-3">
<form method="post" style="margin-top: 1.3em;">
{% csrf_token %}
<table>
{{ form }}
</table>
<button type="submit" class="btn btn-primary btn-lg">Save</button>
</form>
</div>
</div>
{% endblock %}
According to your urls, It is a review/edit/<int:pk>.
So you must add same thing in href tag.
Change this:
<a href="edit/{{ review.id }}"
To this:
<a href="review/edit/{{ review.id }}"
That's why you are getting that error
I've fixed it, firstly the path in my add_review view was wrong, which I have amended and it now works (thanks Ivan).
I also was not actually bringing the ID through on my 'reviews' view in the first place, so when following the links on my edit and review buttons, it didn't know what I meant by 'id', as I hadn't specified what that was in the view context.
Thanks for the help all!
I think you're writing in your urls the wrong way, like this below your div text-center:
<a href="edit/{{ review.id }}" class="mx-2">
It should be:
<a href="{% url 'yourappname:edit' review.id %}">
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)
So my problem is that even though I have created the forms from my model and provided my views with those forms, the related template is not displaying any form:
The following is my forms.py :
from django import forms
from django.contrib.auth.models import User
from .models import Account
class UserUpdateForm(forms.ModelForm):
email = forms.EmailField(max_length=100)
class Meta:
model = User
fields = ['username', 'email']
class AccountUpdateForm(forms.ModelForm):
class Meta:
model= Account
fields = ['image']
And the next one is my views.py:
from .forms importUserUpdateForm, AccountUpdateForm
def account(request):
user_update_form = UserUpdateForm()
profile_update_form = AccountUpdateForm()
return render(request, 'blog/profile.html', {
'user_update_form':user_upate_form,
'profile_update_form':profile_update_form
})
But the following template does not show any form
{% extends './base.html' %}
{% load crispy_forms_tags %}
{% block content %}
<div class="row">
<div class="col-12 d-flex flex-column justify-content-center align-items-start">
<img src="{{ user.account.image.url }}" alt="" class="user-profile-pic">
<label for="user-profile-pic-input">Choose an image</label>
<input type="file" class="form-control-files w-100" id="user-profile-pic-input" name='user-profile-pic-input'>
</div>
</div>
<div class="row">
<div class="col-12">
<form method="POST">
{% csrf_token %}
{{ user_update_form }}
{{ profile_update_form }}
<input type="submit" value="Save changes!" class="btn btn-info btn-block">
</form>
</div>
</div>
{% endblock %}
I had this problem just yesterday. It worked when i called the form class without brackets ()
Try this:
user_update_form = UserUpdateForm
profile_update_form = AccountUpdateForm
If this doesn't work you should probably go down the formset path (inlineformset_factory). It's used to connect modelforms linked by a foreign key. It works with one-to-one and one-to-many relationships.
Here is my code:
# My Form
from flask_wtf import FlaskForm
from wtforms.validators import Length, InputRequired
from wtforms import StringField, SubmitField
class AddGradeForm(FlaskForm):
name = StringField('Grade', validators=[InputRequired(), Length(min=4, max=20)])
submit = SubmitField('Add')
# My route
#admin.route('/AddGrade', methods=['GET', 'POST']) # admin is my blueprint's name
def add_grade():
form = AddGradeForm()
if form.is_submitted():
return str(form.validate_on_submit()) # always returns False
...
flash('New grade has been added', 'success')
return redirect(url_for('grades'))
return render_template('add_grade.html', form=form)
# Template
<form method="POST" action="">
{{ form.hidden_tag() }}
<!-- Second row -->
<div class="row">
<div class="col-12">
<div class="form-group">
{{ form.name.label(class="form-control-label") }}
{% if form.name.errors %}
{{ form.name(class="form-control is-invalid") }}
<div class="invalid-feedback">
{% for error in form.name.errors %}
<span>{{ error }}</span>
{% endfor %}
</div>
{% else %}
{{ form.name(class="form-control") }}
{% endif %}
</div>
</div>
</div>
<div class="input-group mb-35 " style="vertical-align: middle;">
{{ form.submit(class="btn btn-outline-primary btn-block") }}
</div>
</form>
On my local-server validate_on_submit() is working exactly the way I was expecting but In production-server validation_on_submit function always returns False(redirects to the form again with no validation error) I don't know why!?.
Please help me find out this error I have tried many attempts but I couln't found any solution .
I have Seen The same Error , This Worked For me :
Form
Use Form instead of FlaskForm
Route
Use parentheses () instead of brackets [] , when providing allowed methods
To check if form is submitted and validated use :
request.method == 'P0ST' and form.validate() instead of form.validate_on_submit() because we no longer using FlaskForm
Template
Remove form.hidden_tag and use form.csrf.token instead
Here is the code with the changes above :
# My Form
from wtforms import Form,StringField, SubmitField, validators
class AddGradeForm(Form): # replaced FlaskForm with Form
name = StringField('Grade',[validators.InputRequired(), validators.Length(min=4, max=20)])
submit = SubmitField('Add')
# My route
#admin.route('/AddGrade', methods=('GET', 'POST')) # change from [] to ()
def add_grade():
form = AddGradeForm()
if request.method == 'POST' and form.validate():
return str(form.validate_on_submit()) # now returns True
...
flash('New grade has been added', 'success')
return redirect(url_for('grades'))
return render_template('add_grade.html', form=form)
# Template
<form method="POST" action="">
{{ form.csrf_token }} <!-- from form.hidden_tag() to form.csrf_token -->
<div class="row">
<div class="col-12">
<div class="form-group">
{{ form.name.label(class="form-control-label") }}
{% if form.name.errors %}
{{ form.name(class="form-control is-invalid") }}
<div class="invalid-feedback">
{% for error in form.name.errors %}
<span>{{ error }}</span>
{% endfor %}
</div>
{% else %}
{{ form.name(class="form-control") }}
{% endif %}
</div>
</div>
</div>
<div class="input-group mb-35 " style="vertical-align: middle;">
{{ form.submit(class="btn btn-outline-primary btn-block") }}
</div>
</form>
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.