发布于 2026-01-06 0 阅读
0

Django Slug + ID URL:复制 Dev.to 的 URL 模式 我们版本的 URL 未来展望 DEV 的全球展示挑战赛,由 Mux 呈现:展示你的项目!

Django Slug + ID URL:复制 Dev.to 的 URL 模式

我们版本的网址

展望未来

由 Mux 赞助的 DEV 全球展示挑战赛:展示你的项目!

我喜欢dev.to 的一点是它的 URL 设计。它将 slug 与代表某种内部索引值的哈希值结合起来,以确保唯一性。你可以在我的文章“自动生成 Makefile 文档”中看到一个例子,该文章的 URL 为“ https://dev.to/feldroy/autodocumenting-makefiles-175b ”。

让我们来分析一下这个网址:

  1. feldroy是我的公司名称。
  2. autodocumenting-makefiles这是个小白鼠,它是根据文章标题生成的。
  3. 175b是一个哈希值,要么存储在索引字符字段中,要么由路由器分解为数字主键。

以下是看待他们网址设计的另一种方式:

/<org-or-username>/<slugified-title>/<hashed-id>
Enter fullscreen mode Exit fullscreen mode

让我们看看如何使用 Django 来实现这种技术的简化版本。

我们版本的网址

我们将采用Dev.to实现的简化版本。我们的实现将使用数据库主键来确保唯一性,而不是Dev.to所依赖的哈希值。

/<username>/<slugified-title>/<primary-key>/
Enter fullscreen mode Exit fullscreen mode

好了,既然我们已经确定了网址设计,那就开始构建吧!

模型

存储数据!

# articles/models.py
from django.conf import settings
from django.db import models
from django.utils.translation import gettext_lazy as _

class Article(models.Model):

    title = models.CharField(_("Title"), max_length=100)
    slug = models.CharField(_("Slug"), max_length=100)
    author = models.ForeignKey(settings.AUTH_USER_MODEL, 
        on_delete=models.CASCADE)
    # More fields...
Enter fullscreen mode Exit fullscreen mode

表格

收集并验证数据!

# articles/forms.py
from django import forms

from .models import Article

class ArticleForm(forms.ModelForm):

    class Meta:
        model = Article
        fields = ('title', ) # more fields
Enter fullscreen mode Exit fullscreen mode

观点

现在我们有了模型和表单,接下来让我们构建视图:

# articles/views.py
from django.shortcuts import get_object_or_404
from django.contrib.auth.mixins import LoginRequiredMixin
from django.utils import slugify
from django.views.generic import CreateView, DetailView, UpdateView

from .forms import ArticleForm
from .models import Article


class ArticleCreateView(LoginRequiredMixin, CreateView):

    model = Article
    form_class = ArticleForm

    def form_valid(self, form):
        # Save the data to an article object - 
        #   this hasn't yet saved to the database.
        article = form.save(commit=False)
        article.slug = slugify(article.title)
        article.author = self.request.user
        # Save again - this time to the database
        article.save()
        return super().form_valid(form)


class ArticleUpdateView(LoginRequiredMixin, UpdateView):
    model = Article
    form_class = ArticleForm

    def get_object(self):
        # We get records by primary key, which ensures that
        # changes in the title or slug doesn't break links
        return get_object_or_404(Article,
            id=self.kwargs['pk'],
            author__username=self.kwargs['username'],
            author=self.request.user
        )

    def form_valid(self, form):
        # Update the slug if the title has changed.
        article = form.save(commit=False)
        article.slug = slugify(article.title)
        article.save()
        return super().form_valid(form)        


class ArticleDetailView(DetailView):
    model = Article

    def get_object(self):
        # We get records by primary key, which ensures that
        # changes in the title or slug doesn't break links
        return get_object_or_404(Article,
            id=self.kwargs['pk'],
            author__username=self.kwargs['username']
        )        
Enter fullscreen mode Exit fullscreen mode

网址

让我们把这个路由到我们的URL中:

# articles/urls.py
from django.urls import path

from articles import views

urlpatterns = [
    path(route='/new/',
        view=views.ArticleCreateView.as_view(),
        name='create',
    ),
    path(route='/<slug:username>/<slug:slug>/<int:pk>/edit/',
        view=views.ArticleUpdateView.as_view(),
        name='update',
    ), 
    path(route='/<slug:username>/<slug:slug>/<int:pk>/',
        view=views.ArticleDetailView.as_view(),
        name='detail',
    ),       
]
Enter fullscreen mode Exit fullscreen mode

在项目根配置文件中,我们添加以下内容:

# config/urls.py or wherever you stick the project's root urls.py
from django.conf.urls.static import static
from django.contrib import admin
from django.urls import include, path

urlpatterns = [
    # Django Admin, change this URL
    path('two-scoops-of-django-is-awesome', admin.site.urls),
    # Articles management
    path('', include('articles.urls', namespace='article')),
    # More URLS here
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

# There's certainly more URLs down here
Enter fullscreen mode Exit fullscreen mode

添加模板,瞧,一个遵循Dev.to URL 设计的 Django 示例就完成了!

展望未来

经验丰富的 Django 用户都知道,方法中的 slugification 逻辑form_valid应该放在 Article 模型的方法中,而不是视图中。这正是我们在《Django 入门指南》save()中讨论的内容

说到这里,如果你想学习各种高级技巧和窍门,可以看看我和我妻子合著的以冰淇淋为主题的Django 最佳实践书籍课程。

丹尼尔和奥黛丽手持两勺 Django 3.x 的图片

文章来源:https://dev.to/danielfeldroy/django-slug-id-url-design-3l8b