#22447 closed Bug (fixed)
Migrations have bases=(NewBase,) for models with custom metaclass
| Reported by: | Craig de Stigter | Owned by: | Simon Charette | 
|---|---|---|---|
| Component: | Migrations | Version: | 1.7-beta-1 | 
| Severity: | Release blocker | Keywords: | |
| Cc: | Sebastian Bauer | Triage Stage: | Ready for checkin | 
| Has patch: | yes | Needs documentation: | no | 
| Needs tests: | no | Patch needs improvement: | no | 
| Easy pickings: | no | UI/UX: | no | 
Description
With this model:
from django.db import models
from django.db.models.base import ModelBase
from django.utils import six
class MetaZork(ModelBase):
    pass
class BlibbityBlorg(six.with_metaclass(MetaZork, models.Model)):
    ZerbyBlugg = models.CharField(max_length=1)
django-admin makemigrations produces the following:
    operations = [
        migrations.CreateModel(
            name=b'BlibbityBlorg',
            fields=[
                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
                (b'ZerbyBlugg', models.CharField(max_length=1)),
            ],
            options={
            },
            bases=(django.db.models.base.NewBase,),
        ),
    ]
NewBase is a six artifact; the correct base would be models.Model.
Originally reported by petkostas on django-mptt: https://github.com/django-mptt/django-mptt/issues/302
Attachments (1)
Change History (14)
by , 12 years ago
| Attachment: | testproject.zip added | 
|---|
comment:1 by , 12 years ago
| Triage Stage: | Unreviewed → Accepted | 
|---|
comment:2 by , 12 years ago
| Severity: | Normal → Release blocker | 
|---|
comment:3 by , 12 years ago
| Cc: | added | 
|---|
comment:4 by , 12 years ago
| Owner: | changed from to | 
|---|---|
| Status: | new → assigned | 
comment:5 by , 12 years ago
| Has patch: | set | 
|---|
Can you make sure the following patch works for you https://github.com/django/django/pull/2567.
comment:6 by , 12 years ago
This works for the testproject I submitted, but doesn't work for mptt because __module__ is different:
(Pdb) base <class 'mptt.models.NewBase'> (Pdb) base.__module__ 'mptt.models'
I'm not sure why six is setting this module differently; it's nothing special that mptt is doing AFAIK.
Doing some quick research into the differences, I'll post back shortly.
comment:7 by , 12 years ago
Well, I still don't understand why this happens, but it seems that the NewBase doesn't always have the __module__ you expect. So maybe the code shouldn't check for that.
ipdb> MuppettZarkity.mro() [<class 'testproject.testapp.models.MuppettZarkity'>, <class 'mptt.models.MPTTModel'>, <class 'mptt.models.NewBase'>, <class 'django.db.models.base.Model'>, <class 'django.db.models.base.NewBase'>, <type 'object'>] ipdb> BlibbityBlorg.mro() [<class 'testproject.testapp.models.BlibbityBlorg'>, <class 'testproject.testapp.models.ZerbyJarb'>, <class 'django.db.models.base.NewBase'>, <class 'django.db.models.base.Model'>, <class 'django.db.models.base.NewBase'>, <type 'object'>]
However they do consistenly have nothing much in their .__dict__ so perhaps that's a better check than .__module__:
                if (base.__name__ == 'NewBase' and
                    any((not attr.startswith('__') for attr in base.__dict__))):
comment:8 by , 12 years ago
It doesn't work in the mttp case because they skip ModelBase.__new__ here, it would work if they called super(MPTTModelBase, cls).__new__ instead.
Unsure how to deal correctly with this. I've proposed six to replace their with_metaclass implementation with the one Flask uses in order to prevent those NewBase artifacts. I ran the full Django test suite with this modified version and the NewBase hacks removed and it fully passed.
Fixing the issue at this level makes more sense me than trying to work around it by __mro__ and __dict__ checks.
comment:9 by , 12 years ago
I went ahead and created a pull request on six for this issue. Hopefully if it's merged in we can quickly merge a fix for Django as well.
comment:10 by , 12 years ago
Your pull request seems to have been merged into six so I went forward and updated my PR to break changes into two commits: one that backport the new version of with_metaclass to our vendored version of six and a second one that adds a regression test case for the issue reported here.
comment:12 by , 12 years ago
| Resolution: | → fixed | 
|---|---|
| Status: | assigned → closed | 
Test project that shows the problem