我在Django中发现了“多层”模型继承的可能问题。
我通过定义基础模型类,对其进行子类化以及有时进一步对结果模型进行子类化来利用多表继承。例如:
settings.py(默认情况下来自Django 1.8的差异):
ROOT_URLCONF = 'my_app.urls'
WSGI_APPLICATION = 'my_app.wsgi.application'
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'dj_db',
'USER': 'happy',
'PASSWORD': 'camper',
'HOST': '127.0.0.1',
}
}
TIME_ZONE = 'Pacific/Auckland'
INSTALLED_APPS += (
'my_app',
)
models.py:
from django.db import models
from django.contrib.auth.models import User
from django.utils.translation import ugettext_lazy as _
import uuid
class Base(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
date_changed = models.DateTimeField(_('added/modified'), auto_now=True, editable=False)
enabled = models.BooleanField(_('enabled'), default=True)
class MyMate(Base):
user = models.ForeignKey(User, editable=False)
# fields for first and last names, etc.
nick = models.CharField(_("Nick"), max_length=75, editable=True, blank=False,
unique=True, help_text=_("Mate's nickname"))
def __unicode__(self):
return unicode(self.nick).encode('utf-8')
class Meta:
verbose_name = _('Mate')
verbose_name_plural = _('Mates')
class ReBase(Base):
place = models.CharField(max_length=260, editable=False)
def __unicode__(self):
return unicode(self.place).encode('utf-8')
class MyWorkmate(ReBase):
class Meta:
verbose_name = _('Workmate')
verbose_name_plural = _('Workmates')
class MyClassmate(ReBase):
class Meta:
verbose_name = _('Classmate')
verbose_name_plural = _('Classmates')
忽略此类解决方案可能存在的性能问题(这只是一个示例)。
admin.py:
from django.contrib import admin
from django.utils.translation import ugettext_lazy as _
from my_app.models import MyMate, MyWorkmate
@admin.register(MyMate)
class MyMateAdmin(admin.ModelAdmin):
list_page_title = _('My Mates')
model = MyMate
list_display = ('__unicode__', 'date_changed')
fieldsets = (
(None, {
'fields': ('nick', ),
'classes': ('extrapretty', 'wide'),
}),
)
def save_model(self, request, obj, form, change):
obj.user = request.user
obj.save()
@admin.register(MyWorkmate)
class MyWorkmateAdmin(admin.ModelAdmin):
list_page_title = _('My Workmates')
model = MyWorkmate
list_display = ('__unicode__', 'date_changed', 'enabled')
readonly_fields = ('place', )
fieldsets = (
(None, {
'fields': ('place', 'enabled'),
'classes': ('extrapretty', 'wide'),
}),
)
def has_add_permission(self, request):
return False
def has_delete_permission(self, request, obj=None):
return False
def get_actions(self, request):
actions = super(MyWorkmateAdmin, self).get_actions(request)
del actions['delete_selected']
return actions
我使用Admin界面添加了“Mate”,下一步:
In [1]: from my_app.models import MyWorkmate
In [2]: MyWorkmate(place="ACME Inc.").save()
In [4]: from my_app.models import MyMate
In [6]: cool = MyWorkmate.objects.all()[0]
In [8]: cool.id
Out[8]: UUID('25fdba76-bae6-4e99-a674-530b4dcaec6c')
In [9]: cool.pk
Out[9]: u'25fdba76bae64e99a674530b4dcaec6c'
In [12]: lame = MyMate.objects.all()[0]
In [13]: lame.id
Out[13]: UUID('3754aeeb-9e21-4fd9-8132-3308c024fa9d')
In [14]: lame.pk
Out[14]: UUID('3754aeeb-9e21-4fd9-8132-3308c024fa9d')
你知道奇怪的球吗?什么是 MyWorkmate.objects.all()[0] .pk返回Unicode字符串(看起来像是uuid.UUID(。。hex)的结果而不是uuid.UUID obj?
基本上我感兴趣的是:
将“ReBase”(以及可选的“Base”)定义为abstract base classes可恢复预期的行为 - “pk”属性现在始终返回一个uuid.UUID对象:
In [1]: from my_app.models import MyWorkmate
In [2]: MyWorkmate(place="ACME Inc.").save()
In [3]: from my_app.models import MyMate
In [4]: cool = MyWorkmate.objects.all()[0]
In [5]: lame = MyMate.objects.all()[0]
In [6]: cool.id
Out[6]: UUID('cea83736-a674-430a-83dd-8b074f7a1a2f')
In [7]: cool.pk
Out[7]: UUID('cea83736-a674-430a-83dd-8b074f7a1a2f')
In [8]: lame.id
Out[8]: UUID('b6917676-148c-4e63-8c2d-2425ea2c41ac')
In [9]: lame.pk
Out[9]: UUID('b6917676-148c-4e63-8c2d-2425ea2c41ac')