I am using the default User model, and created a custom model called Team. A user can only be on one team, but a team can have many users. Therefore, I must create the ForeignKey field within the User model.
The thing is, I'm using the default User by simply importing User with from django.contrib.auth.models import User
What is the easiest way of adding a ForeignKey field into the default User model? Do I have to extend the default User model?
Or is there a way for me to add a ForeignKey field into Team, and swap the relationship between User and Team?
Honestly when you are working with the default Django user model, it's always better to create a custom user model that you can modify easier. Below is a simple example on how you can modify your User class with the AbtractBaseUser. If you'd like to add a foreign key just use ForeignKey instead of the data types below.
from __future__ import unicode_literals
from django.utils import timezone
from django.contrib.auth.models import (AbstractBaseUser,PermissionsMixin)
from django.db import models
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(unique=True)
username = models.CharField(max_length=7, unique=True)
formattedusername = models.CharField(max_length=11, unique=True, primary_key = True)
first_name = models.CharField(max_length=40)
last_name = models.CharField(max_length=140)
date_joined = models.DateTimeField(default=timezone.now)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
facility = models.CharField(max_length=140)
jobdescription = models.CharField(max_length=140)
positiondescription = models.CharField(max_length=140)
coid = models.CharField(max_length=5)
streetaddress = models.CharField(max_length=140)
USERNAME_FIELD = 'username'
class Meta:
app_label = 'accounts'
db_table = "user"
# REQUIRED_FIELDS = "username"
def __str__(self):
return "#{}".format(self.username)
In my opinion, the best way of achieving what you want is to use an in-between table. Therefore, you would create your Team model as normal and then create another model with two foreign keys to both User and Team. This is an example, it may change, feel free to change it to your needs.
class Group(models.Model):
group = models.ForeignKey(User, on_delete=models.CASCADE)
group = models.ForeignKey(Team, on_delete=models.CASCADE)
class Team (models.Model):
group = models.ForeignKey(Group, on_delete=models.CASCADE)
#your other fields
Related
I have multiple types of user in my django app: Employee and Patient. They have fields that are specific to each of them. They are implemented using the AbstractBaseUser model as below:
from django.db import models
from django.contrib.auth.models import AbstractBaseUser
class User(AbstractBaseUser):
username = models.CharField(max_length=40, unique=True)
USERNAME_FIELD = 'identifier'
first_name = models.CharField(
max_length=50, null=False, blank=False)
last_name = models.CharField(
max_length=50, null=False, blank=False)
date_of_birth = models.DateField(null=False, blank=False)
USER_TYPE_CHOICES = (
(1, 'Patient'),
(2, 'Employee'),
)
user_type = models.PositiveSmallIntegerField(
choices=USER_TYPE_CHOICES, default=1, blank=False, null=False)
class Role(models.Model):
RoleName = models.CharField(max_length=50, null=False, blank=False)
class Employee(models.Model):
user = models.OneToOneField(
User, on_delete=models.CASCADE, primary_key=True)
employment_start_date = models.DateField(null=False, blank=True)
employment_end_date = models.DateField(null=False, blank=True)
role = models.ForeignKey(
Role, on_delete=models.CASCADE, related_name='assigned_employees')
class Patient(models.Model):
user = models.OneToOneField(
User, on_delete=models.CASCADE, primary_key=True)
I have a few questions with how to go forward with this:
How does just the choice in the User class limit the fields that a user has access to? If I had a HTML page would I create an Employee then a User would be created, or the other way round?
When I'm using Django Rest Framework, how can I implement a sign up and log in with the two different types?
I'm struggling to understand how this would work conceptually. Is like Employee and Patient a subclass of User? Or are they separate models? Any help or advice would be greatly appreciated
In your code you don't have two types of User. You have only one type - class User(AbstractBaseUser). Employee and Patient are normal models that are only related to User.
If you wanted to create two types of User with actual inheritence, then you should do following:
class AbstractUser(AbstractBaseUser):
class Meta:
abstract = True
# main user fields here
class Employee(AbstractUser):
# employee fields here
class Patient(AbstractUser):
# patient fields here
If you don't want to do this, your current approach is good. You can simply authenticate User in standard way. During creation you can make seperate forms for registering employee User, that creates automatically related Employee class. Similar for Patient. They will share only fields of User class with either approach.
To authenticate in different ways you can use custom authentication with authenticate() function. Read specifics in Django Docs
I am trying to create a database schema for a simple Visitor Management System where I am creating two models named Visitor and Host by extending the inbuilt User model in Django. The model Appointment is for mapping the relation between the Visitor and Host with their meeting time slot. However, I am getting the 'demoapp.Appointment.host_email' refers to field 'email' which is not local to model 'demoapp.Host' error mentioned in the title when I run python manage.py makemigrations. Why am I getting this, how can I fix it and is there a better way to do it?
from django.db import models
from django.contrib.auth.models import User
from django.utils import timezone
from django.core.validators import RegexValidator
class Host(User):
class Meta:
verbose_name = "Host"
verbose_name_plural = "Hosts"
phone = models.CharField(verbose_name='Phone Number',max_length=10, validators=[RegexValidator(regex='[0-9]{10}')], unique=True, null=True)
class Visitor(User):
class Meta:
verbose_name = "Visitor"
verbose_name_plural = "Visitors"
phone = models.CharField(verbose_name='Phone Number',max_length=10, validators=[RegexValidator(regex='[0-9]{10}')], unique=True, null=True)
purpose = models.CharField(verbose_name='Purpose of meeting', max_length=150, null=True)
class Appointment(models.Model):
host_email = models.ForeignKey(Host, to_field='email', on_delete=models.CASCADE, verbose_name='Host Email')
visitor_email = models.ForeignKey(Visitor, to_field='email', on_delete=models.CASCADE, verbose_name='Visitor Email')
slot = models.DateField(verbose_name='Appointment Slot', default=timezone.now)
is_confirmed = models.BooleanField(verbose_name='Booking Confirmed', default=False)
Why are you specifying to_field in your foreign key? I think you may be misusing it. See the docs. You probably just want to leave that option off, and let Django use the primary key (id) of Host.
If you do mean to use it, you need an email attribute of your model Host. That is what the error is telling you. You'll also need to make this unique if you're going to use it as the field for your ForeignKey.
from django.db import models
from django.contrib.auth.models import User
from django.utils import timezone
from django.core.validators import RegexValidator
class Host(User):
class Meta:
verbose_name = "Host"
verbose_name_plural = "Hosts"
phone = models.CharField(verbose_name='Phone Number',max_length=10, validators=[RegexValidator(regex='[0-9]{10}')], unique=True, null=True)
email = models.EmailField(unique=True) # You're missing this
class Visitor(User):
class Meta:
verbose_name = "Visitor"
verbose_name_plural = "Visitors"
phone = models.CharField(verbose_name='Phone Number',max_length=10, validators=[RegexValidator(regex='[0-9]{10}')], unique=True, null=True)
purpose = models.CharField(verbose_name='Purpose of meeting', max_length=150, null=True)
class Appointment(models.Model):
host_email = models.ForeignKey(Host, to_field='email', on_delete=models.CASCADE, verbose_name='Host Email')
visitor_email = models.ForeignKey(Visitor, to_field='email', on_delete=models.CASCADE, verbose_name='Visitor Email')
slot = models.DateField(verbose_name='Appointment Slot', default=timezone.now)
is_confirmed = models.BooleanField(verbose_name='Booking Confirmed', default=False)
Let's say I have a two models:
class Member(models.Model):
nickname = models.CharField(max_length=128)
email = models.EmailField()
avatar = models.ImageField(upload_to='photos/')
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def __str__(self):
return f'Member {self.nickname}'
class Dashboard(models.Model):
title = models.CharField(max_length=128)
owner = models.ForeignKey(Member, on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
Here I create a distinct model for tracking members who can edit dashboards. Can I use Django users for that instead, avoiding creation of my own models?
Yes, you can.
Just use settings.AUTH_USER_MODEL as your related reference as,
from django.conf import settings
class Dashboard(models.Model):
owner = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
# rest of your models
Note: You can also import the built-in User model from django.contrib.auth.models as #ruddra mentioned, But, there will be errors if you were already extended the auth model.
I want to add some extra fields to my user model and I read custom user model with inherit from abstractuser class but when I implement user model Django username field and etc was gone.
A solution is use another model like profile but I want add extra fields to Django user model. Is this possible?
You can use a custom User model:
from django.contrib.auth.models import AbstractUser
class User(AbstractUser):
"""
Custom User Model
"""
TIMEZONES = tuple(zip(pytz.all_timezones, pytz.all_timezones))
username = models.CharField(max_length=255, unique=True)
full_name = models.CharField(max_length=255, blank=True, null=True)
email = models.CharField(max_length=255, unique=True)
image = models.ImageField(upload_to=get_image_path, blank=True, null=True)
timezone = models.CharField(max_length=32, choices=TIMEZONES, default="UTC")
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
USERNAME_FIELD = "email"
REQUIRED_FIELDS = ["username"]
def __str__(self):
return self.email
You will have to register your custom model in the settings.py file:
# Registering the Custom User Model
AUTH_USER_MODEL = 'my_app.User'
In Django i have created a model which use USER model data
this holds all user id form database, BUT i it filtered by certain group
userId = models.ForeignKey(User, on_delete=models.CASCADE)
model.py
**from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class Review(models.Model):
userId = models.ForeignKey(User, on_delete=models.CASCADE)
name = models.CharField(max_length=100, blank=True)
reviewText = models.TextField(max_length=500, blank=False)
timeStamp = models.DateTimeField(auto_now_add=True, auto_now=False)
def __unicode__(self):#for python <2
return self.name
def __str__(self):#for python 3
return self.name**
form displayed(with all user_id)
If you want to filter foreign key choices, you can use limit_choices_to in your model field like this:
class Review(models.Model):
userId = models.ForeignKey(User, limit_choices_to={'groups__name': 'Your Group Name'}, on_delete=models.CASCADE)