Repository: django-extensions/django-extensions

Issue:
UUIDField and multi-table inheritance
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:

``` python
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:

``` python
>>> 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:

``` python
            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:

``` patch
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`.



Discussion:
I have investigated further and it's a bit tricky.

`has_auto_field` has been set to `True` since commit 22b5af8679f2ea8da57778a48ab70b33d9efefa4 which was intended to fix #50 The change I'm suggesting breaks admin inline editing because of this bug in Django:  https://code.djangoproject.com/ticket/13696 Comments by @wolever in the bug discussion over there summarize the problem quite clearly. To get the admin inline editing to work, it's tempting to set `has_auto_field` to `True`, but it's not the right thing to do because `UUIDField` is not an auto field. By setting `has_auto_field` to `True`, we're saying that Django is providing and `id` field automatically, which obviously is not the case here and that breaks multi-table inheritance, as I've described before.

I'm really not sure what's the best thing to do here. It's better not to try to cheat Django into believing that our `UUIDField` is an auto field. As we see with the case of multi-table inheritance, that little lie comes with a price. But until the bug in Django admin is fixed, setting `has_auto_field` to `False` will trigger #50 again.

As far as I'm concerned, I think I'm going to set `has_auto_field` to `False` and address the inline editing issue by overriding the admin templates with the fixes suggested in the discussion of Django bug 13696.


Resolving patch:
diff --git a/django_extensions/db/fields/__init__.py b/django_extensions/db/fields/__init__.py
--- a/django_extensions/db/fields/__init__.py
+++ b/django_extensions/db/fields/__init__.py
@@ -246,17 +246,6 @@ def __init__(self, verbose_name=None, name=None, auto=True, version=1, node=None
     def get_internal_type(self):
         return CharField.__name__
 
-    def contribute_to_class(self, cls, name):
-        if self.primary_key:
-            assert not cls._meta.has_auto_field, "A model can't have more than one AutoField: %s %s %s; have %s" % (
-                self, cls, name, cls._meta.auto_field
-            )
-            super(UUIDField, self).contribute_to_class(cls, name)
-            cls._meta.has_auto_field = True
-            cls._meta.auto_field = self
-        else:
-            super(UUIDField, self).contribute_to_class(cls, name)
-
     def create_uuid(self):
         if not self.version or self.version == 4:
             return uuid.uuid4()


Test patch:
diff --git a/django_extensions/tests/uuid_field.py b/django_extensions/tests/uuid_field.py
--- a/django_extensions/tests/uuid_field.py
+++ b/django_extensions/tests/uuid_field.py
@@ -48,6 +48,8 @@ def testUUIDField_pkCreate(self):
     def testUUIDField_pkAgregateCreate(self):
         j = TestAgregateModel.objects.create(a=6)
         self.assertEqual(j.a, 6)
+        self.assertIsInstance(j.pk, six.string_types)
+        self.assertEqual(len(j.pk), 36)
 
     def testUUIDFieldManyToManyCreate(self):
         j = TestManyToManyModel.objects.create(uuid_field=six.u('550e8400-e29b-41d4-a716-446655440010'))