Opened 33 hours ago
Closed 3 hours ago
#36183 closed Bug (invalid)
Model o2o inheritance with abstract models does not "evaluate" a lazy relationship
Reported by: | BeryCZ | Owned by: | |
---|---|---|---|
Component: | Database layer (models, ORM) | Version: | 5.1 |
Severity: | Normal | Keywords: | |
Cc: | BeryCZ | Triage Stage: | Unreviewed |
Has patch: | no | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
When I define models like this
class AbstractPage(models.Model): mtime = models.DateTimeField( verbose_name="Last modification at", auto_now=True, ) class Meta: abstract = True class AbstractPageType(models.Model): page = models.OneToOneField( "Page", verbose_name="ID", primary_key=True, on_delete=models.CASCADE, related_name="%(class)s", parent_link=True, ) title = models.CharField( verbose_name="Title", max_length=255, null=False, blank=False, ) class Meta: abstract = True class Page(AbstractPage): pass class ArticlePage(AbstractPageType, Page): pass
And then I do
ArticlePage.objects.order_by("-mtime").all()
I get
File "django/db/models/manager.py", line 87, in manager_method return getattr(self.get_queryset(), name)(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "django/db/models/query.py", line 1701, in order_by obj.query.add_ordering(*field_names) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "django/db/models/sql/query.py", line 2249, in add_ordering self.names_to_path(item.split(LOOKUP_SEP), self.model._meta) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "django/db/models/sql/query.py", line 1777, in names_to_path path_to_parent = opts.get_path_to_parent(model) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "django/db/models/options.py", line 755, in get_path_to_parent targets = (final_field.remote_field.get_related_field(),) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "django/db/models/fields/reverse_related.py", line 311, in get_related_field field = self.model._meta.get_field(self.field_name) ^^^^^^^^^^^^^^^^ Exception Type: AttributeError Exception Value: 'str' object has no attribute '_meta'
It works when I do
class ArticlePage(AbstractPageType, Page): page = models.OneToOneField( "Page", verbose_name="ID", primary_key=True, on_delete=models.CASCADE, related_name="%(class)s", parent_link=True, )
but I would prefer not to have to define page field in every PageType.
Note:
See TracTickets
for help on using tickets.
Hello BeryCZ, thank you for this report. I've analyzed your models and I fear that the issue is the complex inheritance that you have proposed. Specifically, you cannot have a model (
ArticlePage
) that both inherits fromPage
and has aOneToOneField
toPage
. Without understanding your use case, it feels like a possible solution would be for your "pages" to have a FK to "page types" (instead of the other way around with the 1-1 field).Your model definitions create an inheritance conflict:
AbstractPageType
expects a separatePage
instance (this means every model that inherits fromAbstractPageType
must have a separatePage
instance linked via thepage
field).ArticlePage
is also inheritingPage
, which means Django expectsArticlePage
itself to be aPage
instance.Django sees two competing ways to resolve
ArticlePage
:ArticlePage
is aPage
(due to model inheritance), orArticlePage
has a separatePage
instance (due to the pageOneToOneField
).The error is caused because Django tries to retrieve the
mtime
field, which exists onPage
(inherited viaAbstractPage
). But becauseArticlePage
also has aOneToOneField
calledpage
, Django gets confused about how to resolvemtime
. Instead of treatingpage
as a relationship to anotherPage
instance, Django interprets it as a string.Solutions are either to remove the direct inheritance to
Page
or remove thepage
field fromAbstractPageType
.If you have further questions, there are several user support channels available. Please refer to TicketClosingReasons/UseSupportChannels for ways to get help.