djangodjango-taggitdjango-contenttypes

django-taggit on models with UUID as pk throwing out of range on save


I have models that uses UUID as its PK

class Foo(models.Model):        
    foo_id = models.UUIDField(  
        primary_key=True,             
        default=uuid.uuid4,           
        editable=False                
    )  
    tags = TaggableManager()        

When I go and try to add a new tag

f = Foo.objects.latest('pk')
f.tags.add("testing")

I get DataError: integer out of range

When I import pdb on the cursor to view the SQL going in I see this.

(Pdb) params                                                                                                              
(1, 287082253891563438098836942573405313042, 9)                                                                           
(Pdb) sql                                                                                                                 
'INSERT INTO "taggit_taggeditem" ("tag_id", "object_id", "content_type_id") VALUES (%s, %s, %s) RETURNING "taggit_taggedit
m"."id"'    

That long integer (287082253891563438098836942573405313042) trying to be insterted is obvsiouly the cause for the error. This number is the int of the UUID for foo_id

In [6]: foo.foo_id.int                      
Out[6]: 287082253891563438098836942573405313042  

Is there something I can set to allow django-taggit to play nicely with contenttypes and UUID?


Solution

  • Here's an answer based on Austin's comment.

    In django-taggit, references to tagged models are stored in a model named GenericTaggedItemBase under a field called object_id. The object_id field is hardcoded to models.IntegerField. So it's not possible to tag models having UUID primary keys. The code is located here.

    If all your models that need to be tagged are of the same type (in this case, models.UUIDField), then you can set object_id's type to models.UUIDField.

    Here are the changes that have to be made, assuming you're using virtualenvwrapper

    1. Locate the taggit package in the site packages folder. ~/virtualenvs/<your_virtualenv>/lib/<python_version>/site-packages/taggit

    2. Copy the taggit directory into your project.

    3. Delete the taggit directory from site-packages

    4. In the models.py file in taggit, replace

    object_id = models.IntegerField(verbose_name=_('Object id'), db_index=True) with

    object_id = models.UUIDField(verbose_name=_('Object id'), db_index=True)
    
    1. Migrate taggit.

    python manage.py makemigrations taggit

    python manage.py migrate