Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 230
Austin Avatar asked Jul 28 '15 17:07

Austin


2 Answers

I'd like to extend @Pramod response, that was very helpful for me to find the right answer:

Taggit has another class that allows to change the behavior of the TaggedItem

Here is a snippet of how to implement this solution:

from django.db import models
from django.utils.translation import ugettext_lazy as _

from taggit.managers import TaggableManager
from taggit.models import GenericUUIDTaggedItemBase, TaggedItemBase

class UUIDTaggedItem(GenericUUIDTaggedItemBase, TaggedItemBase):
    # If you only inherit GenericUUIDTaggedItemBase, you need to define
    # a tag field. e.g.
    # tag = models.ForeignKey(Tag, related_name="uuid_tagged_items", on_delete=models.CASCADE)

    class Meta:
        verbose_name = _("Tag")
        verbose_name_plural = _("Tags")

class Food(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    # ... fields here

    tags = TaggableManager(through=UUIDTaggedItem)

source: http://django-taggit.readthedocs.io/en/latest/custom_tagging.html#genericuuidtaggeditembase

like image 102
Rafael Aguilar Avatar answered Oct 31 '22 16:10

Rafael Aguilar


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

like image 3
Pramod Avatar answered Oct 31 '22 15:10

Pramod