168 lines
6.0 KiB
Plaintext
168 lines
6.0 KiB
Plaintext
Using a Custom Tag or Through Model
|
|
===================================
|
|
|
|
By default ``django-taggit`` uses a "through model" with a
|
|
``GenericForeignKey`` on it, that has another ``ForeignKey`` to an included
|
|
``Tag`` model. However, there are some cases where this isn't desirable, for
|
|
example if you want the speed and referential guarantees of a real
|
|
``ForeignKey``, if you have a model with a non-integer primary key, or if you
|
|
want to store additional data about a tag, such as whether it is official. In
|
|
these cases ``django-taggit`` makes it easy to substitute your own through
|
|
model, or ``Tag`` model.
|
|
|
|
To change the behavior there are a number of classes you can subclass to obtain
|
|
different behavior:
|
|
|
|
=============================== =======================================================================
|
|
Class name Behavior
|
|
=============================== =======================================================================
|
|
``TaggedItemBase`` Allows custom ``ForeignKeys`` to models.
|
|
``GenericTaggedItemBase`` Allows custom ``Tag`` models. Tagged models use an integer primary key.
|
|
``GenericUUIDTaggedItemBase`` Allows custom ``Tag`` models. Tagged models use a UUID primary key.
|
|
``CommonGenericTaggedItemBase`` Allows custom ``Tag`` models and ``GenericForeignKeys`` to models.
|
|
``ItemBase`` Allows custom ``Tag`` models and ``ForeignKeys`` to models.
|
|
=============================== =======================================================================
|
|
|
|
Custom ForeignKeys
|
|
~~~~~~~~~~~~~~~~~~
|
|
|
|
Your intermediary model must be a subclass of
|
|
``taggit.models.TaggedItemBase`` with a foreign key to your content
|
|
model named ``content_object``. Pass this intermediary model as the
|
|
``through`` argument to ``TaggableManager``::
|
|
|
|
from django.db import models
|
|
|
|
from taggit.managers import TaggableManager
|
|
from taggit.models import TaggedItemBase
|
|
|
|
|
|
class TaggedFood(TaggedItemBase):
|
|
content_object = models.ForeignKey('Food')
|
|
|
|
class Food(models.Model):
|
|
# ... fields here
|
|
|
|
tags = TaggableManager(through=TaggedFood)
|
|
|
|
|
|
Once this is done, the API works the same as for GFK-tagged models.
|
|
|
|
Custom GenericForeignKeys
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
The default ``GenericForeignKey`` used by ``django-taggit`` assume your
|
|
tagged object use an integer primary key. For non-integer primary key,
|
|
your intermediary model must be a subclass of ``taggit.models.CommonGenericTaggedItemBase``
|
|
with a field named ``"object_id"`` of the type of your primary key.
|
|
|
|
For example, if your primary key is a string::
|
|
|
|
from django.db import models
|
|
|
|
from taggit.managers import TaggableManager
|
|
from taggit.models import CommonGenericTaggedItemBase, TaggedItemBase
|
|
|
|
class GenericStringTaggedItem(CommonGenericTaggedItemBase, TaggedItemBase):
|
|
object_id = models.CharField(max_length=50, verbose_name=_('Object id'), db_index=True)
|
|
|
|
class Food(models.Model):
|
|
food_id = models.CharField(primary_key=True)
|
|
# ... fields here
|
|
|
|
tags = TaggableManager(through=GenericStringTaggedItem)
|
|
|
|
GenericUUIDTaggedItemBase
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
.. note::
|
|
|
|
``GenericUUIDTaggedItemBase`` relies on Django UUIDField introduced with
|
|
Django 1.8. Therefore ``GenericUUIDTaggedItemBase`` is only defined
|
|
if you are using Django 1.8+.
|
|
|
|
A common use case of a non-integer primary key, is UUID primary key.
|
|
``django-taggit`` provides a base class ``GenericUUIDTaggedItemBase`` ready
|
|
to use with models using an UUID primary key::
|
|
|
|
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)
|
|
|
|
Custom tag
|
|
~~~~~~~~~~
|
|
|
|
When providing a custom ``Tag`` model it should be a ``ForeignKey`` to your tag
|
|
model named ``"tag"``:
|
|
|
|
.. code-block:: python
|
|
|
|
from django.db import models
|
|
from django.utils.translation import ugettext_lazy as _
|
|
|
|
from taggit.managers import TaggableManager
|
|
from taggit.models import TagBase, GenericTaggedItemBase
|
|
|
|
|
|
class MyCustomTag(TagBase):
|
|
# ... fields here
|
|
|
|
class Meta:
|
|
verbose_name = _("Tag")
|
|
verbose_name_plural = _("Tags")
|
|
|
|
# ... methods (if any) here
|
|
|
|
|
|
class TaggedWhatever(GenericTaggedItemBase):
|
|
# TaggedWhatever can also extend TaggedItemBase or a combination of
|
|
# both TaggedItemBase and GenericTaggedItemBase. GenericTaggedItemBase
|
|
# allows using the same tag for different kinds of objects, in this
|
|
# example Food and Drink.
|
|
|
|
# Here is where you provide your custom Tag class.
|
|
tag = models.ForeignKey(MyCustomTag,
|
|
related_name="%(app_label)s_%(class)s_items")
|
|
|
|
|
|
class Food(models.Model):
|
|
# ... fields here
|
|
|
|
tags = TaggableManager(through=TaggedWhatever)
|
|
|
|
|
|
class Drink(models.Model):
|
|
# ... fields here
|
|
|
|
tags = TaggableManager(through=TaggedWhatever)
|
|
|
|
|
|
.. class:: TagBase
|
|
|
|
.. method:: slugify(tag, i=None)
|
|
|
|
By default ``taggit`` uses :func:`django.template.defaultfilters.slugify`
|
|
to calculate a slug for a given tag. However, if you want to implement
|
|
your own logic you can override this method, which receives the ``tag``
|
|
(a string), and ``i``, which is either ``None`` or an integer, which
|
|
signifies how many times the slug for this tag has been attempted to be
|
|
calculated, it is ``None`` on the first time, and the counting begins
|
|
at ``1`` thereafter.
|