How to creat mutiple UserProfiles that inherit from AbstractUser in Django? - python

Original Question
I want to create 3 UserProfile for 3 types of users. At first, I made a CharFiled as a mark to differentiate them, but then I realized that I have to put some ForeignKey to associate those users. As for this step, I don't know how to make it come true.
To make it specific:
3 types of users that inherit from AbstractUser, each of them can log into the system
There is a hierarchy among them, much like:
AdminstratorA(not a superuser)
AdminstratorB
|--TeacherA
|--TeacherB
|--StudentA
|--StudentB|
following are my failures(simplified version), Using Django2.1 python3.7
got a problem, because I could only set one AUTH_USER_MODEL = 'users.UserProfile' at mysite\settings.py
apps\users\model
from django.contrib.auth.models import AbstractUser
from django.db import models
class AdministratorUser(AbstractUser):
pass
class TeacherUser(AbstractUser):
administrator = models.ForeignKey(AdministratorUser, on_delete=models.CASCADE)
class StudentUser(AbstractUser):
teacher = models.ForeignKey(TeacherUser, on_delete=models.CASCADE)
I set the main table and other 3 tables as complement. Based on that, I designed my admin site based on xadmin, and the data doesn't represent well. I have no idea about it. So I try to redesign my model, which is the plan I described on the top.
apps\users\model
from django.contrib.auth.models import AbstractUser
from django.db import models
class UserProfile(AbstractUser):
user_type_choices = (
('student', 'student'),
('teacher', 'teacher'),
('teacher', 'teacher'),
)
identity = models.CharField(choices=user_type_choices, max_length=100, default='student')
class AdministratorUser(models.Model):
user_profile = models.OneToOneField(UserProfile, on_delete=models.CASCADE)
class TeacherUser(models.Model):
user_profile = models.OneToOneField(UserProfile, on_delete=models.CASCADE)
administrator = models.ForeignKey(AdministratorUser, on_delete=models.CASCADE)
class StudentUser(models.Model):
user_profile = models.OneToOneField(UserProfile, on_delete=models.CASCADE)
teacher = models.ForeignKey(TeacherUser, on_delete=models.CASCADE)

It really depends what you're trying to achieve, but the simplest approach would be similar to the is_staff and is_superuser fields in the standard User model.
class UserProfile(AbstractUser):
is_type1_user = models.BooleanField(default=False)
is_type2_user = models.BooleanField(default=False)
is_type3_user = models.BooleanField(default=False)

You could make use of Django's generic relations by customising the User model as well as the UserManager in the following way:
First of all you need to import the relevant stuff:
from django.apps import apps
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes.fields import GenericRelation
from django.contrib.auth.models import AbstractUser, UserManager as OriginalUserManager
The UserManager:
class UserManager(OriginalUserManager):
def _create_user(self, username, email, password, **extra_fields):
"""
Create and save a user with the given username, email, and password.
"""
if not username:
raise ValueError('The given username must be set')
email = self.normalize_email(email)
username = self.model.normalize_username(username)
user = self.model(username=username, email=email, **extra_fields)
user.set_password(password)
# handle profile creation at user creation
profile_model = User.TYPE_MODELS.get(user.user_type)
profile_model = apps.get_model(app_label='app1', model_name=profile_model)
if profile_model is None:
raise Exception(
"Profile model has not been set in User.TYPE_MODELS for user type {}".format(user.user_type))
profile = profile_model.objects.create()
user.content_type = ContentType.objects.get_for_model(profile_model)
user.object_id = profile.id
user.content_object = profile
user.save(using=self._db)
return user
The User model:
class User(AbstractUser):
TYPE_1 = 0
TYPE_2 = 1
TYPE_CHOICES = (
(TYPE_1, "Type 1"),
(TYPE_2, "Type 2"),
)
TYPE_MODELS = dict((
(TYPE_1, "ProfileType1"),
(TYPE_2, "ProfileType2"),
))
user_type = models.PositiveSmallIntegerField(choices=TYPE_CHOICES, default=TYPE_1)
# Below the mandatory fields for generic relation
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey()
objects = UserManager()
class Meta:
unique_together = ('content_type', 'object_id',)
#property
def profile(self):
return self.content_object
Then you can define your profiles as such (for example):
class BaseProfileModel(models.Model):
_user = GenericRelation(User)
#property
def user(self):
ctype = ContentType.objects.get_for_model(self.__class__)
try:
event = User.objects.get(content_type__pk=ctype.id, object_id=self.id)
except User.DoesNotExist:
return None
return event
class ProfileType1(BaseProfileModel):
x = models.IntegerField(default=0)
class ProfileType2(BaseProfileModel):
y = models.IntegerField(default=0)
Now the way you can use them is in the following way:
Create a user with a default user type:
user = User.objects.create_user("someusername")
user.profile --> will yield a ProfileType1 instance
Create a user with a secific user type
user = User.objects.create_user("someothername", user_type=User.TYPE_2)
user.profile --> will yield a ProfileType2 instance
In both cases if we have in our hands the profile instance we can obtain the user by doing:
profile.user --> will yield our original user instance

