Django: CustomUser model does not have the attributes of built-in User - django

I have a problem with the CustomUser Model. Here is the model:
class CustomUser(models.Model):
department = models.ManyToManyField(Department)
game = models.ManyToManyField(Game)
user = models.OneToOneField(User)
In my user registration form, I want to have fields of User plus the Game and Department fields. Here's my form as of now:
class MyRegistrationForm(UserCreationForm):
email = forms.EmailField(required=True)
first_name = forms.CharField(max_length = '200')
last_name = forms.CharField(max_length = '200')
class Meta:
model = User
fields = ('first_name', 'last_name', 'username', 'email')
I used User as my Model, so clearly it does not have the Game and Department fields as of now. At the same time, if I use CustomUser as a model in my form, I do have all the fields I need, but when I click the register button, an error: "CustomUser does not have a set_password attribute" appears.
Also, in Setting I have this:
CUSTOM_USER_MODEL = 'logins.CustomUser'
So how can I make the CustomUser Model have the attributes of User and have those fields appear in my form?
Thanks in advance!

When creating your own custom user model, it's usually best to subclass the AbstractBaseUser which includes those default fields and will generally make the process easier on you. OneToOne relationship to the default User model is more about expnding the built-in User model, which doesn't sound like what you're looking for. Read more about it here
As Daniel mentioned in the comments, this means you're going to have to explicitly include the username field (and you obviously have the freedom to define it as you'd like, it just has to be unique). In the example below I set up email to be the username
from django.contrib.auth.models import AbstractBaseUser
class CustomUser(AbstractBaseUser):
department = models.ManyToManyField(Department)
game = models.ManyToManyField(Game)
# user = models.OneToOneField(User)
email = models.EmailField(max_length=255, unique=True, db_index=True)
USERNAME_FIELD = 'email'
Now you need to include the password field in your form, and please look at the example given in the documentation, they do a better job explaining than I do.

Related

Implementing user type restrictions in my Django application

I've been going back and forward between two tutorials on creating custom user models:
https://simpleisbetterthancomplex.com/tutorial/2018/01/18/how-to-implement-multiple-user-types-with-django.html
and https://wsvincent.com/django-tips-custom-user-model/
So far here is my code:
Model:
class CustomUser(AbstractUser):
is_admin = models.BooleanField('admin status', default=False)
is_areamanager = models.BooleanField('areamanager status', default=False)
is_sitemanager = models.BooleanField('sitemanager status', default=False)
Form:
class CustomUserCreationForm(UserCreationForm):
class Meta(UserCreationForm.Meta):
model = CustomUser
class CustomUserChangeForm(UserChangeForm):
class Meta(UserChangeForm.Meta):
model = CustomUser
Admin:
class CustomUserAdmin(UserAdmin):
add_form = CustomUserCreationForm
form = CustomUserChangeForm
model = CustomUser
list_display = ['email', 'username',]
admin.site.register(CustomUser, CustomUserAdmin)
I have hit a bit of a wall at this point. I'm not sure what direction to go in with restricting content to users. My general idea is I want admins to access everything, area managers to have the next level of access, site manager after that, then regular users (false on all boolean checks) to have base privileges.
Is this the best route to go for this kind of implementation? Where should I go from here and why?
Don't extend the AbstractUser, user Django built-in groups and permissions to create class of users with different privileges:
https://docs.djangoproject.com/en/3.0/topics/auth/default/#groups
If you need to add more info to you user, a common pattern is to create a UserProfile:
class UserProfile(models.Model):
user = models.OneToOneField(User, related_name='profile')
address = models.CharField(max_length=140)
age = ...
A couple of suggestions:
Use the AbstractUser just in case of specific use cases (for example when you need to customize the AuthenticationBackend)
Use the user ID and not the user profile id as FK in models (it is more easy to retrieve it from requests)
For basic use cases just adding a 'role' field to the UserProfile is enough for implementing a simple logic

create a user in Django 2.1 that is associated with an existing model

In my models.py file I have the following code ->
from django.db import models
class Blogger(models.Model):
username = models.CharField(max_length=20)
email = models.EmailField()
first_name = models.CharField(max_length=20)
last_name = models.CharField(max_length=20)
password = models.CharField(max_length=30, default='')
I want to associate the Blogger model with a User and create the User upon form submission. Here is the forms.py file ->
from django import forms
from blog.models import Blogger
class BloggerForm(models.ModelForm):
class Meta:
model = Blogger
fields = ['username', 'email', 'first_name', 'last_name', 'password']
And here is the views.py ->
class BlogView(FormView):
template_name = 'blogform.html'
form_class = BloggerForm
success_url = 'blog/'
How do I create a new user on the submission of this form ?
All fields in blogger already exists in User model, actually you don't need this Blogger model at all, just use the User model directly.
There's a couple ways you can do this but basically the general 2 answers are:
Toss/copy Django's user model and make your own (hard)
Extend the user model by making a new model, and relating it to the user model (easy)
I usually choose option #2 because then you don't have to reconfig the auth system. This is a good tutorial on how to do it: simpleisbetterthancomplex

