I have a simple model with a generic foreign key:
class Generic(models.Model):
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey('content_type', 'object_id')
I would like to filter all entries in this table that have non-null content_object
's, i.e. filter out all instances of Generic
whose content objects no longer exist:
Generic.objects.filter(~Q(content_object=None))
This doesn't work, giving the exception:
django.core.exceptions.FieldError: Field 'content_object' does not generate an automatic reverse relation and therefore cannot be used for reverse querying. If it is a GenericForeignKey, consider adding a GenericRelation.
Adding GenericRelation
to the referenced content type models makes no difference.
Any help on how to achieve this would be appreciated, many thanks.
EDIT: I realise I could cascade the delete, however this is not an option in my situation (I wish to retain the data).
If you want to filter some records out, it's often better to use the exclude()
method:
Generic.objects.exclude(object_id__isnull=True)
Note, though, that your model now doesn't allow empty content_object
fields. To change this behaviour, use the null=True
argument to both object_id
and content_type
fields.
Okay, since the question has shifted from filtering out null records to determining broken RDBMS references without help of RDBMS itself, I'd suggest a (rather slow and memory hungry) workaround:
broken_items = []
for ct in ContentType.objects.all():
broken_items.extend(
Generic.objects
.filter(content_type=ct)
.exclude(object_id__in=ct.model_class().objects.all())
.values_list('pk', flat=True))
This would work as a one-time script, but not as a robust solution. If you absolutely want to retain the data, the only fast way I could think out is having a is_deleted
boolean flag in your Generic
model and setting it in a (post|pre)_delete
signal.