如何在 Django 中为模型添加标签 | Django 软件包系列 #1 django-taggit-tutorial

2025-06-07

如何在 Django 中为模型添加标签 | Django 软件包系列 #1

django-taggit 教程

这篇文章与OnePublish交叉发布

嘿,开发人员!

欢迎阅读 Django 包系列的第一篇文章。在本教程中,您将学习如何为模型添加标记功能。

类别和标签可以帮助您组织网站或博客,并帮助用户找到他们想要的信息。博客类别是您在博客中讨论的主题。您的类别列表就像您博客的目录。标签则更为具体,用于定位您在特定博客文章中讨论的内容。标签通常只有一两个词,反映了文章的关键词或要点。如果说类别是博客的目录,那么标签就是博客的索引。通过使用相关的关键词标记文章,用户可以轻松找到信息,从而使您的博客更加专业。

django-taggit是一个可复用的应用程序,它主要提供了一个标签模型和一个管理器,方便用户轻松地向任何模型添加标签。我们将创建一个非常简单的博客应用,并在其中实现标签系统。

我假设你已经创建了 Django 项目。让我们开始使用以下命令安装包:

pip3 install django-taggit
Enter fullscreen mode Exit fullscreen mode

安装完成后,打开settings.py并将 taggit 包含在 INSTALLED_APPS 中

INSTALLED_APPS = [
    ...
    'taggit'
]

Enter fullscreen mode Exit fullscreen mode

创建模型

现在,打开models.py并创建 Post 模型:

from django.db import models
from taggit.managers import TaggableManager

class Post(models.Model):
    title = models.CharField(max_length=250)
    description = models.TextField()
    published = models.DateField(auto_now_add=True)
    slug = models.SlugField(unique=True, max_length=100)
    tags = TaggableManager()

    def __str__(self):
        return self.title
Enter fullscreen mode Exit fullscreen mode

TaggableManager 将自动显示为 ModelForm 或管理面板中的一个字段。通过表单字段输入的标签解析如下:

  • 如果输入不包含任何逗号或双引号,则将其视为以空格分隔的标签名称列表。
  • 如果输入确实包含这些字符之一
    • 双引号内的字符组优先作为多词标签(因此双引号内的标签名可以包含逗号)。未闭合的双引号将被忽略。
    • 否则,如果输入中有任何未加引号的逗号,则将其视为逗号分隔。如果没有,则将其视为空格分隔。

django-taggit

创建表单

在您的forms.py中:

from django import forms
from .models import Post

class PostForm(forms.ModelForm):
    class Meta:
        model = Post
        fields = [
            'title',
            'description',
            'tags',
        ]
Enter fullscreen mode Exit fullscreen mode

我们在 ModelForm 中包含了标签,但我们不会使用 Django 的模板语言来呈现它。

创建视图

让我们看看views.py

from django.shortcuts import render, get_object_or_404
from django.template.defaultfilters import slugify

from .models import Post
from .forms import PostForm
from taggit.models import Tag


def home_view(request):
    posts = Post.objects.order_by('-published')
    # Show most common tags 
    common_tags = Post.tags.most_common()[:4]
    form = PostForm(request.POST)
    if form.is_valid():
        newpost = form.save(commit=False)
        newpost.slug = slugify(newpost.title)
        newpost.save()
        # Without this next line the tags won't be saved.
        form.save_m2m()
    context = {
        'posts':posts,
        'common_tags':common_tags,
        'form':form,
    }
    return render(request, 'home.html', context)

def detail_view(request, slug):
    post = get_object_or_404(Post, slug=slug)
    context = {
        'post':post,
    }
    return render(request, 'detail.html', context)

def tagged(request, slug):
    tag = get_object_or_404(Tag, slug=slug)
    # Filter posts by tag name  
    posts = Post.objects.filter(tags=tag)
    context = {
        'tag':tag,
        'posts':posts,
    }
    return render(request, 'home.html', context)
Enter fullscreen mode Exit fullscreen mode

保存表单时,您必须使用 commit=False 选项,并在保存对象后在表单上调用 save_m2m()。

