Tuesday, December 22, 2015

makemigrations of model with single table inheritance and child fields

# ................. Mailbox .....................
class AbstractMailbox(models.Model):
id = models.AutoField(primary_key=True)
localpart = models.CharField(_('Localpart'), max_length=40)
localdomainfk = models.ForeignKey(Localdomain, verbose_name=_('Domain'), db_column='localdomainfk', editable=('AL'))
accountfk = models.ForeignKey(Account, verbose_name=_('Account'), db_column='accountfk', editable=('UL', 'UR','AR'))
status = models.CharField(_('Status'), max_length=1, choices=
(('N', _('New')), ('E', _('Enabled')), ('L', _('Locked')), ('D', _('Disabled')), ('C', _('Closed'))),
default='N', editable=('UL',))
created = models.DateField(_('Created'), auto_now_add=True)
updated = models.DateField(_('Updated'), auto_now=True)
remarks = models.TextField(_('Remarks'),null=True, blank=True, editable=('UL',))
lifetime = TimedeltaField(_('Lifetime of Data'), max_length=10, default='360 days', editable=('UL', 'UE'))
class Meta:
abstract = True
managed = False # can't migrate -- using fake model 'mailbox_for_migration' for migration
db_table = 'mailbox'
verbose_name = _('Mailbox')
verbose_name_plural = _('Mailboxes')
ordering = ['localpart']
unique_together = ('localpart', 'localdomainfk')
def __str__(self):
##return self.localpart+ '@'+self.localdomainfk.name+' ['+self.type+']' # trouble with account/pw reset
return self.localpart+ '@'+self.localdomainfk.name

class Mailbox(AbstractMailbox): # a generic mailbox
type = models.CharField('Typ', max_length=1, choices=
(('A', _('Alias')), ('M', _('Mailbox')), ('S', _('Systemalias'))), editable=False)
aoxuserid = models.IntegerField(_('IMAP Server User ID'), null=True, blank=True)
quota = models.PositiveSmallIntegerField(_('IMAP Server Quota'),null=True, blank=True)
aliastargetaddresses = NULLCharFieldM(_('Alias Targetaddress'), max_length=75)

class Meta:
managed = False # can't migrate -- using fake model 'mailbox_for_migration' for migration
db_table = 'mailbox'
unique_together = ('localpart', 'localdomainfk')

class AliasManager(models.Manager):
def get_queryset(self):
return super(AliasManager, self).get_queryset().filter(type='A')
def filter(self, *args, **kwargs):
if not ('localpart' in kwargs and 'localdomainfk' in kwargs):
return self.get_queryset().filter(*args, **kwargs)
return super(AliasManager, self).get_queryset().filter(*args, **kwargs)

class Alias(AbstractMailbox): # alias
type = models.CharField('Typ', max_length=1, choices=
(('A', _('Alias')), ('M', _('Mailbox')), ('S', _('Systemalias'))), editable=False, default='A')
aliastargetaddresses = NULLEmailFieldM(_('Alias Targetaddress'), max_length=75)
objects = AliasManager()
class Meta:
managed = False # can't migrate -- using fake model 'mailbox_for_migration' for migration
db_table = 'mailbox'
verbose_name = _('Alias')
verbose_name_plural = _('Aliases')
unique_together = ('localpart', 'localdomainfk')

class ConcreteMailboxManager(models.Manager):
def get_queryset(self):
return super(ConcreteMailboxManager, self).get_queryset().filter(type='M')
def filter(self, *args, **kwargs):
if not ('localpart' in kwargs and 'localdomainfk' in kwargs):
return self.get_queryset().filter(*args, **kwargs)
return super(ConcreteMailboxManager, self).get_queryset().filter(*args, **kwargs)

class ConcreteMailbox(AbstractMailbox): # a concrete mailbox
type = models.CharField('Typ', max_length=1, choices=
(('A', _('Alias')), ('M', _('Mailbox')), ('S', _('System Alias'))), editable=False, default='M')
aoxuserid = models.IntegerField(_('IMAP Server User ID'), default=-1)
quota = models.PositiveSmallIntegerField(_('IMAP Server Quota'), default=200)
objects = ConcreteMailboxManager()
class Meta:
managed = False # can't migrate -- using fake model 'mailbox_for_migration' for migration
db_table = 'mailbox'
verbose_name = _('Mailbox')
verbose_name_plural = _('Mailboxes')
unique_together = ('localpart', 'localdomainfk')

class SystemAliasManager(models.Manager):
def get_queryset(self):
return super(SystemAliasManager, self).get_queryset().filter(type='S')
def filter(self, *args, **kwargs):
if not ('localpart' in kwargs and 'localdomainfk' in kwargs):
return self.get_queryset().filter(*args, **kwargs)
return super(SystemAliasManager, self).get_queryset().filter(*args, **kwargs)

class SystemAlias(AbstractMailbox): # system alias like postmaster
type = models.CharField('Typ', max_length=1, choices=
(('A', _('Alias')), ('M', _('Mailbox')), ('S', _('System Alias'))), editable=False, default='S')
aliastargetaddresses = NULLEmailFieldM(_('Alias Targetaddress'), max_length=75)
objects = SystemAliasManager()
class Meta:
managed = False # can't migrate -- using fake model 'mailbox_for_migration' for migration
db_table = 'mailbox'
verbose_name = _('System Alias')
verbose_name_plural = _('System Aliases')
unique_together = ('localpart', 'localdomainfk')

Hi all,

My db, which is in production (with none-Django software) has some (legacy) tables, which share a set of common fields and some fields, which differ by child. The attached single table model hierarchy worked for me, even if it's not a legal Django arrangement. The 'type' field is responsible to select the right child.

Now, I'm starting with migrations and see that makemigrations tries to create one mailbox table per child (because I have db_table there, which was needed to get the arrangement working).

Questions:

Is the above arrangement the best current praxis for the given legacy situation?
Can I stop makemigrations from looking at this model hierarchy at all and instead create a migration for some fake model?
Or asked differently, must I live with the situation where I maintain all my migrations by hand?

Splitting the models from the legacy tables in 2 apps comes into mind.

Any help appreciated,
Axel

--
You received this message because you are subscribed to the Google Groups "Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-users+unsubscribe@googlegroups.com.
To post to this group, send email to django-users@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-users/F016760C-A041-41A5-9494-BDBBE165E317%40Chaos1.DE.
For more options, visit https://groups.google.com/d/optout.

No comments:

Post a Comment