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
.