How to set up django user options for generic models - python

I have a Profile model for custom user data:
class Profile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, null=False)
# more stuff...
I also have a Notifications app that allows models to send notifications and emails to users.
I want users to have the option to turn on or off different notifications, but I DON'T want to add a massive list of boolean fields to the Profile like this:
class Profile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, null=False)
send_model1_notice1 = models.BooleanField()
send_model1_email1 = models.BooleanField()
send_model1_notice2 = models.BooleanField()
send_model1_email2 = models.BooleanField()
send_model2_notice1 = models.BooleanField()
send_model2_email1 = models.BooleanField()
send_model3_notice1 = models.BooleanField()
send_model3_email1 = models.BooleanField()
# etc...
where modelx is some model or some other app that is the origin of the notification, and noticex/emailx is some specific cause for notification.
I was thinking a more sustainable way of doing this would be to create a ProfileOptions model that external models could use to define their own notifications settings.
This way, when I add a new app/model, I could link its notification sources to the ProfileOptions model somehow and have these options to turn them on or off magically appear in the user's profile.
Does this make sense? If so, is it possible? If so is it a good idea? and if so, what structure should I use to connect the models, ProfileOptions, and the user's Profile?
Obviously I'm hoping for an answer to the last question, but I don't want to rule out the possibility that the answer to the others might be "no".

One approach would be to have a separate Notification model which links the two:
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
class Notification(models.Model):
# Foreign key to user profile
user = models.ForeignKey(Profile)
# Generic foreign key to whatever model you want.
src_model_content_type = models.ForeignKey(ContentType)
src_model_object_id = models.PositiveIntegerField()
src_model = GenericForeignKey('src_model_content_type', 'src_model_object_id')
# Notification on or off. Alternatively, only store active notifications.
active = models.BooleanField()
This approach would let you handle an arbitrary number of source models for notifications (each with an arbitrary number of notifications), without trying to squeeze all the notification information into your user profile.

Related

What's the best way to create a generic serializer which is able to serialize all the subclasses of the base model in Django Rest Framework?

I'm currently working on a notification system which is going to deliver many different types of notifications through an API.
I have a base notification class called BaseNotification. Here is the code:
class BaseNotification(models.Model):
message = models.CharField(max_length=500)
seen = models.BooleanField(default=True)
class Meta:
abstract = True
And I want to subclass this model to create different variations of notifications:
class InvitationNotification(BaseNotification):
invited_user = models.ForeignKey(User, on_delete=models.CASCADE)
campagin = models.ForeignKey(Campagin, on_delete=models.CASCADE)
# ... the rest of specific fields
class ChatMessageNotification(BaseNotification):
contact = models.ForeignKey(User, on_delete=models.CASCADE)
chat_room = models.ForeignKey(SomeSortOfChatRoomWhichIsNotImplementedYet, on_delete=models.CASCADE)
# ... the rest of specific fields
As you can see, each of those variations, has some meta-data associated with it. The front-end developer would be able to create user interactions using these meta data (for example, in the case of a chat message, the front-end developer would redirect the user to the chat room)
I want to list all of these notifications through one unified API. For that, I need a serializer to serialize the objects as json but I don't want to have a sperate serializer for each. Ideally I want to have a generalized serializer which is capable of serializing all kinds of notifications and generates different json output depending on the type of the notification object passed in. (It might use other serializers under the hood).
Maybe I'm on the wrong track but the end goal is to deliver notifications and all their meta-data through one unified API.
I really need your suggestions and help. Thank you all in advance.
I finally figured it out by myself. My end goal was to provide some metadata for the front-end developer so that he can implement user interactions based on the type of the notification.
I simply solved the problem with a JSONField. That works just fine and that was the only thing I needed.
models.py
class Notification(models.Model):
NEW_MEMBER_JOINED = 'NEW_MEMBER_JOINED'
INVITATION = 'INVITATION'
TEXT = 'TEXT'
NEW_POST_CREATED = 'NEW_POST_CREATED'
NEW_MESSAGE = 'NEW_MESSAGE'
NEW_CAMPAIGN_CONTENT = 'NEW_CAMPAIGN_CONTENT'
NEW_COMMENT = 'NEW_COMMENT'
target = models.ForeignKey(User, on_delete=models.CASCADE, related_name='notifications')
text = models.CharField(max_length=300)
type = models.CharField(max_length=255)
date_created = models.DateTimeField(auto_now_add=True)
seen = models.BooleanField(default=False)
metadata = models.JSONField(null=True, blank=True)
def __str__(self) -> str:
return f"[{self.type}] {self.text}"
serializers.py
class NotificationSerializer(serializers.ModelSerializer):
class Meta:
model = Notification
fields = '__all__'
read_only_fields = [
'text', 'type', 'metadata', 'date_created', 'seen'
]
In my case, this solution works the best.

django model design with different user types

