How to properly render form fields with django? - python

I am currently working on a login page for a django webapp. I am trying to include the login form within the index.html file. However, the form fields are not being rendered. My urls are correct I believe but I'm not sure where I am going wrong. Here is my views.py, forms.py and a snippet of the index.html. (I do not want to create a new page for the login I'd like to keep it on the index page)
# Home view
def index(request):
form = LoginForm()
if form.is_valid():
user = authenticate(
username=form.cleaned_data['username'],
password=form.cleaned_data['password'],
)
if user is not None:
login(request, user)
messages.success(request, f' welcome {user} !!')
return redirect('loggedIn')
else:
messages.info(request, f'Password or Username is wrong. Please try again.')
return render(request, "index_logged_out.html")
class LoginForm(forms.Form):
username = forms.CharField(max_length=63)
password = forms.CharField(max_length=63, widget=forms.PasswordInput)
<!-- Login -->
<section class="page-section" id="login">
<div class="container">
<div class="text-center">
<h2 class="section-heading text-uppercase">Login</h2>
</div>
<form>
{% csrf_token %}
{{form}}
<center><button class="btn btn-primary btn-block fa-lg gradient-custom-2 mb-3" type="submit" style="width: 300px;">Login</button></center>
</form>
<div class="text-center pt-1 mb-5 pb-1">
<center><a class="text-muted" href="#!">Forgot password?</a></center>
</div>
<div class="d-flex align-items-center justify-content-center pb-4">
<p class="mb-0 me-2">Don't have an account?</p>
<button type="button" class="btn btn-outline-primary">Create New</button>
</div>
</form>
</div>
</section>

To add to A.S's answer, you should initialize a context variable at the start of the view.
def index(request):
context = {}
form = LoginForm()
context['form'] = form
if form.is_valid():
# ...
return render(request, "index_logged_out.html", context)
It makes it easier to work with when you start to pass in more variables to the context later on, otherwise it'll complicate your view.

Related

Django form not showing up in template

My problem is not showing up form in the Django template.
I'm using python 3.7.6
Django 3.2
Here is my code
....................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................
forms.py
from django import forms
from tasks.models import Task, TaskType
class TaskForm(forms.ModelForm):
name = forms.CharField(max_length=100,
required=True, widget=forms.TextInput(attrs={'class': 'form-control'}))
input_image = forms.ImageField(widget=forms.FileInput(
attrs={'class': 'form-control-file'}))
task_type = forms.ModelChoiceField(queryset=TaskType.objects.name.all(), widget=forms.Select(
attrs={'class': 'form-control'}))
class Meta:
model = Task
fields = ['name', 'input_image', 'task_type']
view.py
from django.shortcuts import render, redirect
from tasks.forms import TaskForm
def create_task(request):
if request.method == 'POST' and 'submit-task' in request.POST:
task_form = TaskForm(request.POST, request.FILES, instance=request.user)
if task_form.is_valid():
task_form.save()
return redirect(to='dashboard')
return render(request, 'users/dashboard.html', {'task_form': task_form})
dashboard.html
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
<div class="modal fade" id="myModal">
<div class="modal-dialog modal-fullscreen-lg-down">
<div class="modal-content">
<!-- Modal Header -->
<div class="modal-header">
<h4 class="modal-title">Upload your image</h4>
<button
type="button"
class="btn-close"
data-dismiss="modal"
></button>
</div>
<!-- Modal body -->
<div class="modal-body">
<div class="form-group">
<label class="">Task name</label>
{{task_form.name}}
<div class="input-group">
<select class="custom-select" id="inputGroupSelect04">
<option selected>Choose your model</option>
{{task_form.task_type}}
</select>
<span class="input-group-btn">
<span class="btn btn-outline-dark btn-file">
Browse… {{task_form.image_input}}
</span>
</span>
<input type="text" class="form-control" readonly />
</div>
<img id="img-upload" />
</div>
</div>
<!-- Modal footer -->
<div class="modal-footer">
<button
type="button"
class="btn btn-secondary"
data-dismiss="modal"
>
Close
</button>
<button type="button" class="btn btn-primary" name="submit-task">
Save changes
</button>
</div>
</div>
</div>
</div>
</form>
So, in the template, the form is not showing up. Please help me to fix it. Thank you so much
def create_task(request):
if request.method == 'POST' and 'submit-task' in request.POST:
task_form = TaskForm(request.POST, request.FILES, instance=request.user)
...
return render(request, 'users/dashboard.html', {'task_form': task_form})
I pretty sure that you want to return dashboard.html on GET method,
however task_form is creating only when POST method. In other words task_form does not exists.
You should define it before using:
def create_task(request):
if request.method == 'POST' and 'submit-task' in request.POST:
task_form = TaskForm(...)
...
else:
task_form = TaskForm(...) # task form defined for non POST methods
# or place it here
# task_form = TaskForm(...) # task form defined for non POST methods
return render(request, 'users/dashboard.html', {'task_form': task_form})
the first thing in your code is you are passing an instance for a create method but the instance does not exist when you didn't create the record yet, the other problem is you are not supporting the get method.
there is an example :
from django.shortcuts import render, redirect
from tasks.forms import TaskForm
from .models import Task
def create_task(request):
instance = Task.objects.filter(user=request.user)
if request.method == 'POST':
if instance:
task_form = TaskForm(request.POST, request.FILES, instance=request.user)
else:
task_form = TaskForm(request.POST, request.FILES)
if task_form.is_valid():
task_form.save()
return redirect(to='dashboard')
return render(request, 'users/dashboard.html', {'task_form': task_form})
else:
if instance:
task_form = TaskForm(instance=request.user)
else:
task_form = TaskForm()
return render(request, 'users/dashboard.html', {'task_form': task_form})

