#27337: Convoluted MTI with abstract model mixin fails on PY2, works on PY3
----------------------------------------------+--------------------------
Reporter: Tim Heap | Owner: nobody
Type: Bug | Status: new
Component: Database layer (models, ORM) | Version: 1.10
Severity: Normal | Keywords: python2, mti
Triage Stage: Unreviewed | Has patch: 0
Easy pickings: 0 | UI/UX: 0
----------------------------------------------+--------------------------
This is a rather convoluted situation, but with the set up below, PY2
fails but PY3 works. For context, this is roughly the same model set up
used in Wagtail:
* A Page class with custom Metaclass,
* Developers extend Page using MTI to make custom page types
* Mixins can be used for adding common functionality from e.g. plugins.
{{{#!python
from django.db import models
from django.utils import six
from django.test import TestCase
class ConvolutedMTIWithAbtractMixinTests(TestCase):
def test_convoluted_mti(self):
class PageBase(type(models.Model)):
"""
Wagtail's metaclass does some things, but nothing related.
This empty metaclass still spoils things for some reason?
"""
class Page(six.with_metaclass(PageBase, models.Model)):
"""The base page model. Every page should inherit from
this."""
url = models.CharField(max_length=255)
class Meta:
app_label = 'tests'
class FancyMixin(models.Model):
"""A model mixin with extra functionality, including extra
model fields."""
fancy_field = models.CharField(max_length=10)
class Meta:
abstract = True
class MyPage(FancyMixin, Page):
"""My custom page type. Extends Page using MTI, and mixes in
FancyMixin"""
content = models.CharField(max_length=255)
class Meta:
app_label = 'tests'
# The page_ptr from MyPage to Page is created.
self.assertTrue(hasattr(MyPage, 'page_ptr'))
# The other fields are all there
self.assertTrue(MyPage._meta.get_field('url'))
self.assertTrue(MyPage._meta.get_field('fancy_field'))
self.assertTrue(MyPage._meta.get_field('content'))
# The page_ptr field exists as a parent pointer to page.
self.assertIn(Page, MyPage._meta.parents)
self.assertIsInstance(MyPage._meta.parents[Page],
models.OneToOneField)
# But Django on py27 gets confused, and 'page_ptr' is not
'registered'
# (There is no nice _meta.has_field, so try: catch will do.)
try:
MyPage._meta.get_field('page_ptr')
except FieldDoesNotExist:
self.fail("MyPage.page_ptr field is missing!")
}}}
I stuck this test in `tests/model_inheritance/tests.py` when testing this
out, but the tests can probably go anywhere. For some tests failing in the
wild, this Travis CI build (https://travis-
ci.org/takeflight/wagtail/builds/167013485) of some patches to Wagtail
shows this happening on Django 1.8, 1.9 and 1.10 at least, but only on
Python 2.7.
I've poked around a little bit to see if I could work out what is going
on, but I am not familiar enough with the model internals to make much
headway.
--
Ticket URL: <https://code.djangoproject.com/ticket/27337>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
--
You received this message because you are subscribed to the Google Groups
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/django-updates/050.61257da253f07b79837013a87f34d933%40djangoproject.com.
For more options, visit https://groups.google.com/d/optout.