============ Model Fields ============ Tagulous offers two new model field types: * :ref:`model_tagfield` - conventional tags using a ``ManyToManyField`` relationship. * :ref:`model_singletagfield` - the same UI and functionality as a ``TagField`` but for a single tag, using a ``ForeignKey`` relationship. These will automatically create the models for the tags themselves, or you can provide a custom model to use instead with ``to`` - see :ref:`custom_tag_models` for more details. Tagulous lets you get and set string values using these fields, while still leaving the underlying relationships available. For example, not only can you assign a queryset or list of tag primary keys to a ``TagField``, but you can also assign a list of tag names, or a tag string to parse. Like a ``CharField``, changes made by assigning a value will not be committed until the model is saved, although you can still make immediate changes by calling the standard m2m methods ``add``, ``remove`` and ``clear``. If ``TAGULOUS_ENHANCE_MODELS`` is ``True`` (which it is by default - see :ref:`settings`), you can also use tag strings and lists of tag names in ``get`` and ``filter``, and model constructors and ``object.create()`` - see :doc:`tagged_models` for more details. .. _model_field_arguments: Model Field Arguments ===================== The ``SingleTagField`` supports most standard ``ForeignKey`` arguments, except for ``to_field`` and ``rel_class``. The ``TagField`` supports most normal ``ManyToManyField`` arguments, except for ``db_table``, ``through`` and ``symmetrical``. Also note that ``blank`` has no effect at the database level, it is just used for form validation - as is the case with a normal ``ManyToManyField``. The ``related_name`` will default to ``_set``, as is normal for a ``ForeignKey`` or ``ManyToManyField``. If using the same tag table on multiple fields, you will need to set this to something else to avoid clashes. .. _field_auto_model: Auto-generating a tag model --------------------------- If the :ref:`to argument ` is not set, a tag model will be auto-generated for you. It will be given a class name based on the names of the tagged model and tag field; for example, the class name of the auto-generated model for ``MyModel.tags`` would be ``Tagulous_MyModel_tags``. When auto-generating a model, any :ref:`model option ` can be passed as a field argument - see the :ref:`example_auto_tagmodel` example. If you want to override the default base class, for convenience you can specify a custom base class for the auto tag model - see the :ref:`argument_to_base` argument for details. .. _field_explicit_model: Specifying a tag model ---------------------- You can specify the tag model for the tag field to use with the :ref:`to argument `. You cannot specify any tag options. .. _argument_to: ``to=MyTagModel`` (or first unnamed argument) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Manually specify a tag model for this tag field. This can either be a reference to the tag model class, or string reference to it in the format ``app.model``. This will normally be a :ref:`custom tag model `, which must be a subclass of ``tagulous.models.TagModel``. It can also be a reference to a tag model already auto-generated by another tag field, eg ``to=MyOtherModel.tags.tag_model``, although you must be confident that ``MyOtherModel`` will always be defined first. It can also be a string containing the name of the tag model, eg ``to='MyTagModel'``. However, this is resolved using Django's standard model name resolution, so you have to reference auto-generated models by their class name, not via the field - eg ``to='otherapp.Tagulous_MyOtherModel_tags'``. If the tagged model for this field is also a custom tag model, you can specify a recursive relationship as normal, using ``'self'``. If it is a custom tag model, it should have a :ref:`tagmeta` class. Fields which specify their tag model cannot provide new tag model options; they will take their options from the model - see :doc:`../tag_options` for more details. This argument is optional; if omitted, a tag model will be :ref:`auto-generated ` for you. Default: ``Tagulous__`` (auto-generated) .. _argument_to_base: ``to_base=MyTagModelBase`` ~~~~~~~~~~~~~~~~~~~~~~~~~~ You can specify a base class to use for an auto-generated tag model, instead of using ``TagModel``. This can be useful on complex sites where multiple auto-generated tag models need to share common custom functionality - for example, tracking and filtering by user who creates the tags. This argument will allow you to define one base class and re-use it across your project with less boilerplate than defining many empty custom tag models. Default: ``tagulous.models.TagModel`` .. _model_singletagfield: ``tagulous.models.SingleTagField`` ================================== Unbound field ------------- An unbound ``SingleTagField`` (called on a model class, eg ``MyModel.tag``) acts in the same way an unbound ``ForeignKey`` field would, but also has: ``tag_model`` The related tag model ``tag_options`` A :ref:`TagOptions ` class, containing the options from the tag model's :ref:`tagmeta` or passed as arguments when initialising the field. Bound to an instance -------------------- A bound ``SingleTagField`` (called on an instance, eg ``instance.tags``) acts in a similar way to a bound ``ForeignKey``, but with some differences: Assignment (setter) A bound ``SingleTagField`` can be assigned a tag (an instance of the tag model) or a tag name. If it is passed ``None``, a current tag will be cleared if it is set. The instance must be saved afterwards. Example:: person.title = "Mr" person.save() Evaluation (getter) The value of a bound ``SingleTagField`` will return an instance of the tag model. The tag may not exist in the database yet (its ``pk`` may be ``None``). Example:: tag = person.title report = "Tag %s used %d times " % (tag.name, tag.count) The ``tag_model`` and ``tag_options`` attributes are not available on a bound field. If you only have an instance of the tagged model, you can access them by finding its class, eg ``type(person).title.tag_model``. .. _model_tagfield: ``tagulous.models.TagField`` ============================ Unbound field ------------- An unbound ``TagField`` (called on a model class, eg ``MyModel.tags``) acts in the same way an unbound ``ManyToManyField`` would, but also has: ``tag_model`` The related tag model ``tag_options`` A :ref:`TagOptions ` class, containing the options from the tag model's :ref:`tagmeta` or passed as arguments when initialising the field. Bound to an instance -------------------- A bound ``TagField`` (called on an instance, eg ``instance.tags``) acts in a similar way to a bound ``ManyToManyField``, but with some differences: Assignment (setter) A bound ``TagField`` can be assigned a tag string or an iterable of tags or tag names, eg a list of strings, or a queryset of instances of the tag model. If it is passed ``None``, any current tags will be cleared. The instance must be saved afterwards. Example:: person.skills = 'Judo, "Kung Fu"' person.save() Evaluation (getter) A bound ``TagField`` will return a :ref:`tagrelatedmanager` object, which has functions to get and set tag values. .. _tagrelatedmanager: ``tagulous.models.TagRelatedManager`` ------------------------------------- A ``TagRelatedManager`` is a subclass of Django's standard ``RelatedManager``, so you can do anything you would normally do with a bound ``ManyToManyField``:: person.skills.get(name='judo') tags = person.skills.all() person.skills.add(MyTag) person.skills.clear() Because it's a relationship to a :doc:`tag model `, you can also filter by its fields:: filtered_tags = person.skills.filter(name__startswith='a') popular_tags = person.skills.filter(count__gte=10) A ``TagRelatedManager`` also provides access to the field's ``tag_model`` and ``tag_options``:: person.skills.tag_model.objects.all() is_lowercase = person.skills.tag_options.force_lowercase It also provides the following additional methods: ``set_tag_string(tag_string)`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Sets the tags for this instance, given a tag string. :: person.skills.set_tag_string('Judo, "Kung Fu"') person.save() ``set_tag_list(tag_list)`` ~~~~~~~~~~~~~~~~~~~~~~~~~~ Sets the tags for this instance, given an iterable of tag names or tag instances. :: person.skills.set_tag_list(['Judo', kung_fu_tag]) person.save() ``get_tag_string()`` ~~~~~~~~~~~~~~~~~~~~ Gets the tags as a tag string. :: tag_string = person.skills.get_tag_string() # tag_string == 'Judo, "Kung Fu"' ``get_tag_list()`` ~~~~~~~~~~~~~~~~~~ Returns a list of tag names. :: tag_list = person.skills.get_tag_list() # tag_list == ['Judo', 'Kung Fu'] ``__str__()``, ``__unicode__()`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Same as ``get_tag_string`` :: report = '%s' % person.skills ``__eq__``, ``__ne__`` ~~~~~~~~~~~~~~~~~~~~~~ Compare the tags on this instance to a tag string, or an iterable of tags or tag names. Order does not matter, and case sensitivity is determined by the options :ref:`option_case_sensitive` and :ref:`option_force_lowercase`. :: if ( first.tags == second.tags or first.tags == ['Judo', kung_fu_tag] or first.tags != 'foo, bar' or first.tags != second.tags.filter(name__istartswith='k') ): ... ``__contains__`` ~~~~~~~~~~~~~~~~ See if the tag (or string of a tag name) is in the tags. Case sensitivity is determined by the options :ref:`option_case_sensitive` and :ref:`option_force_lowercase`. :: if 'Judo' in person.skills and kung_fu_tag in person.skills: candidates.append(person) ``reload()`` ~~~~~~~~~~~~ Discard any unsaved changes to the tags and load tags from the database :: person.skills = 'judo' person.save() person.skills = 'karate' person.skills.reload() # person.skills == 'judo' ``save(force=False)`` ~~~~~~~~~~~~~~~~~~~~~ Commit any tag changes to the database. If you are only changing the tags you can call this directly to reduce database operations. .. note:: You do not need to call this if you are saving the instance; the manager listens to the instance's save signals and saves any changes to tags as part of that process. In most circumstances you can ignore the ``force`` flag: * The manager has a ``.changed`` flag which is set to ``False`` whenever the internal tag cache is loaded or saved. It is set to ``True`` when the tags are changed without being saved. * If ``force=False`` (default), this method will only update the database if the ``.changed`` flag is ``True`` - in other words, the database will only be updated if there are changes to the internal cache since last load or save. * If ``force=True``, the ``.changed`` flag will be ignored, and the current tag status will be forced upon the database. This can be useful in the rare cases where you have multiple references to the same database object, and want the tags on this instance to override any changes other instances may have made. For example:: person = Person.objects.create(name='Adam', skills='judo') person.name = 'Bob' person.skills = 'karate' person.skills.save() # person.name == 'Adam' # person.skills == 'judo' ``add(tag, tag, ...)`` ~~~~~~~~~~~~~~~~~~~~~~ Based on the normal ``RelatedManager.add`` method, but has support for tag names. Adds a list of tags or tag names directly to the instance - there is no need to save afterwards. .. note:: This does not parse tag strings - you need to pass separate tags as either instances of the tag model, or as separate strings. Will call ``reload()`` first, so any unsaved changes to tags will be lost. :: person.skills.add('Judo', kung_fu_tag) ``remove(tag, tag, ...)`` ~~~~~~~~~~~~~~~~~~~~~~~~~ Based on the normal ``RelatedManager.remove`` method, but has support for tag names. Removes a list of tags or tag names directly from the instance - there is no need to save afterwards. .. note:: This does not parse tag strings - you need to pass separate tags as either instances of the tag model, or as separate strings. Will call ``reload()`` first, so any unsaved changes to tags will be lost. :: person.skills.remove('Judo', kung_fu_tag)