why the sentence if form.is_valid(): never pass. i have tried many thing, changing the python version for example and always is the same

When I run the code, it never pass the sentence if form.is_valid():
I have changed the version of python, but it is still the same
views.py
def login_page(request):
form = Loginform(request.POST or None)
context = {
"form": form
}
print("User logged in")
if form.is_valid():
# print("form is validated")
print(form.cleaned_data)
# print("form cleaned data")
username = form.cleaned_data.get("username")
password = form.cleaned_data.get("password")
forms.py
from django import forms
class Loginform(forms.Form):
username = forms.EmailField()
password = forms.CharField(widget=forms.PasswordInput)
view.html
<div class='container'>
<div class='row'>
<div class='col'>
<p>{{ content }}</p>
<div class='col-sm-6 col-12'>
<form method='POST'> {% csrf_token %}
{{ form }}
<buttom type='submit' class='btn btn-default'>Submit</buttom>
</form>
</div>
</div>
</div>
</div>
# The form looks well, same the submit. I do not see the error
please help me to undertand what happens with this sentence of form_is_valid

Redirect problems with django form in a modal

I am trying to implement a form in a modal which is focused on modifying a comment in a post, the way i did it everything works, the problem is when I click on the submit button it sends me to the html in which I have the modal and there I edit the comment. when I try to delete the url in the action form that takes me to the second page of my form it throws the error "local variable 'form' referenced before assign", also if I put for example in form action the url of the login sends me towards There but the comment is not updated or edited.
My idea is simply that when I submitting the form, the modal closes, and the page where the modal was opened from the beginning, reload or simply the comment already edited appears.
if you need more information I can add it.
views.py
#need_analyst_role
def comment_modify(request, comment_id):
if 'comment_edit' in request.POST:
form_comment = FormComment(request.POST)
if form_comment.is_valid():
comment_text = form_comment.cleaned_data['text']
comment = ModelRiskTracking.objects.get(id=comment_id)
comment.comment = comment_text
print(comment.comment)
comment.save()
else:
messages.error(request, 'Error!', extra_tags="danger")
context = {}
context['comment'] = ModelRiskTracking.objects.get(id=comment_id)
return render(request, 'analyst_pages/comment_edit.html', context = context)
modal.html
<div class="modal-dialog modal-dialog-centered modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">
<h2 class="modal-title">Editar comentario</h2>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<form action="{% url 'soc_irisk_modify' comment_id=comment.id %}" method="POST">
{% csrf_token %}
<textarea type="text" name="text" class="form-control" rows="15">{{ comment.comment|safe }}</textarea>
<div class="modal-footer">
<input type="submit" value="Actualizar" name="comment_edit" onsubmit="setFormSubmitting()" class="btn btn-info btn-sm pull-right" />
</div>
</form>
</div>
</div>
I open the modal with a button calling a jQuery function:
<script type="text/javascript">
function openModal(url){
$('#commentModal').load(url, function(){
$(this).modal('show');
});
}
</script>
<button type="button" class="btn btn-primary btn-sm pull-right" data-toggle="modal" data-target="#commentModal" onclick="openModal('{% url 'soc_comment_modify' comment_id=comment.id %}')">
when you saving the model, you need to redirect the user
#need_analyst_role
def comment_modify(request, comment_id):
if 'comment_edit' in request.POST:
form_comment = FormComment(request.POST)
if form_comment.is_valid():
comment_text = form_comment.cleaned_data['text']
comment = ModelRiskTracking.objects.get(id=comment_id)
comment.comment = comment_text
print(comment.comment)
comment.save()
return redirect("some_url")
else:
messages.error(request, 'Error!', extra_tags="danger")
return redirect("some_url")
context = {}
context['comment'] = ModelRiskTracking.objects.get(id=comment_id)
return render(request, 'analyst_pages/comment_edit.html', context = context)

WTForms/flaskforms not retrieving data properly via submit button