Related

How to avoid the use of ManytoMany field in Django?

I have the Role model. Account model take the reference from Role model using ManytoMany Field. But, I don't want to use manytomany field. It's necessary to not use ManyToMany field. Is anyone can suggest something better.
I don't want to use use ManyToMany field because, since many to many are a Django feature and not database
The given below model works fine with ManyToMany Field, I want the same with it.
from django.db import models
from django.db.models.fields import proxy
from django.contrib.auth.models import BaseUserManager, AbstractBaseUser
from django.utils.translation import gettext_lazy as _
from django.core.validators import RegexValidator
import uuid
from django.utils import timezone
import math
from django.core.validators import MinValueValidator, MaxValueValidator
ADMIN = 0
CUSTOMER = 1
SELLER = 2
DELIVERY_PARTNER = 4
class Role(models.Model):
'''
The Role entries are managed by the system,
automatically created via a Django data migration.
'''
ROLE_CHOICES = (
(ADMIN, 'admin'),
(CUSTOMER, 'customer'),
(SELLER, 'seller'),
(DELIVERY_PARTNER, 'delivery'),
)
id = models.PositiveSmallIntegerField(choices=ROLE_CHOICES, primary_key=True)
def __str__(self):
return self.get_id_display()
class UserManager(BaseUserManager):
'''
creating a manager for a custom user model
https://docs.djangoproject.com/en/3.0/topics/auth/customizing/#writing-a-manager-for-a-custom-user-model
https://docs.djangoproject.com/en/3.0/topics/auth/customizing/#a-full-example
'''
def create_user(self, mobile_number, password=None):
"""
Create and return a `User` with an email, username and password.
"""
if not mobile_number:
raise ValueError('Users Must Have an email address')
user = self.model(
mobile_number=self.normalize_email(mobile_number)
)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, mobile_number, password):
"""
Create and return a `User` with superuser (admin) permissions.
"""
if password is None:
raise TypeError('Superusers must have a password.')
user = self.create_user(mobile_number, password)
user.is_superuser = True
user.is_staff = True
user.save()
return user
class Account(AbstractBaseUser):
'''Account Model to store mobile number and authentication'''
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
email = models.EmailField(
verbose_name='email address',
max_length=255,
null = True,
)
type = models.ManyToManyField(Role,default=[1])
phone_regex = RegexValidator(regex=r'^\+?1?\d{9,15}$', message="Phone number must be entered in the format: '+999999999'. Up to 15 digits allowed.")
mobile_number = models.CharField(validators=[phone_regex], max_length=17, blank=False,null = False, unique=True)
otp = models.CharField(max_length=6, null = True, unique=True)
user_registered_on = models.DateTimeField(default=timezone.now, blank=True)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
is_superuser = models.BooleanField(default=False)
USERNAME_FIELD = 'mobile_number'
REQUIRED_FIELDS = []
# Tells Django that the UserManager class defined above should manage
# objects of this type.
objects = UserManager()
def get_full_name(self):
pass
def get_short_name(self):
pass
# #property
# def is_superuser(self):
# return self.is_superuser
#property
def is_staff(self):
return self.is_superuser
def has_perm(self, perm, obj=None):
return self.is_superuser
def has_module_perms(self, app_label):
return self.is_superuser
#is_staff.setter
def is_staff(self, value):
self._is_staff = value
def __int__(self):
return self.mobile_number
def verify_user_type(self,type):
for x in self.type.all():
if x.id == type:
return True
return False
class Meta:
'''
to set table name in database
'''
db_table = "login"
I don't want to use use ManyToManyField because, since many to many are a Django feature and not database
There is nothing special about a ManyToManyField. Behind the curtains it creates a model (named appname_modename_m2mfieldname) with two ForeignKeys: one to the "source model" and one to the "target model". This is a pattern known as a junction table [wiki], which is how many-to-many relations are normally defined in a relational database.
You can even work with the "hidden" model with Account.type.through, which will return a reference to a model class.
While you can define an extra model for the junction table yourself, it makes no sense, and will only make the ORM more complicated. For more information, see the database representation section on the ManyToManyField [Django-doc].

