Django - performance difference between join/no join existence filter

Viewed 43

currently I have a Tinder-like application that functions off the following models

class User(models.Model):
    id      = models.BigAutoField(primary_key=True)
    name    = models.CharField(max_length=50)
    age     = models.PositiveIntegerField()
    pic_url = Models.CharField(max_length=100)

class Rating(models.Model):
    id       = models.BigAutoField(primary_key=True)
    by_user  = models.ForeignKey(User,
                                 on_delete=models.PROTECT,
                                 related_name='written_ratings')
    for_user = models.ForeignKey(User,
                                 on_delete=models.PROTECT,
                                 related_name='received_ratings')
    like     = models.BooleanField()

In order to get new User objects to swipe left and right on, we need to query the database (PostgresSQL) for users that we have not yet rated. I am currently doing this by performing the following query

users_that_i_havent_rated_yet = models.User.objects.all().exclude(
                                    id=current_user_id
                                ).filter(
                                    age__gte=some_minimum_age,
                                    age__lte=some_maximum_age,
                                ).exclude(
                                    received_ratings__by_user_id=current_user_id
                                )

Now, I intend on separating the User object into a Profile object - so as to maintain a "history" of any user's changes to their profile, as well as acting as a container for additional unrelated information (also because my professor asked us to do this for our project)

# as the user changes their profile pictures, we will just create 
# a new `Profile` object and set the `current_profile` pointing to it
class User(models.Model):
    id              = models.BigAutoField(primary_key=True)
    name            = models.CharField(max_length=50)
    age             = models.PositiveIntegerField()
    current_profile = models.OneToOneField(Profile,
                                           on_delete=models.PROTECT)

class Profile(models.Model):
    id      = models.BigAutoField(primary_key=True)
    pic_url = models.CharField(max_length=100)
    by_user = models.ForeignKey(User,
                                on_delete=models.PROTECT,
                                related_name='created_profiles')

class Rating(models.Model):
    id          = models.BigAutoField(primary_key=True)
    by_user     = models.ForeignKey(User,
                                    on_delete=models.PROTECT,
                                    related_name='written_ratings')
    for_profile = models.ForeignKey(Profile,
                                    on_delete=models.PROTECT,
                                    related_name='received_ratings')
    like        = models.BooleanField()

Now, since the information is separated into 2 tables, the query becomes

users_that_i_havent_rated_yet = models.User.objects.all().exclude(
                                    id=current_user_id
                                ).filter(
                                    age__gte=some_minimum_age,
                                    age__lte=some_maximum_age,
                                ).exclude(
                                    current_profile__received_ratings__by_user_id=current_user_id
                                )

Will the performance of the query be significantly effected by this additional join? Is there a better way to do this?

0 Answers
Related