我们正在使用 slugify 将我们的帖子标题(字符串)转换为有效的 slug。

如您所见,您可以按标签名称过滤帖子并显示最常用的标签。

创建模板

太棒了!现在我们可以创建模板了。

基础.html

<html>
    <head>
        <title>Simple Blog</title>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
        <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
        <link rel="stylesheet" href="/static/css/tagsinput.css" />
    </head>

    <body>
    {% block content %}{% endblock content %}
    <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
    <script src="/static/js/tagsinut.js"></script>
    <script>
    $("#post-form").submit(function(e){
        e.preventDefault();
        });</script>
    </body>
</html>
Enter fullscreen mode Exit fullscreen mode

主页.html

{% extends 'base.html' %}

{% block content %}
        <div class="container pt-5">
            <form method="POST">
                {% csrf_token %}
                <div class="form-group">
                    <label>Title</label>
                    <input type="text" class="form-control" name="title" placeholder="Add title">
                </div>
                <div class="form-group">
                    <label>Description</label>
                    <textarea type="text" class="form-control" name="description" placeholder="Add description"></textarea>
                </div>
                <div class="form-group">
                    <label>Tags</label>
                    <input type="text" data-role="tagsinput" class="form-control" name="tags">
                </div>
                <button type="submit" class="btn btn-primary">Submit</button>
            </form>
            <p>Common Tags: 
            {% for mt in common_tags %}
                <a href="#" class="badge badge-success">{{mt}}</a>
            {% endfor %}
            </p>
            <div class="row mb-2 posts">
                    {% for post in posts %}
                    <div class="col-md-6">
                        <div class="cards">
                            <div class="row no-gutters border rounded  flex-md-row mb-4 shadow-sm h-md-250">
                                <div class="col p-4 d-flex flex-column position-static">
                                    <h3 class="my-1"><a href="{% url 'detail' post.slug %}">{{post.title}}</a></h3>
                                    <div style="display:flex">
                                        {% for tag in post.tags.all %}
                                        <a href="{% url 'tagged' tag.slug %}" class="mr-1 badge badge-info">#{{ tag }}</a>
                                        {% endfor %}
                                    </div>
                                    <p class="mb-auto">{{post.description}}</p>
                                    <p class="mb-auto text-muted">{{post.published}}</p>
                                </div>
                            </div>
                        </div>       
                    </div>
                    {% endfor %}
            </div>
        </div>    
{% endblock content %}               
Enter fullscreen mode Exit fullscreen mode

在 form 标签中,你可以看到 name 属性,它就是 HTML 模板中表单字段的名称属性。我们必须覆盖标签 input,这也是为什么我们没有使用 Django 模板语言渲染它的主要原因。

我们使用了 jQuery 插件,它提供了一个 Twitter Bootstrap 用户界面来管理标签。这个插件基本上会将文本输入转换为实际的标签。请查看Bootstrap 标签输入

以下是最终结果:

并按标签过滤帖子:

查看django-taggit的文档以了解更多信息。

您可以从我的 GitHub 克隆或下载该项目

GitHub 徽标 thepylot / django-taggit-tutorial

使用 django-taggit 为模型添加标签 | Django 包系列

django-taggit 教程

使用 django-taggit 为你的模型添加标签 | Django 软件包系列 #1

入门

该项目适用于Python 3+和 Django 2+。

安装依赖项:

python3 -m pip3 install -r requirements.txt

然后运行以下命令:

python3 manage.py makemigrations posts
python3 manage.py migrate
python3 manage.py runserver

就这样!请在社交媒体上分享并关注我(你的支持非常重要)!:) 也请查看《Reverse Python》,并一如既往地保持联系!🚀

请我喝杯咖啡 :)
Instagram
Twitter

文章来源:https://dev.to/thedevtimeline/how-to-add-tags-to-your-models-in-django-django-packages-series-1-3704
PREV
使用 Django 实现无限滚动
NEXT
如何设置 Web 服务器 AWS GenAI LIVE!