I'm quite new to python and django. Here is my little project and this is the error message I get when I'm trying to log in as a user to my account. I have tried all the solutions which I gained by searching. Please if you know the solution explain it to me quite simply.
My log in view
def login_view(request):
if request.method == 'POST':
form = AuthenticationForm(data=request.POST, request=request)
if form.is_valid:
user = form.user_cache
login(request, user)
return redirect('accounts:user-home')
else:
form = AuthenticationForm()
return render(request, 'login.html', {'form':form})\
My forms.py
# import form class from django
from django.forms import ModelForm
# import GeeksModel from models.py
from .models import *
from django.contrib.auth.models import User
# create a ModelForm
class ProfileForm(ModelForm):
# specify the name of model to use
class Meta:
model = Profile
exclude = [
'user',
]
class UsernameChangeForm(ModelForm):
class Meta:
model = User
fields = ['username', ]
My login.html
<h2>Log In</h2>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Log In</button>
</form>
<p>Don't have an account yet? Register</p>
Related
What I want to do: I want to have a login form that when details are entered they are saved on the admin side.
My problem: the forms are not showing up on my local host page. See image below:
Here is the code from the login form app:
admin.py:
from django.contrib import admin
# Register your models here.
from .models import Contact
admin.site.register(Contact)
from apps.py:
from django.apps import AppConfig
class ContactConfig(AppConfig):
name = 'contact'
from forms.py
from .models import Contact
class ContactForm(forms.ModelForm):
class Meta:
model = Contact
fields = ('username', 'password')
from models.py:
class Contact(models.Model):
username = models.CharField(max_length=100)
password = models.CharField(
max_length=100,
)
def __str__(self):
return f'{self.username} {self.password}'
from views.py:
# Create your views here.
from .forms import ContactForm
def contact(request):
template = "home2.html"
if request.method == "POST":
form = ContactForm(request.POST)
if form.is_valid():
form.save()
else:
form = ContactForm()
context = {
'form': form,
}
return render(request, template, context)
Then finally from the login page:
{% load static %}
<form method="post" class="form">
{% csrf_token %}
{{ form }}
<button type="submit" class="btn">Log In</button>
</form>
Another thing: forms are connected to the admin side but just do not appear on the login page
as my first project in Django I am creating a todo app, that lets people log in and see their own tasks that they created. For that, I need to save author info in single task data.
From what I learned reading the documentation and doing lots of google-searching, the current approach is to use the get_user_model function from django.contrib.auth.
The problem is, that whenever I try to use it in my model, it seems to not get the username from the currently logged in user. While printing the form.errors to my console, the output is:
<ul class="errorlist"><li>added_by<ul class="errorlist"><li>This field is required.</li></ul></li></ul>
Seems like the get_user_model is not returning any value. Can anyone recommend a better approach for me to do that? Or is there something obvious that I missed?
Here are the code snippets:
models.py
from django.db import models
from django.contrib.auth import get_user_model
class Task(models.Model):
title = models.CharField(max_length=35)
completed = models.BooleanField(default=False)
created_date = models.DateTimeField(auto_now_add=True)
added_by = models.ForeignKey(get_user_model(), on_delete=models.CASCADE)
def __str__(self):
return self.title
forms.py
from django import forms
from .models import *
class TaskForm(forms.ModelForm):
class Meta:
model = Task
fields = '__all__'
widgets = {
'title': forms.TextInput(attrs={'class': 'new_task_text', 'placeholder': 'Add new task'}),
}
views.py
#login_required
def list_homepage(request):
tasks = Task.objects.all()
form = TaskForm()
if request.method == 'POST':
form = TaskForm(request.POST)
if form.is_valid():
form.save()
print(form.cleaned_data)
else:
print(form.errors)
return redirect('/list/home')
context = {
'page_title': 'Todo list',
'tasks': tasks,
'form': form,
}
return render(request, 'tasks/list.html', context)
form in template:
<form method="POST", action="#"> {% csrf_token %}
{{ form.title }}
<input class="submit" type="submit", value="Create task">
</form>
Thank you in advance for any help!
Your form template only includes the title field, you either need to add the added_by field to this form, or add it in the view handling
{{ form.added_by }}
or
if request.method == 'POST':
form = TaskForm({**request.POST, **{"added_by": request.user}})
I looked at similar questions but they do not seem to apply. I have a very simple django form which does not show on the website, I only see the Submit button. Here are the relevant files:
models.py
from django.db import models
from django.urls import reverse
import uuid
# Create your models here.
class Job(models.Model):
id = models.UUIDField(
primary_key=True,
default=uuid.uuid4,
editable=False)
job_name = models.CharField(max_length=200)
#One to many relationship requires on_delete
email = models.EmailField()
def __str__(self):
return self.job_name
forms.py
from django import forms
class JobForm(forms.Form):
job_name = forms.CharField(max_length=200)
email = forms.EmailField()
views.py
from django.shortcuts import render
from django.views.generic import TemplateView
from .forms import JobForm
from .models import Job
class HomePageView(TemplateView):
template_name = 'index.html'
class SubmitPageView(TemplateView):
template_name = 'submit.html'
def submit_job(request):
# Retrieve post by id
if request.method == 'POST':
# Form was submitted
form = JobForm(request.POST)
if form.is_valid():
#Form fields passed validation
#If the form is valid, we retrieve the validated data accessing
#form.cleaned_data. This attribute is a dictionary of form fields and their values.
cd = form.cleaned_data
my_model = Job()
my_model.job_name = cd.get('job_name')
my_model.email = cd.get('email')
# Save the job to the database
my_model.save()
else:
form = JobForm()
return render(request, SubmitPageView(), {'form': form})
And in my template I have
<form method="POST" action=".">
<table>
{% csrf_token %}
{{ form.as_table }}
</table>
which gets rendered as:
<form method="POST" action=".">
<table>
<input type="hidden" name="csrfmiddlewaretoken" value="I7yL9XAUhEPiriKVHKtqh9UfhsLWoJrBo68uguqMecX8gmuNoJV7gykvsPc7FtQ2">
</table>
OK, I found the solution by following https://docs.djangoproject.com/en/3.0/topics/class-based-views/intro/
Basically, as I was using class-based views, the functions to get and post the form need to be subsumed into the class-based view for that page. Here is the current version
of views.py:
from django.shortcuts import render
from django.views.generic import TemplateView
from .forms import JobForm
from .models import Job
class HomePageView(TemplateView):
template_name = 'index.html'
class SubmitPageView(TemplateView):
form_class = JobForm
template_name = 'submit.html'
def get(self, request, *args, **kwargs):
form = self.form_class()
return render(request, self.template_name, {'form': form})
def post(self, request, *args, **kwargs):
form = self.form_class(request.POST)
if form.is_valid():
#Form fields passed validation
#If the form is valid, we retrieve the validated data accessing
#form.cleaned_data. This attribute is a dictionary of form fields and their values.
cd = form.cleaned_data
my_model = Job()
my_model.job_name = cd.get('job_name')
my_model.email = cd.get('email')
# Save the job to the database
my_model.save()
else:
form = JobForm()
return render(request, self.template_name, {'form': form})
Try code below:
# if a GET (or any other method) we'll create a blank form
else:
form = JobForm()
return render(request, 'submit.html', {'form': form})
<form action="/your-name/" method="post">
{% csrf_token %}
{{ form.as_table }}
<input type="submit" value="Submit">
</form>
Does it make a difference if you define the form as a modelForm and explicitly state the model and fields?
Add/modify the following to your Forms.py:
class JobForm(forms.ModelForm):
class Meta:
model = Job
fields = ('job_name', 'email')
job_name = forms....
I cant seem to find any posts here regarding extending the Django UserCreationForm model to include a phone number field for users to enter their number and then validate the phone number using phonenumbers.parse in the backend to check if the number is in the respective format and whether it exists or not. I need to know what code I should include in my forms.py under my "users" app.
I've tried including normal html text field for the phonenumbers and it does not belong to the default UserCreationForm model in Django and neither can it be stored in the database. (I need it to be stored in the database for the phone numbers). I am only using forms.py, views.py and register.html to be rendered in views as shown below, currently I am not using models.py.
/* forms.py */
from django import forms
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm
# from validate_email import validate_email
class UserRegisterForm(UserCreationForm):
email = forms.EmailField()
phone_number = forms.IntegerField(required=True)
class Meta:
model = User
fields = ['username', 'email', 'password1', 'password2']
def save(self, commit=True):
user = super(UserCreationForm, self).save(commit=False)
user.email = self.cleaned_data['email']
if commit:
user.save()
return user
/* views.py */
from django.shortcuts import render, redirect
from django.contrib import messages
from .forms import UserRegisterForm
def register(request):
if request.method == 'POST':
form = UserRegisterForm(request.POST)
if form.is_valid():
form.save()
username = form.cleaned_data.get('username')
messages.success(request, f'Account created for {username}!')
return redirect('blog-home')
else:
form = UserRegisterForm()
return render(request, 'users/register.html', {'form': form})
/* register.html */
{% extends "blog/base.html" %}
{% load crispy_forms_tags %}
{% block content %}
<div class="content-section">
<form method="POST">
{% csrf_token %}
<fieldset class="form-group">
<legend class="border-bottom mb-4">Join Today</legend>
{{ form|crispy }}
</fieldset>
<div class="form-group">
<button class="btn btn-outline-info" type="submit">Sign
Up</button>
</div>
</form>
<div class="border-top pt-3">
<small class="text-muted">
ALready Have An Account? <a class="ml-2" href="#">Sign In</a>
</small>
</div>
</div>
{% endblock content %}
I need to include a phone number field as part of the UserCreationForm in django and validate the number to check if it exists or not and then save the number in the database.
I usually extend Django User Model using OneToOneLink
models.py
from django.db import models
from django.contrib.auth.models import User
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
phone = models.CharField(max_length=11, blank=True) # change the field to watever works for you
# This will auto create a profile of user with blank phone number that can be updated later.
#receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
if created:
UserProfile.objects.create(user=instance)
forms.py
class UserForm(forms.ModelForm):
class Meta:
model = User
fields = ('first_name', 'last_name', 'email')
class UserProfileForm(forms.ModelForm):
class Meta:
model = UserProfile
fields = ('phone')
views.py
def create_user(request):
if request.method == 'POST':
user_form = UserForm(request.POST, instance=request.user)
profile_form = ProfileForm(request.POST, instance=request.user.user_profle)
if user_form.is_valid() and profile_form.is_valid():
user_form.save()
profile_form.save()
messages.success(request, _('New user created successfully'))
return redirect('settings:profile')
else:
messages.error(request, _('Please correct the error below.'))
else:
user_form = UserForm(instance=request.user)
profile_form = ProfileForm(instance=request.user.user_profile)
return render(request, 'template_name.html', {
'user_form': user_form,
'profile_form': profile_form
})
template:
<form method="post">
{% csrf_token %}
{{ user_form.as_p }}
{{ profile_form.as_p }}
<button type="submit">Save changes</button>
</form>
UPDATE to initial answer. I decided while the solution below worked it was preferable to inherit the AbstractUser model and add my own requirements in my own bespoke user model. Once in place it's far more straight forward dealing with views and templates. I hesitated at first as I didn't feel confident enough to mess around with the default User model, but it is actually very simple. It also helped me understand abstracting models in general via.
class Meta:
abstract = True
The posts here were very helpful.
How to Extend Django User model using AbstractUser
Extending User Model
Previous post:
I've been struggling with this issue also. I've found a solution that works ok, but may have some pitfalls, which it would be good to get views on. My solution is a combination of the other answer to this question, with two modifications. Firstly the code above should be used to update a user rather than create one, because at registration no user profile exists so can't be called. Secondly, I removed the create_user_profile method on the model and used the answer posted here How to Extend UserCreateForm
to save the extended user information at registration. The reason for removing the create_user_profile was to prevent interference with the save() method on the form. The extended model i'm using is called Account.
I also found this article useful extending the django user model, and I'm still considering whether one of the other options might be more appropriate.
My code looks like this:
Views:
def register_view(request):
form = AccountRegisterForm(request.POST or None)
if form.is_valid():
form.save()
return redirect("accounts:login")
context = {"form": form}
return render(request, "accounts/register.html", context)
def user_update_view(request):
user_obj = User.objects.get(username=request.user)
account_obj = Account.objects.get(user=request.user)
user_form = UserForm(request.POST or None, instance=user_obj)
account_form = AccountForm(request.POST or None, instance=account_obj)
if user_form.is_valid() and account_form.is_valid():
user_form.save()
account_form.save()
return redirect(reverse("accounts:detail"))
context = {
"account_form": account_form,
"user_form": user_form,
}
return render(request, "accounts/account_update.html", context)
Forms
class AccountRegisterForm(UserCreationForm):
group = forms.ModelChoiceField(queryset=Group.objects)
dir = forms.ModelChoiceField(queryset=Directorate.objects)
class Meta:
model = User
fields = (
"username",
"first_name",
"last_name",
"group",
"dir",
)
def save(self, commit=True):
if not commit:
raise NotImplementedError(
"Can't create User and UserProfile without database save"
)
user = super(AccountRegisterForm, self).save(commit=True)
user_account = Account(
user=user,
group=self.cleaned_data["group"],
dir=self.cleaned_data["dir"],
)
user_account.save()
class UserForm(forms.ModelForm):
class Meta:
model = User
fields = ("username", "first_name", "last_name")
class AccountForm(forms.ModelForm):
class Meta:
model = Account
fields = (
"group",
"dir",
)
In {% set form.username = user.get_username %} I want to make form.username equal to the user's username, so when the form is sent, I know who sent it. However, it raises the error: "Did you forget to register or load this tag?"
If I replace this line with {{forms.username}} it works, but it makes necessary for the user to fill the form himself, with whatever he wants, allowing him to submit a file with a username that is not his.
file.html (is included in the home.html):
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{% set form.username = user.get_username %}
{{ form.file }}
<button type="submit">Upload</button>
views.py:
from django.shortcuts import render
from django.conf import settings
from django.core.files.storage import FileSystemStorage
from data.models import UserData
from data.forms import UserDataForm
def model_form_upload(request):
if request.method == 'POST':
form = UserDataForm(request.POST, request.FILES)
if form.is_valid():
form.save()
else:
form = UserDataForm()
return render(request, 'data/ranking_index.html', {
'form': form
})
models.py:
from django.db import models
class UserData(models.Model):
username = models.CharField(max_length=40)
file = models.FileField(upload_to='userdata/')
uploaded_at = models.DateTimeField(auto_now_add=True)
forms.py:
from django import forms
from data.models import UserData
class UserDataForm(forms.ModelForm):
class Meta:
model = UserData
fields = ('username', 'file', )
You haven't included user when rendering the template. So as a result jinja2 fails to find the value for user. I suggest the following.
return render(request, '<your template>', {
'form': form
'user': user
})
You need to create this user object in the same function or import from somewhere else its created. Hope this helps!