Permissions from 2 django projects are merged. How to separate them? - django

Good day to all)
I created a custom user model with custom permissions. I have several projects and their permissions merged into one table('auth_permission'). Is it possible to somehow customize the table itself for these permissions to separate projects?(like db_table = '"schema"."table"' to the models.).Google did not give answers.
class TestUser(AbstractUser):
phone = PhoneNumberField(null=False, blank=False, unique=True)
email = CharField(unique=True, max_length=35, null=False, blank=False)
class Meta:
db_table = '"fyzzys"."users"'
permissions = [
("can_see_payments", "payments"),
("can_see_analytics", "analytics"),
]
UPD: Here is a screenshot that shows the permissions of two completely different projects at the same time from admin panel.

In order to give a user permissions, you will want to add the PermissionsMixin to the User model like so.
class TestUser(AbstractBaseUser, PermissionsMixin):
If you are using the AbstractUser you are actually already inheriting the PermissionsMixin.
The permissionmixin is a model within django.contrib.auth.models. It adds to the user model the following fields (columns in the user table); is_superuser, groups, user_permissions. The permissions mixin allows you to add (and remove) 0..*(many) individual or group permissions to a user.
To add permissions to a user you can then use.
from django.contrib.auth.models import Permission
# The permission needs to exist first.
permission = Permission.objects.get(name='Can view poll')
u.user_permissions.add(permission)
The code for for the django.contrib.auth.models.permissionsmixin can be found following the link.

Related

Can I implement separate user authentication and models for two apps in django project?

In this django project I have two separate applications that I need to keep user account information separate. For example, if a person creates an account for app A, I need them to be able to make a separate account (with the possibility of using the same unique email for account creation) for app B. At this moment in time, it seems as though there is no way for me to handle having two separate auth models for two separate users. I am wondering what the django workaround for this might be, or if I am misunderstanding the problem in some way?
Here is an example user model that would work for both application A and B, but would need separate tables or models for authentication and account creation:
class GenericUser(AbstractUser):
"""abstract user class for user authentication"""
firstname = models.CharField('First Name', blank=True, max_length=100)
lastname = models.CharField('Last Name', blank=True, max_length=100)
email = models.CharField('Email', unique=True, max_length=100)
class Meta:
permissions = (
("some-permission", "some-description"),
)
First I tried creating two separate user entities in the models.py file in my django project, however when I finished doing this, there was nowhere to put the second user model in the settings.py folder. This is where I am stuck now.
May be you are looking for this .. django support multiple authentication model. in order to do this you need to create a custom authentication backend by inherit from 'django.contrib.auth.backends.BaseBackend' (you can specify different user model there, I think ) and specify the authentication model in the settings.py of the project.
For more information. check this doc

Unsure of approach for Django custom user groups and permissions

I am creating my first Django (ver 3.1) website which is simply a blog with a home page and store page. I want to create custom user groups that define specific roles (with unique permissions) for my blog.
These groups are:
Reader - anonymous viewers and new accounts; has read permission for all content only
Author - login required; has read and create permissions; edit and delete permissions for own content only
Moderator - login required; has all CRUD permissions for all content
Admin - login required, has all permissions (superuser)
All new users by default are in the Reader group. Author would either be assigned manually or eventually by an online form application to determine eligibility. Moderator and Admin would of course be manually assigned.
I am approaching this with possible future development, such as allowing user groups to be easily extended to other website pages. For example, a 5% discount for Author users applied to all store items, etc.
Which approach to creating user groups would be best for my situation? I have seen it done within the Django Admin Panel and by creating custom User Models via extending the AbstractBaseUser and UserBaseManager classes.
I think extending the AbstractUser model is a good approach. How about something like this?
class CustomUser(AbstractUser):
"Define the extra fields related to User here"""
first_name = models.CharField(_('First Name of User'), blank=True, max_length=20)
last_name = models.CharField(_('Last Name of User'), blank=True, max_length=20)
#  - - - Some more User fields according to your need s
class Meta:
permissions = (("can_read_content", "To provide read facility on all content"),
#---------------------
)

Rename django custom permissions

I'm working with django 2.0 app and going to update django version to 3.0.
But in my project there are few custom permissions named like view_modelname.
class MyConcreteModel(models.Model):
model_field_1 = models.CharField(max_length=100, blank=False)
# other fields
class Meta:
permissions = (
("view_myconcretemodel", "Can see available device interfaces"),
)
In django 3 (since v 2.1) such kind of permissions are default. So I got conflict with permission names.
Now I'm trying to rename custom permissions before updating django version.
class MyConcreteModel(models.Model):
model_field_1 = models.CharField(max_length=100, blank=False)
# other fields
class Meta:
permissions = (
("user_view_myconcretemodel", "User can see available device interfaces"),
)
After migration 'new' (with new names) permissions were created in DB. But old permissions still there and all users have old permissions (with old names like view_myconcretemodel). Obviously I need 'new' permissions for all users.
Is there possibility simple to rename permissions or give 'new' permissions to relevant users (according to 'old' permissions), and do it automatically?
After reading how to Programmatically creating permissions https://docs.djangoproject.com/en/3.2/topics/auth/default/#programmatically-creating-permissions
My solution is to modify codename in Permission model. i.e.
from django.contrib.auth.models import Permission
perm = Permission.objects.get(codename="view_myconcretemodel") #old name
perm.codename = "user_view_myconcretemodel" #new name
perm.save()

Django Form save - circular dependency

