I have a Custom User model in my app
class User(AbstractBaseUser, PermissionsMixin):
uuid = models.UUIDField(default=uuid.uuid4, unique=True)
email = models.EmailField(_('email address'), db_index=True, unique=True)
and this AUTH_USER_MODEL = 'users.User' in my settings file.
Now I want to create a model on the top of this custom user model(User), lets call it Agent, this model will have three columns:
user_uuid #Foreign Key Refernce(OnetoOne) to the Custom User Model
uuid # unique identifier for Agent model
scope # CharField specific to Agent model
What is the best way to do that?
While there is no best practice, it all depends on what you are doing, the most likely to work method is a type field specifying Agent and a one-to-one table (docs) for extra fields.
It'll be up to you to create the records as-needed. There isn't anything special about what you are doing just because it is a user.
class AgentDetails(Model):
user = OneToOneField(User, primary_key=True, on_delete=CASCADE)
...
A more complete user model would look something like this:
class User(AbstractBaseUser, PermissionsMixin):
USERNAME_FIELD = 'email'
EMAIL_FIELD = 'email'
REQUIRED_FIELDS = ["name"]
email = EmailField(unique=True, db_index=True)
name = CharField(max_length=100)
type = ChoiceField(choices=[('user','User'),('agent','Agent')])
is_staff = models.BooleanField(default=False, help_text='If the user can log into this admin site.')
is_active = models.BooleanField(default=True, help_text='If the user is active, instead of deleting')
created_at = models.DateTimeField('Date Joined', default=timezone.now)
objects = MyUserManager() #
In addition, you are probably going to need to add:
Custom admin page
Custom UserManager
You can derive one table from an abstract base, but this will generate 1 table for each user type which will not work with the standard authentication. For info, see Django's Model Inheritance.
class User(Model):
email = EmailField()
class Meta:
abstract = True
class Agent(User): # generates table 1
extra_field = CharField()
class Standard(User): # generates table 2
extra_field = CharField()
If the user model you have given is complete, then I don't think it will work with the default django infrastructure. From your question its not clear if you need help on that.
Related
I'm currently developing a web-application for managing driving licenses as a web development homework assignment. Instead of just storing information on every driver as a model I want to make a user for each driver. What is the easiest way to do so? What am I doing wrong?
I updated a car owner model so that it is now inherited from djangdo Abstract User.
# models.py
class Car_owner(AbstractUser):
id_owner = models.IntegerField(primary_key=True)
last_name = models.CharField(max_length=30, null=False)
first_name = models.CharField(max_length=30, null=False)
birth_date = models.DateField(null=True)
passport = models.IntegerField(null=True, blank=True)
address = models.CharField(max_length=50, null=True, blank=True)
nationality = models.CharField(max_length=15, null=True, blank=True)
# username = models.CharField(max_length=16, unique=True, default=uuid4)
# password = models.CharField(max_length=16, default='password')
I also have forms.py file:
from django import forms
from project_first_app.models import Car_owner
class CreateOwner(forms.ModelForm):
class Meta:
model = Car_owner
fields = ['id_owner', 'last_name', 'first_name', 'birth_date', 'passport', 'address', 'nationality']
But when migrating I get the following issue:
UNIQUE constraint failed: new__project_first_app_car_owner.username
In migrations files I have:
migrations.AddField(
model_name='car_owner',
name='username',
field=models.CharField(default=uuid.uuid4, max_length=16, unique=True),
),
and then:
migrations.AlterField(
model_name='car_owner',
name='username',
field=models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and #/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username'),
),
Those are automatically generated.
You have commented username and password in your model, why ?
Password field already exists in the abstractbaseuser, so comment it does not remove it. The abstract model user of Django need a unique information for authenticating user. You can use a Username or an Email.
For using the email instead of username, you can define USERNAME_FIELD = "email" in your class. But you have to define a field email, or you keep username field and add it to fields ModelForm.
There is a constraint on the username field (or email field), so you have to define it for each Car_owner you want to create (it is for authenticating purpose).
your field id_owner is useless, Django create automatically a field called id in each model which is the primary key.
so for resolving your problem easily, add username in fields list of your Form for beginning.
I'm doing some querying currently and I was wondering if I would be able to query something from these 3 models where the return would give me all the projects the users are working on. I know about the basic filtering however thats not really enough in this case, how would one go about querying through 2 foreign keys.
class User(models.Model):
first_name = models.CharField(max_length=255)
last_name = models.CharField(max_length=255)
email = models.EmailField()
class ProjectUser(models.Model):
project = models.ForeignKey("Project", on_delete=models.CASCADE)
user = models.ForeignKey("User", on_delete=models.CASCADE)
is_lead = models.BooleanField(default=False)
class Meta:
unique_together = (("project", "user"),)
class Project(models.Model):
name = models.CharField(max_length=255)
client = models.CharField(max_length=255)
complete = models.BooleanField(default=False)
You can obtain the Projects a user is working on with:
Project.objects.filter(
projectuser__user=user
)
The double underscores are used to look "through" relations. Furthermore the default related_query_name=… parameter [Django-doc] is, if not specified, the name of the model in lowercase.
I am trying to filter queryset for a reverse foreign key.
Here are my two models:-
class BranchModel(basemodel.BaseModel):
company = models.ForeignKey(CompanyModel, on_delete=models.PROTECT)
name = models.CharField(max_length=30, default="Head Office")
user = models.ForeignKey(User, on_delete=models.PROTECT, related_name='branch_owner')
class User(AbstractUser):
id = models.UUIDField(
primary_key=True, default=uuid.uuid4, editable=False
)
objects = UserManager()
I want to get all the users of a branch.
I tried to use this queryset:-
User.objects.filter(branchmodel__user=self.request.user)
but it is giving me empty result.
how can i modify this?
I assume you want all branches of user as per your model setup. Below code will gives you all branches of request.user
user=self.request.user
prtnt(user) # to check user in terminal
userbranches=user.branch_owner.all()
I have two type of Users Artist and Customer. so far I have this
in models.py
class User(AbstractBaseUser, PermissionsMixin):
Email = models.EmailField(unique=True)
USERNAME_FIELD = 'Email'
objects = MyUserManager()
class Customers(models.Model):
User = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
CustomerID = models.AutoField(primary_key=True)
class Artists(models.Model):
User = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
ArtistID = models.AutoField(primary_key=True)
I use Email as authentication, and it is good until an Artist wants to be Customer too.
and he/she can't have two accounts one as Customer and another as Artist with the same Email.
here my questions:
Is this way of implementation correct? if not, how to do that?
what is the best way to have a user be Artist and Customer at the same time? Is this have security issues?
I've found that it's usually a bad idea to derive subclasses from Users.
Instead, use a custom user model and add flags for the various roles (and yes, I'm deriving from AbstractUser on purpose; many apps expect .username to be a thing, and you can just always assume username == email):
class User(AbstractUser, PermissionsMixin):
is_customer = models.BooleanField(default=False)
is_artist = models.BooleanField(default=False)
I also suggest looking into an app like django-allauth (which will work with custom user models) to make the whole register/login/password-change/email-confirmation flows easier.
I changed my models a bit and create a OneToOne relation between Artist and Customer:
class User(AbstractBaseUser, PermissionsMixin):
Email = models.EmailField(unique=True)
USERNAME_FIELD = 'Email'
objects = MyUserManager()
class Customers(models.Model):
User = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
CustomerID = models.AutoField(primary_key=True)
class Artists(models.Model):
Customer = models.OneToOneField(Customers, on_delete=models.CASCADE)
ArtistID = models.AutoField(primary_key=True)
I have extended the in built user model in django via AbstractUser. However when it cam to deployment and to create a superuser it failed because of having a null entry in some of the additional fields in the extended model. Is there a way to have these fields not required for a superuser but required for a normal user. (I presume this is a typical use case - as I don't need an admin to fill out address, account number etc...)
models.py
class User(AbstractUser):
title = models.CharField(max_length=255, null=True)
date_of_birth = models.DateField()
phone_number = models.IntegerField(null=True)
account_name = models.CharField(max_length=255)
account_number = models.IntegerField()
house_name_number = models.CharField(max_length=255, verbose_name="house name or number")
street_name = models.CharField(max_length=255)
town_city = models.CharField(max_length=255)
county = models.CharField(max_length=255)
postcode = models.CharField(max_length=8)
Instead of using mandatory fields in models, you have to set them to optional using null=True, blank=True and let the validation happen in forms. For users other than admin create a form that checks for extra fields andvalidate those fields. Render this form through templates at the time of signup/registration. Also instead of using modelforms use forms.Form this will give you a better level of customization. This will make extra fields mandatory for all users other than Admin.