David Foie Gras
David Foie Gras

Reputation: 2080

How to make Q object expression in this case(filtering by ForeignKey field)?

models.py:

class Post(models.Model):
    title = models.TextField(max_length=1000, null=True, blank=True, default=None)
    created = models.DateTimeField(auto_now_add=True)


class PostFollow(models.Model):
    post = models.ForeignKey(Post, on_delete=models.CASCADE, null=True, blank=True)
    user = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True)

and from those model classes, I want to get posts that is not followed by some user.

Like this:

user = User.objects.get(pk=1)

not_followed_post = Post.objects.filter(Q(pk__lte=1000) & ~Q(self__is_not_followed_by_user=user))

How can I do this?

Upvotes: 1

Views: 40

Answers (1)

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 477309

I think it more self-explaining when using .exclude(..):

not_followed_post = Post.objects.exclude(
    postfollow__user=user
).filter(
    pk__lte=1000
)

The .exclude(..) will perform universal quantification in a transparent way.

I tink it is probably better to add explicit related_names here, to make it easier to pinpoint where the relation is looking at. For example:

class PostFollow(models.Model):
    post = models.ForeignKey(
        Post,
        on_delete=models.CASCADE,
        null=True,
        blank=True,
        related_name='postfollow'
    )
    user = models.ForeignKey(
        User,
        on_delete=models.CASCADE,
        null=True,
        blank=True,
        related_name='postfollow'
    )

The pk__lte is rather weird. Usually the pk is used only as an identifier. Making queries like __lte is of course possible, but rather uncommon.

Yes, pks are typically "distributed" in creation order (given you do not specify an explicit one), so if you never assign expliclty, you could probably use it to obtain more recent records than a given record. But still I think it is a bit "risky" to start filtering in such way. If you for example later add historical data to the database, then these can (depending on how you insert the data) have higher ids, and thus show up in the results.

Upvotes: 3

Related Questions