Django多表继承影响子模型的'pk'属性

时间:2016-12-27 06:37:13

标签: python django python-2.7 inheritance django-models

我在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?

基本上我感兴趣的是:

  1. 此行为是错误或功能的结果吗?
  2. 是否可以安全重新定义'pk'属性 django.db.models.base.Model(或者可能只有_get_pk_val()方法) 在“Base”中总是返回uuid.UUID()。hex?我其实喜欢这个“bug”,但不认为这是可能的。
  3. 将“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')
    

0 个答案:

没有答案