#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 test suite with this modified version 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