Django UNIQUE constraint failed: accounts_user.username

I am implementing a custom Django user from scratch. Almost all things are working, but an issue arises when I create new user from the Django admin panel as follows.
django.db.utils.IntegrityError: UNIQUE constraint failed: accounts_user.username
Why does this error occur even if there is no username field in my User model?
I have included supporting files here.
models.py
import uuid
from django.contrib.auth.models import AbstractUser
from django.db import models
from django.utils.translation import gettext_lazy as _
from .managers import CustomManager
from .utils import path_to_upload
# Create your models here.
class BaseModelMixin(models.Model):
uuid = models.UUIDField(default=uuid.uuid4, unique=True, editable=False)
creation_date = models.DateTimeField(_("Created At"), auto_now=True)
modification_date = models.DateTimeField(_("Modified At"),
auto_now_add=True)
class Meta:
abstract = True
class User(AbstractUser, BaseModelMixin):
display_name = models.CharField(_("Display Name"), max_length=200,
blank=True, null=True)
email = models.EmailField(_("Email Address"), unique=True,
blank=False, null=False)
profile_pic = models.ImageField(_("Profile Picture"),
upload_to=path_to_upload)
USERNAME_FIELD = "email"
REQUIRED_FIELDS = ["display_name"]
objects = CustomManager()
forms.py
from django import forms
from django.contrib.auth.password_validation import validate_password
from django.forms import TextInput, PasswordInput
from django.contrib.auth.forms import UserCreationForm
from django.utils.translation import gettext_lazy as _
from .models import User
class AdminUserRegistrationForm(UserCreationForm):
password1 = forms.CharField(validators=[validate_password,],
widget=forms.PasswordInput(attrs={"placeholder": "Password"}))
password2 = forms.CharField(validators=[validate_password, ],
widget=forms.PasswordInput(attrs={"placeholder": "Confirm Password"}))
class Meta(UserCreationForm.Meta):
model = User
fields = ["display_name", "email", "profile_pic"]
widgets = {}
for field in fields:
if field not in ("password", "profile_pic"):
widgets[field] = TextInput(attrs={
"placeholder": field.replace("_", " ").title()
})
widgets["password"] = PasswordInput(render_value=True,
attrs={'required': False})
widgets["profile_pic"] = forms.FileInput()
class AdminUserUpdateForm(forms.ModelForm):
password = forms.CharField(label=_("Password"), required=True,
validators=[validate_password],
widget=PasswordInput(render_value=True))
class Meta:
model = User
fields = ["display_name", "profile_pic", "password"]
widgets = {}
for field in fields:
if not field == "profile_pic":
widgets[field] = TextInput(attrs={"placeholder": field.replace("_", " ").title()})
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
managers.py
from django.contrib.auth.models import BaseUserManager
from django.utils.translation import gettext_lazy as _
class CustomManager(BaseUserManager):
def create_user(self, display_name, email, password, **extras):
if not email:
raise ValueError(_("Email is a mandatory field"))
email = self.normalize_email(email)
user = self.model(display_name=display_name, email=email, **extras)
user.set_password(password)
# user.save()
return user
def create_superuser(self, display_name, email, password, **extras):
extras.setdefault("is_staff", True)
extras.setdefault("is_active", True)
extras.setdefault("is_superuser", True)
if "is_superuser" not in extras:
raise ValueError(_("'is_superuser' is mandatory for superuser"))
if "is_staff" not in extras:
raise ValueError(_("'is_staff' is mandatory for superuser"))
return self.create_user(display_name, email, password, **extras)
admin.py
from django.contrib import admin
from . import models
from . import forms
# Register your models here.
class CustomUserAdmin(admin.ModelAdmin):
# add_form = forms.AdminUserRegistrationForm
form = forms.AdminUserRegistrationForm
model = models.User
list_display_links = None
list_display = ("display_name", "email",)
admin.site.register(models.User, CustomUserAdmin)
You are inheriting from AbstractBaseUser and it has username field, in order to completely remove it from your model you need to set it as None in the custom user class:
class User(AbstractUser, BaseModelMixin):
username = None
...
By default AbstractUser has username field.
by doing USERNAME_FIELD = "email" username field won't be removed.
It just tells Django to use email as username field instead of the actual username field.
since the username field is required and unique you need to remove it manually:
class User(AbstractUser, BaseModelMixin):
# ...
username = None
# ...

