I am developing a Django application that only uses Django Admin as the only way to create new user.
I need to create roles or groups for the users and each user should have only one group. For each group I will add the necessary permissions.
The problem is, that the Groups from Django are written on a ManyToMany relationship and I need to override it to a ForeignKey.
How to achieve it?
user.py:
from django.db import models
from django.contrib.auth.models import AbstractUser, Group
from django.utils.translation import gettext_lazy as _
from api_auth.models.user_manager import UserManager
class User(AbstractUser):
username = None
email = models.EmailField(_('email address'), unique=True)
name = models.CharField(_("name"), max_length=150, blank=True)
organisation = models.ForeignKey('api_orgs.Organisation', on_delete=models.PROTECT,
verbose_name=("Organisation"), blank=True, null=True)
welcome_email_sent = models.BooleanField(('welcome email'), default=False)
is_staff = models.BooleanField(
_("staff status"),
default=True,
help_text=_("Designates whether the user can log into this admin site."),
)
objects = UserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['name']
Related
I am trying to migrate, and view the admin page. both makemigrations and migrate passed, yet when i go to the admin url it reads this: "django.db.utils.OperationalError: no such column: social_app_user.id"
And once i create an id field, it changes to "django.db.utils.OperationalError: no such column: social_app_user.password"
I was under the impression that the AbstractUser model included all the default user fields, not sure about the primary key, but regardless.
Please help, thanks!
Note: the 'id' field in this models.py file was added after i got the error.
from django.contrib.auth.models import AbstractUser, UserManager
from django.db import models
class User(AbstractUser):
is_verified = models.BooleanField(default=True)
id= models.AutoField(primary_key=True, null=False)
REQUIRED_FIELDS = []
objects = UserManager()
def __str__(self):
f"{self.username} {self.email}"
return
class main_feed(models.Model):
content= models.CharField(unique=True, max_length=255, default='', null=False)
poster = models.ForeignKey('User', related_name='author', on_delete=models.CASCADE, to_field='username')
likes = models.IntegerField(default=0, null=False)
favorites = models.IntegerField(default=0, null=False)
date_posted = models.DateTimeField(auto_now=True)
def __str__(self):
f"{self.content} {self.likes} {self.poster} {self.date_posted}"
return
It turns out I had to restart my entire application and run startapp again.
This time i added the user model and set up the settings and admin file BEFORE the very first migration. then everything works dandy. But I have no idea why this is the case, shouldnt the migration update and override the default user model?
anyways the question is answered now.
I have custom user model:
class User(AbstractUser):
"""
Our own User model. Made by overriding Django's own AbstractUser model.
We need to define this as the main user model in settings.py with
variable AUTH_USER_MODEL *IMPORTANT*
"""
is_admin = models.BooleanField(default=False)
is_staff = models.BooleanField(default=False)
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
email = models.EmailField(
max_length=255,
unique=True,
verbose_name="email address"
)
institute = models.ForeignKey(
Institute, on_delete=models.SET_NULL, null=True)
objects = MyUserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
def __str__(self):
return self.email
I have two users in my projects. One is the super admin and the other is the admin. I've specified the model for admin as such:
class AdminUser(User):
is_admin = False
is_staff = True
def __str__(self):
return self.first_name+" "+self.last_name
# Control model features
class Meta:
verbose_name = 'Admin User'
verbose_name_plural = 'Admin Users'
Now I want to revoke access of the entire user model from this Admin User. How could this be achieved? We are going to have many more user types in future. They will be specified through models.
You can achieve this by just using groups in Django.
Your superuser will be you, that will have all permissions for default using the field is_admin=True. The second user can be a simple Staff user that is member of the group "Admins", just create the group and assign all the permissions to that group except the permissions to Add, Change and Delete users.
That will do the trick.
Update: If you need more complex cases, you can use the app django-groups-manager or django-guardian So you can create groups in trees, there you can use more domain driven permission rules.**
This question already has an answer here:
How to query related models in django models.py
(1 answer)
Closed 3 years ago.
I have a model called StudentProfile:
class StudentProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True)
class_advisor = models.CharField(max_length=50)
year = models.OneToOneField(YearLevel, on_delete=models.SET_NULL, null=True)
section = models.OneToOneField(Section, on_delete=models.SET_NULL, null=True)
what I want to happen is, class_advisor to only return and accpet User with is_teacher = True.
by the way here's my User model:
class User(AbstractUser):
email = models.EmailField(
max_length=254,
unique=True,
verbose_name='Email Address',
blank=True
)
is_student = models.BooleanField(default=False, verbose_name='Student')
is_superuser = models.BooleanField(default=False, verbose_name='Administrator')
is_teacher = models.BooleanField(default=False, verbose_name='Teacher')
is_staff = models.BooleanField(default=False, verbose_name='Staff')
is_registrar = models.BooleanField(default=False, verbose_name='Registrar')
Yes, however at the moment, something is wrong with your modeling. You should make class_advisor a ForeignKey to the user model. Imagine that you store the username (or whatever unique attribute of that user) in your model. If later that teacher changes that username, then it will refer to a non-existing user, or later to a different user that picked the username.
You can set the limit_choices_to=... parameter [Django-doc]:
from django.db.models import Q
from django.contrib.auth import get_user_model
class StudentProfile(models.Model):
user = models.OneToOneField(get_user_model(), on_delete=models.CASCADE, primary_key=True, related_name='studentprofile')
class_advisor = models.ForeignKey(get_user_model(), limit_choices_to=Q(is_teacher=True), related_name='students')
year = models.OneToOneField(YearLevel, on_delete=models.SET_NULL, null=True)
section = models.OneToOneField(Section, on_delete=models.SET_NULL, null=True)
If you use forms, etc. It will limit the options to Users that are teachers, and do validation on this.
It is better to use get_user_model() [Django-doc] here to refer to your user model, since if you later alter it, the ForeignKey (and OneToOneField will refer to the new model).
Try this:
StudentProfile.objects.filter(user__is_teacher=True)
StudentProfile.objects.filter(user__is_teacher=True).values('class_advisor')
I'm working on an application in the saas model (django 2.1). I use the django tenants plugin (https://github.com/tomturner/django-tenants).
My problem is to display all tenants in the "public" schema. In such a way as to see how much each tenant has users, to be able to manage them, etc.
Is it a good architectural solution to put a foreign key into Tenant in the User model and save this column during the registration process?
Is there another way to do it?
Below is example, pseudo code:
class Tenant(TenantMixin):
name = models.CharField(_('Name of company'), max_length=50, unique=True)
on_trial = models.BooleanField(default=True)
paid_until = models.DateTimeField()
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
auto_create_schema = True
def __str__(self):
return self.name
def get_name(self):
return self.name
class Domain(DomainMixin):
pass
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(_('Email address'), unique=True)
first_name = models.CharField(_('First name'), max_length=60, blank=True)
last_name = models.CharField(_('Last name'), max_length=60, blank=True)
member_of_company = models.ForeignKey(Tenant, on_delete=models.CASCADE, related_name='users', null=True, blank=True)
You can iterate over your tenants and get the Users for each tenant with the following code:
from django.db import connection
from django.contrib.auth import get_user_model
from tenant_schemas.utils import get_tenant_model
UserModel = get_user_model()
TenantModel = get_tenant_model()
for tenant in TenantModel.objects.all():
connection.set_tenant(tenant)
tenant_users = UserModel.objects.all()
# Do whatever you want with your users
I have followed these [1,2,3] links to create a custom user model by extending AbstractBaseUser class. I am storing login information of three type of users lets say teacher, Admin and students in this table. USERNAME field is emailId.
I want to make emailId unique among one type of users. In other words, in my system student can register as teacher as well with same emailId. But since emailId is USERNAME field and hence unique, I am unable to achieve this.
Please suggest how can I do this in Django application.
UserModel :
class UserModel(AbstractBaseUser):
user_type_choices = (
(constants.USER_TYPE_ADMIN, 'Admin'),
(constants.USER_TYPE_INSTITUTE, 'Institute'),
(constants.USER_TYPE_STUDENT, 'Student')
)
sys_id = models.AutoField(primary_key=True, blank=True)
name = models.CharField(max_length=127, null=False, blank=False)
email = models.EmailField(max_length=127, unique=True, null=False, blank=False)
mobile = models.CharField(max_length=10, unique=True, null=False, blank=False)
user_type = models.PositiveSmallIntegerField(choices=user_type_choices, null=False, blank=True)
is_staff = models.BooleanField()
is_active = models.BooleanField(default=True)
objects = MyUserManager()
USERNAME_FIELD = "email"
REQUIRED_FIELDS = ['name', 'mobile', 'user_type','is_staff']
I am using other models like StudentsDetails, TeacherDetails with foreign key to UserModel to store extra information.