首页 > 解决方案 > 为什么我不能在 Django Rest Framework 中为父母和孩子使用自定义 slug?

问题描述

我正在尝试为父子模型使用自定义 slug。

楷模:

# models.py

class Parent(models.Model):
    slug = models.SlugField()

class Child(models.Model):
    parent = models.ForeignKey(Parent)
    order = models.IntegerField()
    slug = models.SlugField()

    class Meta:
        ordering = ['order', 'pk']

    def save(self, *args, **kwargs):
        self.slug = f"{parent.slug}/{self.order}"
        super(Text, self).save(*args, **kwargs)

    def get_absolute_url(self):
            return reverse("app:child-detail", kwargs={"slug": self.slug})

Child 模型将在其 slug 中使用其顺序和 Parent 的 slug。

我可以<int:pk>在 URL 中使用默认值,但是当我尝试将其交换为 时<slug:slug>,我在 List 和 Detail 视图中都收到此错误:

无法使用视图名称“app:child-detail”解析超链接关系的 URL。您可能未能在 API 中包含相关模型,或者lookup_field该字段的属性配置错误。

当我尝试在子对象上调用 get_absolute_url() 时(其中顺序为“1”且父项的 slug 为“parent-slug”),我收到以下错误:

django.urls.exceptions.NoReverseMatch:使用关键字参数'{'slug':'parent-slug/1'}'反转'child-detail'。尝试了 2 种模式:['api/v1/child/(?P[-a-zA-Z0-9_]+)(?P\.[a-z0-9]+/?)$', ' api/v1/child/(?P[-a-zA-Z0-9_]+)$']

网址:

# project urls.py

urlpatterns = [
    path("admin/", admin.site.urls),
    path("api/v1/", include("app.urls", namespace="app")),
    path("api-auth/", include("rest_framework.urls")),  # login for Browserable API
]

# app urls.py

from django.urls import path, include
from rest_framework.urlpatterns import format_suffix_patterns

app_name = "app"
urlpatterns = [
    path("children/", ChildList.as_view(), name="child-list"),
    path("child/<slug:slug>", ChildDetail.as_view(), name="child-detail"),
]

urlpatterns = format_suffix_patterns(urlpatterns)

意见:

# app views.py

class ChildList(generics.ListCreateAPIView):
    queryset = Child.objects.all()
    serializer_class = ChildSerializer
    lookup_field = "slug"

class ChilldDetail(generics.RetrieveUpdateDestroyAPIView):
    queryset = Child.objects.all()
    serializer_class = ChildDetailSerializer
    lookup_field = "slug"

序列化器:

# app serializers.py

class ChildSerializer(serializers.HyperlinkedModelSerializer):
    url = HyperlinkedIdentityField(
        view_name="app:child-detail", lookup_field="slug"
    )

    class Meta:
        fields = ("url", "pk")
        model = Child
        # Commented out code below also doesn't work
        # lookup_field = "slug"
        # extra_kwargs = {"url": {"lookup_field": "slug"}}

class ChildDetailSerializer(serializers.HyperlinkedModelSerializer):
    url = HyperlinkedIdentityField(
        view_name="app:child-detail", lookup_field="slug"
    )

    class Meta:
        fields = ("url", "pk")
        model = Child
        # Commented out code below also doesn't work
        # lookup_field = "slug"
        # extra_kwargs = {"url": {"lookup_field": "slug"}}

非常感谢任何帮助。

标签: djangodjango-modelsdjango-rest-frameworkdjango-views

解决方案


"{parent.slug}/{self.order}"- 这不是蛞蝓

蛞蝓是一个报纸术语。slug 是某事物的短标签,仅包含字母、数字、下划线或连字符。它们通常用于 URL。

slug 字段中不允许使用反斜杠或正斜杠。这就是为什么<slug:slug>模式不接受它 - 价值parent/1不是有效的蛞蝓。

在将任何内容保存到 SlugField 之前,请考虑使用FilePathField或不同的分隔符(允许用于 slug)或使用slugify函数。


推荐阅读