I am a beginner in Django, and I have an academy project. I extended the User model by adding some fields to it and used them in a form to allow users to log in. When I try it, it works, but when I submit the form, I get this error: Cannot resolve keyword 'username' into field. Choices are: id, profile_image, status, user, user_id
I know this question is repetitive, but all the cases I've seen were not similar to mine.
models.py
from django.contrib.auth.models import User
from django.db import models
STATUS_CHOICES = (
('', 'What is your use of the academy?'),
('student', 'Student'),
('teacher', 'Teacher'),
('author', 'Author'),
)
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
profile_image = models.ImageField(null=True, default='profile.jpg')
status = models.CharField(
max_length=150,
choices=STATUS_CHOICES,
default='What is your use of the academy?',
)
USERNAME_FIELD = 'user__username'
def __str__(self):
return self.user.username
views.py
from django.shortcuts import render
from django.urls import reverse_lazy
from django.views.generic import CreateView
from .forms import RegisterUserForm
# Create your views here.
def profile(request):
return render(
request,
'common/profile.html'
)
class RegisterView(CreateView):
form_class = RegisterUserForm
success_url = reverse_lazy('login')
template_name = 'registration/register.html'
urls.py
from django.urls import path, include
from django.contrib.auth.views import LoginView
from .forms import UserLoginForm
from . import views
urlpatterns = [
path('login/', LoginView.as_view(authentication_form=UserLoginForm), name='login'),
path('register/', views.RegisterView.as_view(), name='register'),
path('profile/', views.profile, name='profile'),
path('', include('django.contrib.auth.urls')),
]
register.html
{% extends 'base.html' %}
{% load i18n %}
{% block content %}
<div class="container">
<div class="row justify-content-md-center">
<div class="card col-md-6 px-0">
<div class="card-header text-center">
<h3 class="mb-0 py-2">{% trans 'Signup' %}</h3>
</div>
<div class="card-body">
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{% include 'common/form.html' with form=form %}
<div class="d-grid gap-2 text-center">
<button type="submit" class="btn btn-primary d-grid gap-2 col-6 mx-auto">
{% translate 'Signup' %}
</button>
</div>
</form>
</div>
</div>
</div>
</div>
{% endblock content %}
This is my repo on github: https://github.com/HamzaWaleedDV/e_academy
I hope for your assistance.
I tried solutions in this proplems:
Error: Cannot resolve keyword 'id' into field
Cannot resolve keyword 'username' into field. Choices are: city, id, phone, etc
Step 1
Remove AUTH_USER_MODEL = 'accounts.Profile'
from settings.py. You are extending the User
model by creating a OneToOneField
with your Profile
model, so you are still using the Django User
model.
Step 2
Remove USERNAME_FIELD = 'user__username'
from models.py. Again, this is used for custom user models.
Step 3
Remove the class Meta from your models.py:
# REMOVE THIS
class Meta(UserCreationForm.Meta):
model = Profile
fields = UserCreationForm.Meta.fields + ("profile_image","status")
Step 4
Adjust your forms.py to add the new fields:
class RegisterUserForm(UserCreationForm):
...
password2 = forms.CharField(
label='Password Confirmation',
widget=forms.PasswordInput(attrs=attrs)
)
# ADD THESE
# I haven't worked out how to make them pretty, or how to include
# the choices for the status, but I figure you can do that
profile_image = forms.ImageField()
status = forms.CharField(max_length=20)
field_order = ['first_name', 'last_name', 'username', 'profile_image', 'email', 'password1', 'password2', 'status']
Step 5
Change your RegisterView
to save the form, and then add a Profile
since the form you have is just creating a User
, now you need to create a Profile
object connected to that User
:
class RegisterView(CreateView):
form_class = RegisterUserForm
success_url = reverse_lazy('login')
template_name = 'registration/register.html'
def form_valid(self, form):
form.save() # The User is now created
# Create a Profile instance for that User
Profile.objects.create(user=form.instance, status=self.request.POST.get('status'), profile_image=self.request.FILES['profile_image'])
super(RegisterView, self).form_valid(form)
return redirect('login')
Finally
Change your template to SHOW the image:
{% extends 'base.html' %}
{% load static %}
{% load i18n %}
{% block content %}
<style>
.vertical-line {
width: 1px; /* عرض الخط بالبكسل */
height: 100%; /* الارتفاع يمتد ليغطي العنصر بالكامل */
background-color: #80808081; /* لون الخط */
margin: 0 10px; /* هامش يمين ويسار للخط */
}
</style>
<div class="container">
<div class="row">
<div class="card col-md-12 px-0">
<div class="card-header">
<h1 class="text-center">
{% trans 'Hello ' %}{{ user.username }}{% trans '👋' %}
</h1>
</div>
<div class="card-body">
<div class="row">
<div class="col-lg-3 text-center">
<img src="{{ profile.profile_image.url }}" height="200px" width="200px" style="border-radius: 50%;" alt="{{ user.username }}">
<h6>
<span class="badge bg-info">student</span>
</h6>
<hr>
<h5>{{ user.username }}</h5>
</div>
<div class="col-lg-3 justify-content-start">
<div class="vertical-line"></div>
</div>
<div class="col-lg-3">
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock content %}
Result
After registering a new user, hyz:
Note
Take a look at the docs, and be aware that if you do end up wanting to use a custom user model (which, the docs themselves actually recommend), it is easy to do at the start of a project, but tricky if you try to do it in the middle of the project. The same docs tell you how.
-------- EDIT --------
To allow the user to update the profile image:
views.py
@login_required
def edit_profile(request):
if request.method == 'POST':
form = ProfileForm(request.POST, instance=request.user)
if form.is_valid():
form.save()
# user data changed, now change the data in the Profile
profile = Profile.objects.get(user=request.user)
profile.profile_image = request.FILES['profile_image']
profile.save()
return redirect('profile')
else:
form = ProfileForm(instance=request.user)
return render(request, 'common/profile.html', {
'form': form
})
forms.py
class ProfileForm(UserChangeForm):
password = None
profile_image = forms.ImageField()
class Meta():
model = User
fields = ['first_name', 'last_name', 'email', 'profile_image']
widgets = {
'first_name': forms.TextInput(attrs=attrs),
'last_name': forms.TextInput(attrs=attrs),
'email': forms.EmailInput(attrs=attrs),
}
# The form saves the User info, now to save the Profile
def __init__(self, *args, **kwargs):
super(ProfileForm, self).__init__(*args, **kwargs)
self.fields['profile_image'].required = False
models.py
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
# Added blank=True
profile_image = models.ImageField(null=True, blank=True, default='academy_courses/static/profile.jpg')
def __str__(self):
return self.user.username
Make sure to run
python manage.py makemigrations
python manage.py migrate