I have 2 models Account and User. An Account can have multiple users.
When the first User(Owner) is created at the same time the Account will be created.
Because User have a ForeignKey to Account, I need first to create the Account, and after the User.
But Account had a field created_by which is request.user. So is a circular problem.
I think I need to create first the Account and created_by to be a superuser(first) and than create the User, and update the Account with the new user.
class Account(MetaData):
name = models.CharField(max_length=255)
created_by = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True,
related_name='%(app_label)s_%(class)s_created_by', on_delete=models.CASCADE)
class User(AbstractBaseUser):
account = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True, null=True, related_name='owner')
How can I do that ?
I need this only first time, for the first user, because after that for the other users the Account will exist.
When I'm saying first user, I'm not referring to staff users (as superusers), but normal users for which an account is mandatory thru a register form.
blank=True is just for staff members.
Your User model's account field allows nulls, so nothing prevents you from first creating the user without an account, then creating the account with this user, and finally updating the user with the account:
with transaction.atomic():
user = User.objects.create(account=None, ...)
account = Account.objects.create("test", created_by=user)
user.account = account
user.save(update_fields=["account"])
Since it's only a problem for the first user, you might want to override the method create_superuser of the manager to add the account. Also, since you've defined the ForeignKeys with null=True, it should not be a problem to first create a superuser (using super().create_superuser()) and then create the account and attach it to the superuser.
When deploying your site the first time, you'll have to manually run the ./manage.py createsuperuser command.

Django - Multiple User Profiles

Initially, I started my UserProfile like this:
from django.db import models
from django.contrib.auth.models import User
class UserProfile(models.Model):
user = models.OneToOneField(User)
verified = models.BooleanField()
mobile = models.CharField(max_length=32)
def __unicode__(self):
return self.user.email
Which works nicely along with AUTH_PROFILE_MODULE = 'accounts.UserProfile' set in settings.py.
However, I have two different kinds of users in my website, Individuals and Corporate, each having their own unique attributes. For instance, I would want my Individual users to have a single user only, hence having user = models.OneToOneField(User), and for Corporate I would want them to have multiple users related to the same profile, so I would have user = models.ForeignKey(User) instead.
So I thought about segregating the model into two different models, IndivProfile and CorpProfile, both inheriting from UserProfile while moving the model-specific attributes into the relevant sub-models. Seems like a good idea to me and would probably work, however I would not be able to specify AUTH_PROFILE_MODULE this way since I'm having two user profiles that would be different for different users.
I also thought about doing it the other way around, having UserProfile inherit from multiple classes (models), something like this:
class UserProfile(IndivProfile, CorpProfile):
# some field
def __unicode__(self):
return self.user.email
This way I would set AUTH_PROFILE_MODULE = 'accounts.UserProfile' and solve its problem. But that doesn't look like it's going to work, since inheritance in python works from left to right and all the variables in IndivProfile will be dominant.
Sure I can always have one single model with IndivProfile and CorpProfile variables all mixed in together and then I would use the required ones where necessary. But that is just doesn't look clean to me, I would rather have them segregated and use the appropriate model in the appropriate place.
Any suggestions of a clean way of doing this?
You can do this in following way. Have a profile which will contains common fields which are necessary in both profiles. And you have already done this by creating class UserProfile.
class UserProfile(models.Model):
user = models.ForeignKey(User)
# Some common fields here, which are shared among both corporate and individual profiles
class CorporateUser(models.Model):
profile = models.ForeignKey(UserProfile)
# Corporate fields here
class Meta:
db_table = 'corporate_user'
class IndividualUser(models.Model):
profile = models.ForeignKey(UserProfile)
# Individual user fields here
class Meta:
db_table = 'individual_user'
There is no rocket science involved here. Just have a keyword which will distinguish between corporate profile or individual profile. E.g. Consider that the user is signing up. Then have a field on form which will differentiate whether the user is signing up for corporate or not. And Use that keyword(request parameter) to save the user in respective model.
Then later on when ever you want to check that the profile of user is corporate or individual you can check it by writing a small function.
def is_corporate_profile(profile):
try:
profile.corporate_user
return True
except CorporateUser.DoesNotExist:
return False
# If there is no corporate profile is associated with main profile then it will raise `DoesNotExist` exception and it means its individual profile
# You can use this function as a template function also to use in template
{% if profile|is_corporate_profile %}
Hope this will lead you some where. Thanks!
I have done it this way.
PROFILE_TYPES = (
(u'INDV', 'Individual'),
(u'CORP', 'Corporate'),
)
# used just to define the relation between User and Profile
class UserProfile(models.Model):
user = models.ForeignKey(User)
profile = models.ForeignKey('Profile')
type = models.CharField(choices=PROFILE_TYPES, max_length=16)
# common fields reside here
class Profile(models.Model):
verified = models.BooleanField(default=False)
I ended up using an intermediate table to reflect the relation between two abstract models, User which is already defined in Django, and my Profile model. In case of having attributes that are not common, I will create a new model and relate it to Profile.
Could be worth to try using a through field. The idea behind it is to use the UserProfile model as through model for the CorpProfile or IndivProfile models. That way it is being created as soon as a Corp or Indiv Profile is linked to a user:
from django.db import models
from django.contrib.auth.models import User
class UserProfile(models.Model):
user = models.ForeignKey(User)
profile = models.ForeignKey(Profile, related_name='special_profile')
class Profile(models.Model):
common_property=something
class CorpProfile(Profile):
user=models.ForeignKey(User, through=UserProfile)
corp_property1=someproperty1
corp_property2=someproperty2
class IndivProfile(Profile):
user=models.ForeignKey(User, through=UserProfile, unique=true)
indiv_property1=something
indiv_property2=something
I think that way it should be possible to set AUTH_PROFILE_MODULE = 'accounts.UserProfile', and every time you create either a CorpProfile or a IndivProfile that is linked to a real user a unique UserProfile model is created. You can then access that with db queries or whatever you want.
I haven't tested this, so no guarantees. It may be a little bit hacky, but on the other side i find the idea quite appealing. :)