﻿id	summary	reporter	owner	description	type	status	component	version	severity	resolution	keywords	cc	stage	has_patch	needs_docs	needs_tests	needs_better_patch	easy	ui_ux
37471	No system check for GenericRelation on a model with DB_CASCADE, leaving orphaned generic rows	Akshat Gupta		"The docs say that database-level and Python-level `on_delete` variants cannot be mixed in the same model or in related models. System checks enforce this with `models.E050` and `fields.E323`.

`GenericRelation` is a Python-level cleanup, but it is not checked. If a model has a `GenericRelation` and a `DB_CASCADE` foreign key, the database deletes the model's rows and Django never deletes the generic related objects. They stay in the table with no error and no check warning.

{{{#!python
class Tag(models.Model):
    content_type = models.ForeignKey(ContentType, models.CASCADE)
    object_id = models.PositiveIntegerField()
    content_object = GenericForeignKey()


class Author(models.Model):
    pass


class Book(models.Model):
    author = models.ForeignKey(Author, models.DB_CASCADE)
    tags = GenericRelation(Tag)
}}}

{{{#!python
>>> author = Author.objects.create()
>>> book = Book.objects.create(author=author)
>>> book.tags.create()
>>> author.delete()
>>> Book.objects.count(), Tag.objects.count()
(0, 1)
}}}

`manage.py check` reports no issues. With `models.CASCADE` instead of `models.DB_CASCADE`, the `Tag` row is deleted.

Why it happens: `Collector.collect()` skips `DB_CASCADE` relations, so `Book` instances are never collected. Their private fields are never visited, so `GenericRelation.bulk_related_objects()` never runs. `GenericRelation.remote_field.on_delete` is `DO_NOTHING`, so `Model._check_related_fields()` does not see it as a Python-level variant.

I verified this on 6.1.3 and on main with SQLite. I also ran random schemas with database and Python `on_delete` variants against the equivalent all-Python schemas. Among schemas that pass all checks, the only difference in the final data was orphaned generic rows.

Suggested fix: add a system check error for a model that has a `GenericRelation` (any private field with `bulk_related_objects()`) and a `DB_CASCADE` foreign key. It would not fire for `DB_SET_NULL` or `DB_SET_DEFAULT`, because those do not delete the model's rows. This is the same kind of gap as #37254 (implicit M2M through tables), which was fixed in 6.1.x.

I am happy to work on a patch once the approach is agreed.
"	Bug	new	Database layer (models, ORM)	6.1	Normal		DB_CASCADE, GenericRelation, on_delete	Akshat Gupta	Unreviewed	0	0	0	0	0	0