So I'm just trying to get the submit button to work properly.
Work properly meaning to get the user input for email and password to be directed to my login.
Currently, it only redirects to the index.html, but I want it to go result with a redirect to either profile or error.
Here's the python part:
#app.route("/login", methods=["GET", "POST"])
def login():
"""Log user in if credentials provided are correct."""
form = LoginForm(request.post)
# this is if its POST
if form.validate and request.method == 'POST':
email = request.form['email']
password = request.form['password']
if email == admin#gmail.com" and password == "admin":
return redirect(url_for('/home'))
else:
return redirect(url_for('/error'))
# this is if its GET
#return render_template("index.html", form=form)
This is the login form
class LoginForm(FlaskForm):
email = StringField('email', validators=[InputRequired()])
password = PasswordField('password', validators=[InputRequired()])
remember = BooleanField('remember me')
Here's the html part:
<div class="modal-body">
<form role="form">
<div class="form-group">
<div class="input-group">
<form method="POST" action="{{ url_for('login')}}">
{{ form.csrf }}
<dl style="width: 100%;">
<div class="form-group">
<form role="form">
<div class="form-group">
<div class="input-group">
{{ wtf.form_field(form.email) }}
{{ wtf.form_field(form.password) }}
</div>
</div> <!-- /.form-group -->
</form>
</div> <!-- /.form-group -->
<div style="margin-left: 70%;" class="checkbox">
{{ wtf.form_field(form.remember) }}
</div>
<div class="modal-footer">
<input class="btn btn-lg btn-primary btn-block" style="background-color: #3eb2a0;border-color: #3eb2a0;" type="submit" value="Sign In">
</div>
</dl>
</form>
</div>
</div>
</form>
</div>
Only problems i see with your code is one:
if email == admin#gmail.com" and password == "admin":
return redirect(url_for('/home'))
You do not have a quotation mark before admin#gmail.com
two:
return redirect(url_for('/home'))
is there a reason for the forward slash? have you tried 'home'
edit:
Here is an example of how i set up views that are similar to yours
#bp.route('/upvote', methods=['GET', 'POST'])
def view():
form = key()
if form.validate_on_submit():
received_key = form.key_code.data
url = form.url.data
username = form.username.data
return redirect(url_for('views.success')) #views is the name of the blueprint the success route is in
return render_template('upvote.html', title='title here', form=form)
form.validate_on_submit():
Takes the place of form.validate and form.submit.data/if response.method ='POST'
and you can then retrieve the data stored in the forms by form.variable.data.
Check to see if you are even receiving data back from the forms at all. It seems like it might not be recieving the post request and skipping everything under your "if request.method = 'POST'" statement.
Your view would look like:
#app.route("/login", methods=["GET", "POST"])
def login()
form = LoginForm()
# this is if its POST
if form.validate_on_submit():
email = form.email.data
password = form.password.data
if email == "admin#gmail.com" and password == "admin":
return redirect(url_for('home'))
else:
return redirect(url_for('error'))
#return render_template("index.html", form=form)

AbstractUser Login View

I've spent a couple of days on this, read the docs, read some Two Scoops info, and I'm missing something. I'm trying to make a view to log in an AbstractUser. The AbstractUser model is in my_app and the view is in an app called mainsite, that I use to store project-wide views.
After the user logs in, they will have access to class-based views that they will use to add, edit, and delete database records. These users are not staff, so I am not giving them access to the admin.
Every time I try to log in as a user, authenticate(username, password) (in views.py) returns none.
What am I missing?
Here's the setup--I have a custom Person model that extends the AbstractUser model:
# my_app.models.py
class Person(AbstractUser):
date_left = models.DateField(blank=True, null=True)
phone_number = models.IntegerField(blank=True, null=True)
def _full_name(self):
return self.get_full_name()
full_name = property(_full_name)
def __str__(self):
return self.get_full_name()
class Meta:
verbose_name_plural = 'People'
I've added Person to settings.py:
# settings.py
...
AUTH_USER_MODEL = "my_app.Person"
...
I have the following URLconf:
# project/urls.py
from mainsite.views import login_view
...
url(r'^login/$', login_view, name='login'),
...
This view logs in the user:
# mainsite.views.py
def login_view(request):
if request.method == 'POST':
username = request.POST['username']
password = request.POST['password']
user = authenticate(username=username, password=password)
if user is not None:
login(request, user)
return render(request, 'logged_in.html')
else:
return render(request, 'login.html',
{'message': 'Bad username or password'}
)
else:
return render(request, 'login.html')
And finally, here's the template with the login fields:
#templates/login.html
<form action="{% url 'login' %}" method="post">
{% csrf_token %}
<div class="row column"><h1>Login</h1></div>
{% if message %}
<div class="row">
<div class="small-12 medium-6 columns">
<div class="alert callout">
<p>{{ message }}</p>
</div>
</div>
</div>
{% endif %}
<div class="row">
<div class="small-12 medium-6 columns">
<label>Username
<input type="text" id="username" name="username">
</label>
</div>
</div>
<div class="row">
<div class="small-12 medium-6 columns">
<label>Password
<input type="password" id="password" name="password">
</label>
</div>
</div>
<div class="row">
<div class="small-12 medium-6 columns">
<input type="submit" value="Log in" class="button">
</div>
</div>
</form>
I found an answer (with help from reddit) in the docs.
When you use AbstractUser, you need to create your own UserCreationForm and UserChangeForm. If you use AbstractBaseUser, then you will need to create additional forms.
I had not created these forms, and I created my users in the admin using forms automatically generated by Django. These forms did not set the password correctly. The automatically generated form probably used user.password = 'some_password'. The correct way to do it is user.set_password('some_password') .

Categories