Extending Django User model with django-allauth - python

I'm using django-allauth and I want to be able to add new field to my User model.
What's the best way to do this as of you ?

I use userena. But I am sure that it will look almost the same ;)
class UserProfile(UserenaBaseProfile):
user = models.OneToOneField(User, unique=True)
city = models.CharField(max_length=32, blank=True, null=True)
in settings.py:
AUTH_PROFILE_MODULE = 'accounts.UserProfile'

See the docs Storing additional information about users, Make a model with OneToOneField relation to User.
from django.contrib.auth.models import User
class UserProfile(models.Model):
# This field is required.
user = models.OneToOneField(User)
# Other fields here
accepted_eula = models.BooleanField()
favorite_animal = models.CharField(max_length=20, default="Dragons.")

Related

Django Multiple-User Model

I need advice on a multiple user type.
Scenario:
A user can be an organization, where in this organization they can place adverts on the website. The owner of this organization(user) can edit/delete users and adverts of his own organization(group). In this organization user type there are users that also can log in and they can only see the adverts placed by them, but the owner of this group must see all adverts of his own and of his users. Think like an estate listing where an organization has multiple locations/users that can place adverts, and has to be managed by a admin user of this organization.
What type or model is the best/cleanest for implementing this in a good way? Do I need the Django's User and Group model?
One solution would be to have the "User Profiles" structure.
So you use the standard Django User Model and you attach to it several OneToOne relationships depending on the number of profile types you'll have. This has the advantage of allowing users to cover more than one role at the same time.
For example:
from django.contrib.auth.models import User
class Organization(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name="organization")
name = models.CharField(max_length=50, blank=True, null=True)
class Supervisor(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name="supervisor")
name = models.CharField(max_length=50, blank=True, null=True)
organization = models.ForeignKey(Organization, on_delete=models.CASCADE, related_name="supervisors")
class CustomUser(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name="custom_user")
name = models.CharField(max_length=50, blank=True, null=True)
supervisor = models.ForeignKey(Supervisor, on_delete=models.CASCADE, related_name="custom_users", blank=True, null=True)
And then when you go and create the models for the ads to be displayed on the website you can use the built-in PermissionRequiredMixin.
In order to do that you have to start by adding "permissions" in the ad model Meta class:
class Ad(models.Model):
# fields
class Meta:
permissions = [
('can_edit_ads', 'org_representative')
]
Then on your view you have to extend the PermissionRequiredMixin, example:
class EditAd(UpdateView, PermissionRequiredMixin):
model = Ad
template_name = "ad123.html"
permission_required = "ad.can_edit_ads"
A quick way to test it is by going in the user table on the admin panel, open a user detail page where you can see all the permissions, and there alongside the others you'll find your custom one as well.
From there you can easily assign the new permission to the specific user.

Override django user with AUTH_USER_MODEL

I have override the default User model in my app with AUTH_USER_MODEL.
Here is the user model I want to use in my app, which is tied closely to a legacy database:
from django.contrib.auth.models import AbstractUser
from django.db import models
class User(AbstractUser):
name = models.CharField(max_length=128, blank=True)
email = models.EmailField(unique=True)
password = models.CharField(max_length=128)
is_active = models.BooleanField(default=True)
is_admin = models.BooleanField(default=False)
date_joined = models.DateTimeField(default=timezone.now)
normalized_email = models.EmailField(unique=True)
However, django complains that fields such as first_name, last_name, etc. are not provided. Is there a way to remove some of the existing fields in the User model? Or does specifying a custom user model only allow you to add additional fields on top of that? Is there a simple way to delete them, or do I basically have to add those fields (and ignore them) to our existing database in order to be able to use django with it?
AbstractUser is for when you want to add additional fields to Django's defaults. Use AbstractBaseUser if you don't want all those fields.

Django relations between Models

What I currently have in my models is this:
class Project(models.Model):
project_name = models.CharField(max_length=255, unique=True, blank=False)
def __str__(self):
return str(self.project_name)
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
role = models.CharField(choices=ROLE_CHOICES, max_length=255, default='Agent')
Now my question is: Users should be able to have multiple Projects - so I obviously can't use a OneToOne-Field in the Profile-Model.
Later I want to use it for example to just show a user news which are only related to the projects he participates in.
What would be the best strategy to make this possible? Any input is highly appreciated.
Use ManyToMany on project.
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
role = models.CharField(choices=ROLE_CHOICES, max_length=255, default='Agent')
project = models.ManyToManyField(Project)
This way one profile can have as many project as he/she wants
On your view you can use this field to filter based on project

Django request.user is model, for admin and normal user

I want to autocomplete 2 fields:
created_by = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='created_by')
updated_by = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='updated_by')
for normal users and for django admin.
If for normal users I can use get request.user from my view(found some solutions here on the site),but this is not the case for admin/staff because I don't control the views, so I'm searching for a solution at the Model level by overwriting the save function.
from django.contrib.auth.models import User
created_by = models.ForeignKey(User, related_name='created_by')
updated_by = models.ForeignKey(User, related_name='updated_by')
Then in your view, you can do this :
form.created_by = request.user
form.updated_by = request.user
It's going to autocomplete by the current user who made the action.
May be I didn't understant your question, so may be this is what you're looking for : How to auto insert the current user when creating an object in django admin?
May be the solution with default user by Middleware help you.
django-populate-user-id-when-saving-a-model
is pretty simple, just add to your field: editable=False
Like this:
created_by = models.ForeignKey(settings.AUTH_USER_MODEL, editable=False, related_name='created_by')

Django REST Framework: change field names

My Django application provides readonly api access to the users of the site. I created a user profile model and use it in the serializer of the user model:
Model:
# + standard User Model
class UserProfile(models.Model):
user = models.ForeignKey(User, unique=True)
display_name = models.CharField(max_length=20, blank=True)
Serializer:
class UserProfileSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = UserProfile
fields = ('display_name',)
class UserSerializer(serializers.HyperlinkedModelSerializer):
userprofile_set = UserProfileSerializer(many=False, label='userprofile')
class Meta:
model = User
fields = ('id', 'username', 'userprofile_set')
This works but the field userprofile_set looks ugly. Is it possible to change the field name?
To complement your answer, you can also make use of relationships' related names:
class UserProfile(models.Model):
user = models.ForeignKey(User, unique=True, related_name='profiles')
display_name = models.CharField(max_length=20, blank=True)
that way you can also use this in your code:
user = User.objects.last() #some user
user.profiles.all() #UserProfiles related to this user, in a queryset
user.profiles.last() #the last UserProfile instance related to this user.
May I recommend that you turn that ForeignKey into a OneToOneField? that way an user can have one and just one user profile, and you don't need to establish uniqueness:
class UserProfile(models.Model):
user = models.OneToOneField(User, related_name='profile')
display_name = models.CharField(max_length=20, blank=True)
Oh, I can name the variable userprofile_set as I like. First I tested the name userprofile which conflicted. If I name the field profile it works. :)
class UserSerializer(serializers.HyperlinkedModelSerializer):
profile = UserProfileSerializer(many=False, label='userprofile')
class Meta:
model = User
fields = ('id', 'username', 'profile')

Categories