# Tagging Publications ## Example Overview - **Objective**: This example demonstrates how to implement tagging functionality in a Django form using `django_tomselect`. Users can create new tags dynamically or select from existing ones. The tags are validated and saved to the database with support for autocomplete and real-time updates. - **Features Highlighted**: - Support for dynamic tag creation with the `create` feature. - Real-time autocomplete of existing tags using `django_tomselect`. - **Use Case**: - Content management systems where articles or products require tagging for organization and filtering. - Applications requiring user-generated metadata to categorize or describe entities. **Visual Examples**   ## Key Code Segments ### Forms The form uses a custom `DynamicTagField`, a subclass of `TomSelectMultipleChoiceField`, to allow dynamic creation and selection of tags. The most complex part of the form is the `clean_tags` method, which validates and saves tags to the database. :::{admonition} Form Definition :class: dropdown ```python class DynamicTagField(TomSelectMultipleChoiceField): """A custom field that allows new values to be created on the fly.""" def clean(self, value): """Override to allow values that aren't in the autocomplete results yet.""" if not value: if self.required: raise ValidationError(self.error_messages["required"], code="required") return [] # Convert all values to strings str_values = [str(v) for v in value] return str_values class TaggingForm(forms.Form): """Form for managing publication tags with validation.""" tags = DynamicTagField( config=TomSelectConfig( url="autocomplete-publication-tag", value_field="value", label_field="label", placeholder="Enter tags...", highlight=True, create=True, minimum_query_length=2, max_items=10, plugin_dropdown_header=PluginDropdownHeader( title="Publication Tags", extra_columns={"usage_count": "Usage Count", "created_at": "Created"}, ), plugin_remove_button=PluginRemoveButton(title="Remove tag", label="×", class_name="remove-tag"), ), help_text=( "Enter or select tags. Tags must be 2-50 characters long, " "contain only letters, numbers, hyphens, and underscores, " "and start/end with letters or numbers." ), ) def clean_tags(self): """Validate tags and create/update them in the database.""" tag_names = self.cleaned_data.get("tags", []) if len(tag_names) < 1: raise ValidationError("Please add at least one tag") if len(tag_names) > 10: raise ValidationError("Maximum 10 tags allowed") # Check for duplicates (case-insensitive) lower_names = [name.lower() for name in tag_names] if len(lower_names) != len(set(lower_names)): raise ValidationError("Duplicate tags are not allowed") # Process each tag tags = [] for name in tag_names: # Clean the tag name name = name.lower().strip() # Validate the tag format if len(name) < 2: raise ValidationError(f"Tag '{name}' is too short") if not all(c.isalnum() or c in "-_" for c in name): raise ValidationError(f"Tag '{name}' contains invalid characters") if "--" in name or "__" in name: raise ValidationError(f"Tag '{name}' contains consecutive special characters") if not name[0].isalnum() or not name[-1].isalnum(): raise ValidationError(f"Tag '{name}' must start and end with a letter or number") # Try to get existing tag or create new one tag, _ = PublicationTag.objects.get_or_create( name=name, defaults={"is_approved": True}, ) tags.append(tag) return tags ``` ::: **Explanation**: - The `DynamicTagField` allows users to add new tags on the fly. - The `clean_tags` method ensures all tags are validated and saved to the database. ### Templates The form is rendered in the `tagging_publication.html` template, providing an intuitive interface for managing tags. :::{admonition} Main Template :class: dropdown ```html {% extends 'example/base_with_bootstrap5.html' %} {% block extra_header %} {{ form.media.css }} {{ form.media.js }} {% endblock %} {% block content %}
This example is a sort of hybrid, backed by AutocompleteModelView, but using a TomSelectMultipleChoiceField subclass to handle the tag input. The form is rendered with the TomSelect widget, and the tags are saved to the database.
Add or select tags for your publication. Valid tag examples: