Ticket #182 (closed defect: fixed)

Opened 6 years ago

Last modified 6 years ago

Improper handling of _bases

Reported by: ralf.gerlich@… Owned by: andrew
Priority: major Milestone: 0.7
Component: migrations Version: 0.6-pre
Keywords: meta bases typeerror inheritance Cc:


I have the following model (shortened for better readability):

class Person(models.Model):
    surname = models.CharField(max_length=60);
    firstname = models.CharField(max_length=60);

class Pilot(Person):
    is_instructor = models.BooleanField(default=False);

class Flight(models.Model):
    # ...
    attendants = models.ManyToManyField(Pilot, blank=True, related_name='attended_flights');
    passengers = models.ManyToManyField(Person, blank=True, related_name='passenger_flights');
    # ...

I want to migrate all pilots from the passengers field to the attendants field:

from south.db import db
from django.db import models
from logbook.models import *

class Migration:
    no_dry_run = True;
    def forwards(self, orm):
        for pilot in orm.Pilot.objects.all():
            for flight in pilot.passenger_flights.all():
    def backwards(self, orm):
        for pilot in orm.Pilot.objects.all():
            for flight in pilot.attended_flights.all():
    models = {
        'logbook.flight': {
            'attendants': ('models.ManyToManyField', ["orm['logbook.Pilot']"],
                {'related_name': "'attended_flights'",
                 'blank': 'True'}),
            'passengers': ('models.ManyToManyField', ["orm['logbook.Person']"],
                {'related_name': "'passenger_flights'",
                 'blank': 'True'}),
        'logbook.person': {
            'firstname': ('models.CharField', [], {'max_length': '60'}),
            'id': ('models.AutoField', [], {'primary_key': 'True'}),
            'surname': ('models.CharField', [], {'max_length': '60'})
        'logbook.pilot': {
            'Meta': {'_bases': ["logbook.models.Person"]},
            'is_instructor': ('models.BooleanField', [], {'default': 'False'}),
            'person_ptr': ('models.OneToOneField', ["orm['logbook.Person']"], {})
    complete_apps = ['logbook']

The line pilot.attended_flights.add(flight); gives me a TypeError? exception, saying that an object of type 'flight' is expected.

Examining the type of flight I get 'logbook.models.Flight', while the model associated with pilot.attended_flights is 'logbook.models.flight'.

Looking into the code at south/orm.py I find that the base-class for the classes generated by the fake ORM is loaded using ask_for_it_by_name, which resolves the base of Pilot to be logbook.models.Person, i.e. the real instead of the fake base.

As the passenger_flights-relation is defined in Person, the field definitions in the fake Person and the fake Pilot differ.

Fix: Use the fake base class instead.

Is there a way to work around this issue?

Change History

comment:1 Changed 6 years ago by andrew

  • Status changed from new to assigned
  • Milestone set to 0.6

Yes, I should be able to use the fake bases, you're right.

comment:2 Changed 6 years ago by andrew

Bumping to 0.7

comment:3 Changed 6 years ago by andrew

  • Milestone changed from 0.6 to 0.7

comment:4 Changed 6 years ago by andrew

  • Status changed from assigned to closed
  • Resolution set to fixed

Fixed in [237ca3bb6d5d]. Finally :)

Note: See TracTickets for help on using tickets.