Querying Parent from the foreign key django - django

I have the following models :
class CustomUser(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(unique=True)
first_name = models.CharField(max_length=32)
last_name = models.CharField(max_length=32)
is_staff = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
date_joined = models.DateTimeField(default=timezone.now)
USERNAME_FIELD = 'email' # unique identifier, changed to email (default was username)
REQUIRED_FIELDS = ['first_name', 'last_name']
objects = CustomUserManager() # custom manager for interacting with database
def __str__(self):
return self.email
class Refer(models.Model) :
referred_by = models.ForeignKey(CustomUser, on_delete=models.CASCADE, default='admin', related_name='referred_by')
referrals = models.ManyToManyField(CustomUser, related_name='referrals', blank=True)
unique_ref_id = models.CharField(max_length=8, blank=True, default=generate())
def __str__(self) :
return f'Referred By: {self.referred_by}'
I want to implement referral system using this, I have unique_for_id field (example 'exbvagtl'), how can i create new referral under that user?
Something like : Refer.objects.create(referred_by= CustomUser.objects.get(Refer__unique_ref_id='exbvagtl'))
Better model designs, resources and improvements are heavily welcomed!

I think you are overcomplicating things. By making a Refer object that has a ForeignKey to CustomUser, this means that each CustomUser can have zero, one or more Refer objects. While that is not impossible to manage, it makes it harder, since now your views will need to make sure you are working with the correct Refer object, or have to "concatenate" these. Furthermore it means that a CustomUser can have multiple unique_ref_ids.
The question is why we need such object in the first place. You can simply construct a unique_ref_id on the CustomUser object, and add a ForeignKey to 'self' that specifies what the referring person was:
class CustomUser(PermissionsMixin, AbstractBaseUser):
email = models.EmailField(unique=True)
first_name = models.CharField(max_length=32)
last_name = models.CharField(max_length=32)
is_staff = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
date_joined = models.DateTimeField(auto_now_add=True)
unique_ref_id = models.CharField(max_length=8, blank=True, default=generate)
referred_by = models.ForeignKey(
'self',
related_name='referrals',
null=True,
default=None,
on_delete=models.SET_NULL
)
USERNAME_FIELD = 'email' # unique identifier, changed to email (default was username)
REQUIRED_FIELDS = ['first_name', 'last_name']
objects = CustomUserManager() # custom manager for interacting with database
def __str__(self):
return self.email
Here we thus can add a user that was referred to by another user with:
CustomUser.objects.create(referred_by_id=id_of_referred_user)
If later the referred_by user is removed, then it will be set to NULL.
You can also query the users that have been referred by a user with:
myuser.referrals.all()

The problem is coming from your design of the referral system. Usually, in a referral system, one user has one referral_id. But your design suggests that one user can have multiple referral_ids.
I will suggest you move the unique_ref_id to the CustomUser model. That way you can do something like this:
Refer.objects.create(referred_by=CustomUser.objects.get(unique_ref_id="exbvagtl"))
2nd suggestion: put everything in one table
You will notice that the person referring another person is also a person, so it's basically a reference to self. In that regards you can have your CustomUser model look as follows:
class CustomUser(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(unique=True)
first_name = models.CharField(max_length=32)
last_name = models.CharField(max_length=32)
is_staff = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
date_joined = models.DateTimeField(default=timezone.now)
referred_by = models.ForeignKey(self, on_delete=models.SET_NULL, blank=True, null=True)
unique_ref_id = models.CharField(max_length=8, blank=True, default=generate())
USERNAME_FIELD = 'email' # unique identifier, changed to email (default was username)
REQUIRED_FIELDS = ['first_name', 'last_name']
objects = CustomUserManager() # custom manager for interacting with database
def __str__(self):
return self.email
Base on that, you can do things like this:
Create a new user:
sponsor = CustomUser.objects.get(unique_ref_id="exbvagtl")
user = CustomUser(email=email, first_name=first_name, last_name=last_name,referred_by=sponsor)
user.save()
Get the list of a user's referrals:
sponsor = CustomUser.objects.get(unique_ref_id="exbvagtl")
referrals = CustomUser.objects.filter(referred_by=sponsor)
Hope this helps, if you have any doubts, don't hesitate to ask below.

Related

Django admin prefetch content_type model

I used the django debug toolbar to analyse why the calls to my usermodel were so painfully slow within the django admin. There I saw that I had hundreds of duplicate calls to the content_type model:
SELECT ••• FROM "django_content_type" WHERE "django_content_type"."id"
= 1 LIMIT 21
362 similar queries. Duplicated 4 times.
To be honest, I do not understand where these calls come from in the first place but I wanted to pre_fetch the model. However, this seems not to be possible in the normal way because there is actually no ForeignKey or any other kind of direct relationship between the models. How could I reduce those 362 content_type calls?
This is the usermodel in question:
class User(AbstractBaseUser, PermissionsMixin):
"""
Base model for the user application
"""
USERNAME_FIELD = "email"
objects = UserManager()
username_validator = None
username = None
email = models.EmailField(_("email address"), unique=True)
is_staff = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
date_joined = models.DateTimeField(default=timezone.now)
first_name = models.CharField(max_length=150, blank=True)
last_name = models.CharField(max_length=150, blank=True)
title_of_person = models.ForeignKey(
TitleOfPerson, on_delete=models.CASCADE, blank=True, null=True
)
is_verified = models.BooleanField(default=False)
language = models.ForeignKey(
Language, blank=True, null=True, on_delete=models.SET_NULL
)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
verbose_name = _("User")
verbose_name_plural = _("Users")
def __str__(self) -> str:
return self.email
Thanks

Django - Is it possible to get objects of "indirectly related one to one field" with reverse_many_to_one_manager?

For instance I have these models:
class Company(models.Model):
name = models.CharField(max_length=100)
class User(AbstractBaseUser):
email = models.EmailField(max_length=250, unique=True)
date_joined = models.DateTimeField(auto_now_add=True)
last_login = models.DateTimeField(auto_now=True)
is_admin = models.BooleanField(default=False)
is_active = models.BooleanField(default=False)
is_staff = models.BooleanField(default=False)
is_superuser = models.BooleanField(default=False)
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True)
company = models.ForeignKey(Company, on_delete=models.PROTECT)
is_admin = models.BooleanField(default=False)
Now I can easily get all the profiles for a company using the following query:
Company.objects.first().profile_set.all()
But is there a way I can get the related users from company instead of profile, keeping in mind that a user object is one to one related with profile object?
Note: These models are just example models, and keeping in view the application logic, we can't combine user and profile model.
company = Company.objects.get(id=X)
User.objects.filter(profile__company=company)
or create a manager on Users:
def from_company(self, company: Company):
return self.filter(profile__company=company)
https://docs.djangoproject.com/en/4.0/topics/db/managers/

Django 4.0 - Trying to run a query based on result from another query

guys!
Here's what I'm trying to do:
I have a User model, a LinkedOrganization model, an Organization model that looks like this:
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(db_index=True, unique=True)
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
mobile = models.CharField(max_length=12)
is_staff = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
is_superuser = models.BooleanField(default=False)
objects = UserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['first_name', 'last_name', 'mobile']
class Meta:
verbose_name = 'User'
verbose_name_plural = 'Users'
# Organization fields
class Organization(models.Model):
organization_name = models.CharField(max_length=50, unique=True)
def __str__(self):
return self.organization_name
class LinkedOrganization(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='linked_user')
organization = models.ForeignKey(Organization, on_delete=models.CASCADE, related_name='linked_organization')
is_manager = models.BooleanField(default=False)
is_admin = models.BooleanField(default=False)
class Meta:
unique_together = (
("user", "organization")
)
In my API-view I'm trying to return all the users that are linked to an organization that the requester is a manager of.
Now, one requester can be a manager of 1 or more organizations, and I need to get all the users linked to those organizations. Meaning I need it to be sort of 'is member of organization A' OR 'is member of organization B', and iterate through all the organizations. Is it possible to do this with a Queryset in Django?
I realized when I wrote this that I could just get the organizations and use ReverseObjectManager to get the users of the organizations and iterate through those and make the dictionaries I need in Python, but if getting a query and use the result in a queryset is a function of Django that would be easier.
You may benefit from a slightly different database schema, not just for this query but in general. Consider the following:
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(db_index=True, unique=True)
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
mobile = models.CharField(max_length=12)
organization = models.ForeignKey('Organization', on_delete=models.CASCADE, related_name='user_organization')
is_staff = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
is_superuser = models.BooleanField(default=False)
objects = UserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['first_name', 'last_name', 'mobile']
class Meta:
verbose_name = 'User'
verbose_name_plural = 'Users'
# Organization fields
class Organization(models.Model):
organization_name = models.CharField(max_length=50, unique=True)
manager = models.ForeignKey(User, etc...)
def __str__(self):
return self.organization_name
In this scenario, every user has an organization, and every organization has a manager. Simple. Also note that I referenced the 'Organization' in the foreign key field as a string, since it is declared above where the Organization model is defined. With that, you can query like so:
managed_users = User.objects.filter(user_organization__manager=request.user)
A common practice is to create a profile model for the user, where additional fields like their organization, contact info, etc can be added. In that case you'd have something like this:
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
organization = models.ForeignKey(Organization, etc...)

how to implement two user types (seller and customer or buyer) using django allauth like fiverr?

I am working on a web e-commerce project where there will be two types of user (seller, customer). I have been wondering how to implement the logic like fiverr seller and buyer. I have created a user account with two flags yet (is_seller, is_customer).
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(max_length=254, unique=True)
name = models.CharField(max_length=254, blank=True)
customer = models.ForeignKey('Customer', on_delete=models.CASCADE)
is_seller = models.BooleanField(default=False)
is_customer = models.BooleanField(default=False)
is_staff = models.BooleanField(default=False)
is_superuser = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
last_login = models.DateTimeField(null=True, blank=True)
date_joined = models.DateTimeField(auto_now_add=True)
USERNAME_FIELD = 'email'
EMAIL_FIELD = 'email'
REQUIRED_FIELDS = []
objects = UserManager()
I want 2 users (seller and customer). A seller can request for a customer account as well (so same email will be used for login and signup) and vice versa.
what will be the best approach to this kind of scenario?
If they all share the same data fields then this might be the simplest way to do it. I'd only recommend multiple user models if there'll be different data captured. In that case, you could extend the User model.

Creating a group hierarchy in Django

I can't seem to figure out how to best implement a user model following this schema in Django:
All are members, some are staff and must be part of a committee, where each committee has a leader
I'm creating a custom admin interface for my use. I've extended the AbstractBaseUser class to create a new class User that represents all members, but there are some fields that are not relevant to members.
class User(AbstractBaseUser):
first_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100)
username = models.CharField(max_length=20, unique=True)
date_joined = models.DateTimeField(auto_now_add=True)
email = models.EmailField(max_length=100, default='')
phone_number = models.CharField(default='', blank=True)
balance = models.IntegerField(default=0)
minimum_balance = models.IntegerField(default=0)
status = models.CharField(choices=STATUS, default=STATUS_ACTIVE)
committee = models.CharField(choices=COMMITTEE, default=COMMITTEE_1)
objects = MyUserManager()
USERNAME_FIELD = 'username'
EMAIL_FIELD = 'email'
REQUIRED_FIELDS = ['first_name',
'last_name',
'email',]
def get_full_name(self):
return "{0} {1}".format(self.first_name,self.last_name)
def get_short_name(self):
return self.first_name
def __str__(self):
return self.username
These fields are not needed by a regular member:
status = models.CharField(choices=STATUS, default=STATUS_ACTIVE)
committee = models.CharField(choices=COMMITTEE, default=COMMITTEE_1)
Should these fields be included in the User class and be part of a Group, or should they be somewhere else? How can a leader of a committee be represented in this Django model? Also, is there a better way to implement a hierarchy of users like this in Django?
You can create a modal for committee like this.
Class Committee(models.Model):
name = models.CharField(max_length=255, unique=True)
members = models.ManyToManyField(User)
leader = models.ForeignKey(User)
Above models depict there will not be multiple committees with the same name, a committee will have some members and one leader.