Reputation: 7358
Here is my Django model:
class Message(models.Model):
text = models.TextField()
parent = models.ForeignKey('Message', null=True, on_delete=models.SET_NULL)
threads = ThreadManager()
class ThreadManager(models.Manager):
def get_queryset(self):
return super(ThreadManager, self).get_queryset().filter()
As you see, it uses a custom manager. In ThreadManager
I want to filter messages which has a self relation. I mean parent
refers to its record. (x.parent = x
)
How to write that filter
? Is it possible at all?
Upvotes: 1
Views: 2678
Reputation: 477170
You can use a filter where you address the pk
column:
from django.db.models import F
Message.objects.filter(parent=F('pk'))
So here we specify that the parent_id
should be the same as the primary key, hence in that case the relation is cyclic.
Note that this filter will not detect cycles that have a length longer than 1. For example if we have two messages A
and B
, and A.parent = B
and B.parent = A
, then this filter will not detect this. It only detects Message
s where A.parent == A
.
Furthermore Django does not perform a semantical check: if you later let parent
refer to another model, this filter does not makes much sense anymore, but Django will not produce a warning.
In case we want to opposite, we can use .exclude(..)
or wrap it into a Q
object:
# using exclude
Message.objects.exclude(parent=F('pk'))
# using Q
from django.db.models import Q
Message.objects.filter(~Q(parent=F('pk')))
So in that case the Message
either has no parent, or a parent that is not the same message.
Upvotes: 5