Search code examples
djangodjango-modelsdjango-querysetdjango-3.0django-q

Querying Parent from the foreign key 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!


Solution

  • 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()