Skip to content

UUIDField and multi-table inheritance #329

Closed
@ghost

Description

It seems that with Django 1.5, the UUIDField doesn't work well when used as a primary key with multi-table inheritance.

My models:

from django.db import models
from django_extensions.db.fields import UUIDField


class ParentModel(models.Model):

    uid = UUIDField(max_length=64, primary_key=True, editable=False,
                    blank=True, version=4)

    parent_field = models.CharField(max_length=64)


class ChildModel(ParentModel):
    child_field = models.CharField(max_length=64)

Then I create a child object:

>>> from myapp.models import ChildModel
>>> obj = ChildModel.objects.create(parent_field="I'm in the parent table", child_field="I'm in the child table")
>>> obj.pk
1

As you can see the pk attribute is not correct. When I look in database, I can see that the link to the parent table is incorrect:

sqlite> .header on
sqlite> .mode column
sqlite> select * from myapp_childmodel;
parentmodel_ptr_id  child_field           
------------------  ----------------------
1                   I'm in the child table
sqlite> select * from myapp_parentmodel;
uid                                   parent_field           
------------------------------------  -----------------------
285fbd0a-faf9-463e-9d8e-d6d67f533e4d  I'm in the parent table

After investigating the issue I found that the correct value was set at some point but was then overridden by Django here: https://github.com/django/django/blob/1aca9d93beaac9f5e37cd90d1e29e572b5f7a86d/django/db/models/base.py#L664

The critical bit is:

            if update_pk:
                setattr(self, meta.pk.attname, result)

The value of update_pk depends on the value of meta.has_auto_field that is set to True by UUIDField's contribute_to_class method.

So this patch fixes the issue for me:

diff --git a/django_extensions/db/fields/__init__.py b/django_extensions/db/fields/__init__.py
index a3b1d68..94c2f9a 100644
--- a/django_extensions/db/fields/__init__.py
+++ b/django_extensions/db/fields/__init__.py
@@ -250,7 +250,7 @@ class UUIDField(CharField):
                 self, cls, name, cls._meta.auto_field
             )
             super(UUIDField, self).contribute_to_class(cls, name)
-            cls._meta.has_auto_field = True
+            cls._meta.has_auto_field = False
             cls._meta.auto_field = self
         else:
             super(UUIDField, self).contribute_to_class(cls, name)

I'm not sure of all the consequences of doing this, but it doesn't seem completely crazy to set has_auto_field to False since UUIDField is not an AutoField.

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions