Django multi-table inheritance affects the 'pk' property of the child model
<p>I discovered a possible issue with "multilayer" model inheritance in Django.</p>

<p>I take advantage of multi-table inheritance by defining a base model class, subclassing it and sometimes further subclassing the resulting model. Example:</p>

<p><strong>settings.py (diff from Django 1.8 default):</strong></p>

<pre><code>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',
)
</code></pre>

<p><strong>models.py:</strong></p>

<pre><code>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')
</code></pre>

<p>Ignore the possible performance problems of such a solution (this is just an example). </p>

<p><strong>admin.py:</strong></p>

<pre><code>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
</code></pre>

<p>I added a "Mate" using Admin interface, next:</p>

<pre><code>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')
</code></pre>

<p>Did you notice the oddball? What's the dealio with <strong>MyWorkmate.objects.all()[0].pk returning a Unicode string</strong> (what looks like the result of uuid.UUID().hex) instead of a uuid.UUID obj?</p>

<p>Basically what I'm interested in knowing is:</p>

<ol>
<li>is this behavior the result of a bug or a feature?</li>
<li><s>is it possible to <strong>safely</strong> redefine the 'pk' property of
django.db.models.base.Model (or perhaps only the _get_pk_val() method)
within "Base" to always return  uuid.UUID().hex? I actually like this "bug", but don't think it is possible.</s></li>
</ol>

<p>Defining "ReBase" (and optionally "Base") as <a href="https://docs.djangoproject.com/en/1.8/topics/db/models/#abstract-base-classes" rel="nofollow noreferrer">abstract base classes</a> restores the expected behavior - 'pk' property now always returns a uuid.UUID object:</p>

<pre><code>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')
</code></pre>