=============
Quick Start
=============

This guide will help you quickly implement tagging functionality in your Django application using dj-flexi-tag.

Preparing Your Models
===================

First, let's make your existing models "taggable" by adding the FlexiTagMixin:

.. code-block:: python

    from django.db import models
    from flexi_tag.utils.models import FlexiTagMixin

    class Product(FlexiTagMixin):
        name = models.CharField(max_length=100)
        price = models.DecimalField(max_digits=10, decimal_places=2)
        # other fields...

    class Article(FlexiTagMixin):
        title = models.CharField(max_length=200)
        content = models.TextField()
        # other fields...

The FlexiTagMixin doesn't add any fields to your models - it simply marks them for tag model generation.

Generating Tag Models
===================

After adding the FlexiTagMixin to your models, run the management command to generate the corresponding tag models:

.. code-block:: bash

    # Standard usage
    python manage.py generate_tag_models

    # For testing what would be generated without creating files
    python manage.py generate_tag_models --dry-run

    # If models aren't detected after recent changes (development mode)
    python manage.py generate_tag_models --force-reload

This command will create files named `flexi_generated_model.py` in the same directories as your models. It will also automatically run the `makemigrations` command to create the necessary migration files for the new tag models.

.. note::
   If you've just added FlexiTagMixin to a model and the command doesn't detect it,
   try using the ``--force-reload`` flag or restart your Django development server.

For example, the generated tag model will look like this:

.. code-block:: python

    # products/flexi_generated_model.py

    # This file is auto-generated. Do not edit manually.
    # Generated by the generate_tag_models command.

    from django.db import models

    from flexi_tag.utils.compat import GinIndex, JSONField


    class ProductTag(models.Model):
        instance = models.OneToOneField(
            "products.Product",
            on_delete=models.CASCADE,
            primary_key=True,
        )
        tags = JSONField(default=list)

        class Meta:
            app_label = "products"
            db_table = "products_product_tag"
            indexes = [GinIndex(fields=["tags"])]

        def __str__(self):
            return "Tags for {}".format(self.instance)

The command will also automatically add the necessary import to your original models.py file:

.. code-block:: python

    # At the bottom of your imports in models.py
    from .flexi_generated_model import ProductTag  # noqa

If you have multiple models with the FlexiTagMixin in the same app, the imports will be combined in a single line:

.. code-block:: python

    # At the bottom of your imports in models.py
    from .flexi_generated_model import ArticleTag, ProductTag  # noqa

Creating and Applying Migrations
==============================

After the tag models have been generated and migrations created automatically, you only need to apply the migrations:

.. code-block:: bash

    python manage.py migrate

Adding API Support
===============

To expose tagging functionality through a REST API, add the TaggableViewSetMixin to your ViewSets:

.. code-block:: python

    from rest_framework import viewsets

    from flexi_tag.utils.views import TaggableViewSetMixin

    from .models import Product
    from .serializers import ProductSerializer

    class ProductViewSet(viewsets.ModelViewSet, TaggableViewSetMixin):
        queryset = Product.objects.all()
        serializer_class = ProductSerializer

This adds the following endpoints to your ViewSet:

* `POST /products/{id}/add_tag/` - Add a tag to a product
* `POST /products/{id}/bulk_add_tag/` - Add multiple tags to a product
* `POST /products/{id}/remove_tag/` - Remove a tag from a product
* `POST /products/{id}/bulk_remove_tags/` - Remove multiple tags from a product
* `POST /products/bulk_add_tags/` - Add tags to multiple products
* `POST /products/bulk_remove_tags_with_many_instances/` - Remove tags from multiple products

Using the API
===========

Adding a Single Tag
-----------------

.. code-block:: http

    POST /api/products/1/add_tag/
    Content-Type: application/json

    {
      "key": "featured"
    }

Adding Multiple Tags
-----------------

.. code-block:: http

    POST /api/products/1/bulk_add_tag/
    Content-Type: application/json

    {
      "keys": ["new", "sale", "limited-edition"]
    }

Removing a Tag
------------

.. code-block:: http

    POST /api/products/1/remove_tag/
    Content-Type: application/json

    {
      "key": "featured"
    }

Removing Multiple Tags
-------------------

.. code-block:: http

    POST /api/products/1/bulk_remove_tags/
    Content-Type: application/json

    {
      "keys": ["new", "sale"]
    }

Bulk Operations
-------------

Add tags to multiple products:

.. code-block:: http

    POST /api/products/bulk_add_tags/
    Content-Type: application/json

    {
      "objects": [1, 2, 3, 4],
      "keys": ["clearance", "last-chance"]
    }

Remove tags from multiple products:

.. code-block:: http

    POST /api/products/bulk_remove_tags_with_many_instances/
    Content-Type: application/json

    {
      "objects": [1, 2, 3, 4],
      "keys": ["new-arrival"]
    }

Programmatic Usage
================

You can also manage tags programmatically in your application code:

.. code-block:: python

    from flexi_tag.utils.service import TaggableService

    # Create a service instance
    tag_service = TaggableService()

    # Get a product instance
    product = Product.objects.get(id=1)

    # Add a tag
    tag_service.add_tag(instance=product, key="featured")

    # Add multiple tags
    tag_service.bulk_add_tags(instance=product, keys=["sale", "new"])

    # Remove a tag
    tag_service.remove_tag(instance=product, key="featured")

    # Bulk operations
    products = Product.objects.filter(in_stock=True)
    tag_service.bulk_add_tags_with_many_instances(instances=products, keys=["available"])

Next Steps
=========

Now that you have basic tagging functionality working, you can explore:

* :doc:`advanced` - For custom tag validation, advanced queries, and more
* :doc:`api` - For a complete API reference