DRF: Username still required after customizing Abstract User

I'm trying to write a REST API using Django and DRF. I'm trying to create a user model and use it in my application. But the problem is that it returns a 400 error status code which says:
{"username":["This field is required."]}
This is my code for models:
import uuid
from django.contrib.auth.models import AbstractUser
from django.db import models
from django.conf import settings
from django.dispatch import receiver
from django.utils.encoding import python_2_unicode_compatible
from django.db.models.signals import post_save
from rest_framework.authtoken.models import Token
from api.fileupload.models import File
#python_2_unicode_compatible
class User(AbstractUser):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
email = models.EmailField('Email address', unique=True)
name = models.CharField('Name', default='', max_length=255)
phone_no = models.CharField('Phone Number', max_length=255, unique=True)
address = models.CharField('Address', default='', max_length=255)
country = models.CharField('Country', default='', max_length=255)
pincode = models.CharField('Pincode', default='', max_length=255)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
def __str__(self):
return self.email
#receiver(post_save, sender=settings.AUTH_USER_MODEL)
def create_auth_token(sender, instance=None, created=False, **kwargs):
if created:
Token.objects.create(user=instance)
The Serializer:
class CreateUserSerializer(serializers.ModelSerializer):
username = None
def create(self, validated_data):
validated_data['username'] = uuid.uuid4()
user = User.objects.create_user(**validated_data)
return user
def update(self, instance, validated_data):
instance.name = validated_data.get('name', instance.name)
instance.address = validated_data.get('address', instance.address)
instance.country = validated_data.get('country', instance.country)
instance.pincode = validated_data.get('pincode', instance.pincode)
instance.phone_no = validated_data.get('phone_no', instance.phone_no)
instance.email = validated_data.get('email', instance.email)
instance.save()
return instance
class Meta:
unique_together = ('email',)
model = User
fields = (
'id', 'password', 'email', 'name', 'phone_no', 'address', 'country', 'pincode',
)
extra_kwargs = {'password': {'write_only': True}}
Admin.py file:
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from .models import User
#admin.register(User)
class UserAdmin(UserAdmin):
pass
class User(AbstractUser):
As your User model inherits from AbstractUser, it will inherit
the username field.
Just remove the username field from your User model by setting username = None like this:
class User(AbstractUser):
# ...
username = None
# ...
class UserAdmin(UserAdmin):
As your UserAdmin model inherits from django.contrib.auth.admin.UserAdmin, you will need to update fieldsets, list_display, search_fields, and ordering fields in your UserAdmin model because they use username which you have removed from your User model.
Abstract User always has the username field. Removing it will cause problems. I will suggest you store the email address of the user in username field as well and use that. Please make sure its always updated in both fields which is not very hard.

Override the save() method