I am just learning Django so I thought of creating a project called job board to understand more in detail. I have drawn the following use case.
People can register as job seekers, build their profiles and look for
jobs matching their skillsets
Companies can register, post jobs.
Multiple representatives from a company should be able to register
and post jobs.
Independent Recruiter can create an account as well.
The company can contact to that independent recruiter.
How would be the model design for such a use case? I am confused with the multiple user types in Django. Some favors creating a user profile, while some favors using Groups.
For now, I could only do the following
class User(AbstractUser):
'''
Abstract user because django recommends to start with custom user
'''
username = None
email = models.EmailField(_("Email Address"), unique=True)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
objects = UserManager()
def __str__(self):
return self.email
class Company(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
I could create a model for User and Company. But I have no idea on handling multiple user types like user can be either job seeker or recruiter. Also, multiple representatives from a company should be able to register and post jobs as well as there can be independent recruiter as well. How would you handle such a case if you have to? Can anyone help me in a step by step guide, please? This way it will clear my confusion and will help me in better design of tables in the future.
Update with example in a nutshell
class User(models.Model):
'''
User can be of any 3 types or can have multiple role as well
'''
is_job_seeker = models.BooleanField(default=False)
is_recruiter = models.BooleanField(default=False)
is_mentor = models.BooleanField(default=False)
class Company(models.Model):
user = models.ForeignKey(User) # only user with is_recruiter flag active can be
class JobSeeker(models.Model):
user = models.OneToOneField(User)
# job seeker profile related fields like experiences, skills, education, profile image etc
class Recruiter(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
company = models.ForeignKey(Company, null=True, blank=True)
# recruiter related profile
Your implementation is almost there. It doesn't look like you need a custom user model right now, so I would just use Django's default.
I would have something like:
from django.conf import settings
from django.db import models
class Company(models.Model):
user = models.OneToOneField(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
)
# Other company-related fields
class JobSeeker(models.Model):
user = models.OneToOneField(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
)
# Other jobseeker-related fields
class Recruiter(models.Model):
user = models.OneToOneField(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
)
company = models.ForeignKey(Company, null=True, blank=True)
# Other recruiter-related fields
When you create any of the models above, you can assign them a user account; and for recruiter, you can assign the company they work for. For example, a company named stack_overflow can have its own company account with a username/password/etc. Then, recruiters who work for stack_overflow could also have their own accounts with their own username/password/etc. Running a command like stackoverflow.recruiter_set will give you all recruiters who work for stack_overflow.
Note that I do not reference User directly. Using the above approach makes your life easier if you decide to switch User models in the future.
I am assuming you don't want to create a User, then create a Company and link it to that user - you just want to do it in one go. That's a slightly different question and the solution will involve you creating a sign-up Form, or something of that sort, where you can add some logic about whether the user is a company, recruiter or jobseeker.
Regarding your other points, it looks like you're looking to set user permissions. Here are the docs for setting default permissions for your custom users, and here are the general docs for Django's built-in permissions system. For example, your Company and Recruiter model could return True for has_perm('your_app.add_job'), while your Jobseeker model returns False. I.e. Companies and Recruiters can create Jobs, but jobseekers cant.
Hope this helps!

Login form for custom users in django

I have created a custom User SignUp Class.
class SignUp(models.Model):
userId = models.CharField(max_length=8, blank=False, unique=True)
Name = models.CharField(max_length=200)
VehicleNumber= models.CharField(max_length=12)
ContactNum = models.IntegerField(default=0)
def __unicode__(self):
return smart_unicode(self.Name)
I have used this to create a Sign up form. Now, I am not getting a way for creating user login. Note: I can't use django in-built users because they don't have a field for images.
You can extend the built-in django user, by adding OneToOneField.
YourCustomUser(models.Model):
user = models.OneToOneField(User,related_name='profile')
image = models.ImageField()
//put here your others attributes
If you have YourCustomUser instance and want to access to User built-in instance
your_custom_instance.user
If you have User built-in instance and want to retrieve e.i the image
user.profile.image
You can use and extend the built-in model User. The shortest path is
from django.contrib.auth.models import User
from django.db import models
class UserWithPhoto(User):
image = models.ImageField()
but is better practice to use User Profiles, you can read about it in: User authentication in Django
You can read about this in Django user profile and here Extending the User model with custom fields in Django.
Why is better user profile over extending the User model directly?
If you extend the User model you will have the changes applied to all you users. Think about this, you could have Administrators, Developers, Reviwers, even Guests, all of them might have some field that others don't, so a different profile for each one is the better solution than subclassing User for each one, or even worst create a single class with all fields you need for all kinds of users (only think about it hurts ).

Django Relating Model to User

I want to relate the Model of the Note in my web app with the user that created it .I guess the relation should be Many-to-One.So that i can then filter data by user.Help my the right code , explain , do you thing this is the right method to use in order to have separate data for each user.I really want your opinion on that.
class Note(models.Model):
title = models.CharField(max_length=200)
body = models.TextField()
cr_date = models.DateTimeField(auto_now_add=True)
owner = models.ForeignKey(........) <----- should be something like that
You can add that as foreign key to user model,
#if you are using user model provided by django contrib
from django.contrib.auth.models import User
class Note(models.Model):
#user other fields
owner = models.ForeignKey(User)

Django Model Design: Registered and Unregistered Users referenced together

Experimenting with django, I am trying to design a site that will reference registered users of the site as well as non-registered users. Trying to figure out how to best design my models for this, I'd like to give the non-registered user the ability to register and have it linked to the information I already have. I've read some other SO questions that are sort of related so I know I should be using a seperate class (registered & non-registered), but how would I reference 2 different models using a one foreign key?
Models.py:
from django.db import models
from django.contrib.auth.models import User
class NonRegisteredPerson(models.Model):
first_name = models.CharField(max_length=20, default='')
last_name = models.CharField(max_length=20, default='')
email = models.EmailField(max_length=20,default='', blank=True)
class Seat(models.Model):
num = models.CharField(max_length=100, blank=True)
# For the Non Registered User
occupant = models.ForeignKey('NonRegisteredPerson')
# For the Registered User - using Built-in User
occupant = models.ForeignKey(User)
How do I get "occupant" to reference NonRegisteredPerson and User?
Don't know if this matters, but the way I would handle if a NonRegisteredUser signs up for the site, is check if their e-mail exists in the NonRegisteredPerson model, if it does then delete them from that model and add to the Built-in User.
I know this must be a common scenario, but I don't know what or where I should be looking up for this. TIA.

Categories

Resources