Extending User fields in UserCreationForm

I am trying to add some custom fields to a user, and extend the UserCreationForm so that I can add these fields when the user is created. I am following the docs but when I try to load the page to create a user I get an error: Unknown field(s) (username) specified for Customer.
The docs that I am following: Custom User and Auth Forms
models.py
class User(AbstractUser):
is_restaurant = models.BooleanField(default=False)
is_customer = models.BooleanField(default=False)
class Customer(models.Model):
user = models.OneToOneField(User, primary_key=True, on_delete=models.CASCADE)
address = models.CharField(max_length=200)
def __str__(self):
return self.user.get_full_name()
forms.py
class CustomerSignUpForm(UserCreationForm):
class Meta(UserCreationForm.Meta):
model = Customer
fields = UserCreationForm.Meta.fields + ('address',)
I understand that username is not part of the Customer class, but the docs appear to be doing the same thing...
The doc says:
If your custom user model is a simple subclass of AbstractUser, then
you can extend these forms in this manner...
In other words this will work only in case you want to add to the form is_restaurant or is_customer fields:
class CustomerSignUpForm(UserCreationForm):
class Meta(UserCreationForm.Meta):
model = User
fields = UserCreationForm.Meta.fields + ('is_restaurant',)
But in your case Customer is not subclass of AbstractUser, since this method is not working for you. As a workaround you can try to work with two separate forms in the same time as suggested in this answer.

What's difference between property and fields of meta in django form?

Curious about their difference. Example :
from django import forms
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm
GENDER_CHOICES = (
('M', '남'),
('F', '여'),
)
class MyUserCreationForm(UserCreationForm):
email = forms.EmailField(required=True)
birth = forms.DateField(widget=forms.SelectDateWidget(
years=range(1970, 2015)), required=True)
gender = forms.ChoiceField(choices=GENDER_CHOICES, initial='M')
class Meta:
model = User
fields = ('username', 'birth', 'email',
'gender', 'password1', 'password2')
def save(self, commit=True):
user = super(MyUserCreationForm, self).save(commit=False)
user.email = self.cleaned_data['email']
user.birthday = self.cleaned_data['birth']
if commit:
user.save()
return user
It defines email, birth, gender as properties of form, and it also has fields in Class Meta. I want to clearly understand their difference. Thanks in advance.
The Meta.fields property is for model forms. It is used to specify which model fields you want the model form to handle. So if you had a model like so:
class MyModel(models.Model):
name = models.CharField(max_length=255)
date = models.DateField(auto_now=True)
You could define a form that only handles the name, because the date is auto-populated and you might not want the user to be able to set it manually:
class MyModelForm(forms.ModelForm):
class Meta:
model = Article
fields = ['name']
This property is not used on regular (non-model) forms.
The form in your question subclasses UserCreationForm which is a ModelForm for the User model. So the fields property is specifying which of the User model properties you want the form to expose.
The field definitions on the class itself (email, birth, gender) are only necessary if:
You want to add fields to the form that are not in the model. In this case, it looks like gender and birth are exactly such fields (unless you have a custom user model which has these fields).
You want to customise the widget used to render a field. In this case you can override the original field and specify a custom widget. This is what is being done in the birth field where the widget has a restricted date range that would not exist in the default widget.
All the other fields (username, email) will be rendered using the default widgets because you haven't explicitly specified them in the class. password1 and password2 are not User model properties but are additional fields defined in the UserCreationForm.

Data being stored in User class instead of UserProfile

I'm trying to create a custom class Employee that uses the default authentication. I am able to successfully register but the fields associated with Django's User class are stored in User while my custom fields are stored in Employee. How can I get everything stored in Employee?
This is my forms.py:
class UserForm(forms.ModelForm):
password = forms.CharField(widget=forms.PasswordInput())
class Meta:
model = User
fields = ('username', 'first_name', 'last_name', 'email', 'password')
class EmployeeForm(forms.ModelForm):
class Meta:
model = Employee
fields = ('sales', 'hours')
And my models.py:
class Patient(models.Model):
user = models.OneToOneField(User)
sales = models.CharField(max_length=30)
hours = models.CharField(max_length=30)
Like I said, I would prefer to use the default authentication and therefore avoid using a custom backend
What you're using is generally called a User Profile which will not store the added fields in the same table (which you have found out). MOre info on that can be found in Extending existing user model.
What you're wanting to do (and the method that I typically need to use in my projects) is Substitute a custom user model. It is a bit more complicated, but once you get the hang of it it's not too bad. It will allow you to store all your User fields in one table instead of in separate tables/models.