I have a custom users schema in Django for work with roles or users type, creating an application named userprofile which will be or will setup my custom user model.
In my settings.py I have the following configuration:
INSTALLED_APPS = [
...
'userprofile',
]
#Custom model Users
AUTH_USER_MODEL = 'userprofile.User'
I customize my User class (userprofile/models.py) that inherit of the AbstractUser class for add some fields to my User model due to my requirements demanded me.
I also create these another models for roles/profile users (MedicalProfile, PatientProfile, PhysiotherapistProfile) with their own fields or attributes
In addition MedicalProfile, PatientProfile, PhysiotherapistProfile have a OneToOneField relationship with my custom model/class User so:
from __future__ import unicode_literals
from django.conf import settings
from django.contrib.auth.models import AbstractUser
from django.db import models
from django.dispatch import receiver
from django.db.models.signals import post_save
class User(AbstractUser):
is_medical = models.BooleanField(default=False)
is_physiotherapist = models.BooleanField(default=False)
is_patient = models.BooleanField(default=False)
slug = models.SlugField(max_length=100, blank=True)
photo = models.ImageField(upload_to='avatars', null = True, blank = True)
# Overriding the save method
def save(self, *args, **kwargs):
if self.is_medical:
profile = MedicalProfile(user=self)
super(User, self).save(self, *args, **kwargs)
profile.save()
# We get the profiles user according with their type
def get_medical_profile(self):
medical_profile = None
if hasattr(self, 'medicalprofile'):
medical_profile=self.medicalprofile
return medical_profile
def get_patient_profile(self):
patient_profile = None
if hasattr(self, 'patientprofile'):
patient_profile = self.patientprofile
return patient_profile
def get_physiotherapist_profile(self):
physiotherapist_profile = None
if hasattr(self, 'physiotherapistprofile'):
physiotherapist_profile = self.physiotherapistprofile
return physiotherapist_profile
class Meta:
db_table = 'auth_user'
class MedicalProfile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
#active = models.BooleanField(default=True)
name = models.CharField(max_length=64)
class PatientProfile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
#active = models.BooleanField(default=True)
name = models.CharField(max_length=64)
class PhysiotherapistProfile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
#active = models.BooleanField(default=True)
name = models.CharField(max_length=64)
My Question
I want to focus my question in relation to the override process save() method:
def save(self, *args, **kwargs):
if self.is_medical:
profile = MedicalProfile(user=self)
super(User, self).save(self, *args, **kwargs)
profile.save()
I want, each that an user is created, automatically be created their profile (MedicalProfile, PatientProfile, PhysiotherapistProfile) according to if their field checked (is_medical, is_patient, is_physiotherapist)
The inconvenient that I have is with my override process is the following:
When I create an user via django admin, I get this error
I don't know about it, in relation of the reason by which is setup the user PK to None ...
What alternatives can I have for solve this situation and when I create an user, their profile instance be saved (MedicalProfile, PhysiotherapistProfile, PatientProfile) depending of the attribute checkbo/field (is_medical, is_physiotherapist , is_patient) that I choose?
I bring to all my apologies before, in case of the my question do not be suited or appropriated with the stackoverflow philosophy or by the extense of my question.
The reason that it's extense is that I want give all details for get an answer
Any orientation I will be grateful and will be appreciated
You need to do something in your save method if the user is not medical; you still need to actually save the object.
A fixed implementation would be:
def save(self, *args, **kwargs):
user = super(User, self).save(self, *args, **kwargs)
if self.is_medical:
MedicalProfile(user=self).save()
My class User located in userprofile/models.py is overriding the save method, stayed so:
class User(AbstractUser):
is_medical = models.BooleanField(default=False)
is_physiotherapist = models.BooleanField(default=False)
is_patient = models.BooleanField(default=False)
slug = models.SlugField(max_length=100, blank=True)
photo = models.ImageField(upload_to='avatars', null = True, blank = True)
def save(self, *args, **kwargs):
user = super(User, self).save( *args, **kwargs)
# Creating and user with medical, patient and physiotherapist profiles
if self.is_medical and not MedicalProfile.objects.filter(user=self).exists()\
and self.is_patient and not PatientProfile.objects.filter(user=self).exists()\
and self.is_physiotherapist and not PhysiotherapistProfile.objects.filter(user=self).exists():
medical_profile=MedicalProfile(user=self).save()
patient_profile=PatientProfile(user=self).save()
physiotherapist_profile=PhysiotherapistProfile(user=self).save()
#profile.save()
# Creating and user with medical and patient profiles
elif self.is_medical and not MedicalProfile.objects.filter(user=self).exists()\
and self.is_patient and not PatientProfile.objects.filter(user=self).exists():
medical_profile=MedicalProfile(user=self).save()
patient_profile=PatientProfile(user=self).save()
# Creating and user with medical and physiotherapist profiles
elif self.is_medical and not MedicalProfile.objects.filter(user=self).exists()\
and self.is_physiotherapist and not PhysiotherapistProfile.objects.filter(user=self).exists():
medical_profile=MedicalProfile(user=self).save()
physiotherapist_profile=PhysiotherapistProfile(user=self).save()
# Creating and user with physiotherapist and patient profiles
elif self.is_physiotherapist and not PhysiotherapistProfile.objects.filter(user=self).exists()\
and self.is_patient and not PatientProfile.objects.filter(user=self).exists():
physiotherapist_profile = PhysiotherapistProfile(user=self).save()
patient_profile = PatientProfile(user=self).save()
# Creating and user with medical profile
elif self.is_medical and not MedicalProfile.objects.filter(user=self).exists():
profile = MedicalProfile(user=self)
profile.save()
# Creating and user with patient profile
elif self.is_patient and not PatientProfile.objects.filter(user=self).exists():
profile = PatientProfile(user=self)
profile.save()
# Creating and user with physiotherapist profiles
elif self.is_physiotherapist and not PhysiotherapistProfile.objects.filter(user=self).exists():
profile = PhysiotherapistProfile(user=self)
profile.save()
# We get the profiles user according with their type
def get_medical_profile(self):
medical_profile = None
if hasattr(self, 'medicalprofile'):
medical_profile=self.medicalprofile
return medical_profile
def get_patient_profile(self):
patient_profile = None
if hasattr(self, 'patientprofile'):
patient_profile = self.patientprofile
return patient_profile
def get_physiotherapist_profile(self):
physiotherapist_profile = None
if hasattr(self, 'physiotherapistprofile'):
physiotherapist_profile = self.physiotherapistprofile
return physiotherapist_profile
# We redefine the attributes (create db_table attribute) in class Meta to say to Django
# that users will save in the same table that the Django default user model
# https://github.com/django/django/blob/master/django/contrib/auth/models.py#L343
class Meta:
db_table = 'auth_user'
class MedicalProfile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
#active = models.BooleanField(default=True)
name = models.CharField(max_length=64)
class PatientProfile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
#active = models.BooleanField(default=True)
name = models.CharField(max_length=64)
class PhysiotherapistProfile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
#active = models.BooleanField(default=True)
name = models.CharField(max_length=64)
# Enter the username as slug field
#receiver(post_save, sender = settings.AUTH_USER_MODEL)
def post_save_user(sender, instance, **kwargs):
slug = slugify(instance.username)
User.objects.filter(pk=instance.pk).update(slug=slug)
the save() method let me save the users with all possible combinations of profiles.
But, is there a better way to do this?

How can I save data in my custom field. (Extends from User) Django

I am using django authentication system. I have my User model
class User(models.Model):
first_name = models.CharField(max_length = 50)
last_name = models.CharField(max_length = 50)
username = models.CharField(max_length = 50, unique = True)
password = models.CharField(max_length = 50)
def __str__(self):
return "%s %s" %(self.first_name, self.last_name)
class Meta:
abstract = True
and recently I discovered that you cannot add some extra fields when you're using the django auth (for example: contact field). Google say, you can extend it. So, I extend it by making a UserProfile:
class UserProfile(User):
contact = models.CharField(max_length=20, null=True)
def __str__(self):
return self.contact_info
The problem is, I don't know how to add/save the data (contact) to the UserProfile. And how to display it in my template. I tried some but if failed:
views.py
if request.method == 'POST':
fname = request.POST['fname']
lname = request.POST['lname']
contact = request.POST['contact']
username = request.POST['username']
password = request.POST['password']
user = User.objects.create_user(username, email=None, password=password)
user.first_name = fname
user.last_name = lname
user.contact = contact
user.save()
user.contact = contact
user.save()
return redirect('system.views.user_login')
Is there any other way to save it?
I don't know where you saw that you can't add extra fields to your User model. You are already defining your own model; there is absolutely nothing to stop you from adding whatever fields you like.
However, if you are doing that, you must inherit from AbstractBaseUser, and set the AUTH_USER_MODEL setting to point to your model. Also, it makes no sense at all for you to define your User model as abstract.
To extend django auth user model, you can use AbstractUser.
from django.contrib.auth.models import AbstractUser
class UserProfile(AbstractUser):
contact = models.CharField(max_length=20, null=True)
def __str__(self):
return self.contact_info

Categories