在本文中,我们将创建一个项目,该项目发布有关使用Django和Django Rest框架的咆哮的项目。我们将使用Django的内置slugify
方法并覆盖其save()
方法,以自动为每个咆哮创建 slug 。我们还将使用称为drf-writable-nested的第三方软件包来处理模型中ManyToManyField
的序列化。
我们将首先创建虚拟环境,安装初始软件包,创建Django项目,创建Django应用程序,最后进行初始迁移
python -m venv venv
. venv/bin/activate
python -m pip install django djangorestframework
django-admin startproject myproject
cd myproject
python -m manage startapp rants
python -m manage migrate
我们列出了项目的安装_Apps设置中的rest_framework
和我们的rants应用程序,并将它们包含在项目urls.py
# settings.py
INSTALLED_APPS = [
...
'rest_framework',
'rants',
]
# myproject/urls.py
from django.urls import path, include
urlpatterns = [
path('', include('rants.urls', namespace='main')),
path('api-auth/', include('rest_framework.urls', namespace='rest_framework')),
]
接下来,我们在rants
应用程序中创建模型:
# models.py
from django.db import models
class Category(models.Model):
title = models.CharField(max_length=50)
slug = models.SlugField(max_length=50)
def __str__(self):
return self.title
class Rant(models.Model):
title = models.CharField(max_length=150)
slug = models.SlugField(max_length=150)
categories = models.ManyToManyField(
Category, related_name='rants_categories')
class Meta:
verbose_name = "rant"
verbose_name_plural = 'rants'
def __str__(self):
return self.title
我们有一个带有标题的咆哮模型,带有CharField
的slug和一个类别属性,该类别属性具有ManyToManyField
连接到具有标题和slug属性的类别模型。
然后我们迁移数据库python -m manage makemigrations && python -m manage migrate
。接下来,我们为这两个模型创建一个序列化器:
# serializers.py
from rest_framework import serializers
from .models import Rant, Category
class CategorySerializer(serializers.ModelSerializer):
slug = serializers.SlugField(read_only=True)
class Meta:
model = Category
fields = "__all__"
class RantSerializer(serializers.ModelSerializer):
categories = CategorySerializer(many=True)
slug = serializers.SlugField(read_only=True)
class Meta:
model = Rant
fields = ('id', 'title', 'slug', 'categories')
many = True
最后,我们创建了视图并将其映射到我们的URL,以便我们可以看到应用程序的API端点。
# views.py
from rest_framework.response import Response
from rest_framework.generics import ListCreateAPIView, UpdateAPIView, DestroyAPIView
from .models import Rant
from .serializers import RantSerializer
class RantList(ListCreateAPIView):
queryset = Rant.objects.all()
serializer_class = RantSerializer
def list(self, request):
queryset = self.get_queryset()
serializer = RantSerializer(queryset, many=True)
return Response(serializer.data)
class RantUpdate(UpdateAPIView):
queryset = Rant.objects.all()
serializer_class = RantSerializer
class RantDelete(DestroyAPIView):
queryset = Rant.objects.all()
serializer_class = RantSerializer
我们将ListCreateAPIView
用于读取端点来表示模型实例集合,该集合提供了get
和post
方法处理程序,UpdateAPIView
,用于单个模型实例的更新端点,该实例提供了put
和patch
Methoder,patch
Method Handler,DestroyAPIView
单个模型实例的删除端点,该实例提供了delete
方法处理程序。让我们将这些视图映射到urls.py
# urls.py
from django.urls import path
from .views import RantList, RantUpdate, RantDelete
from .models import Rant
from .serializers import RantSerializer
app_name = 'rants'
urlpatterns = [
path('api/rants/', RantList.as_view(queryset=Rant.objects.all(), serializer_class=RantSerializer)),
path('api/rants/update/<int:pk>/', RantUpdate.as_view(queryset=Rant.objects.all(), serializer_class=RantSerializer)),
path('api/rants/delete/<int:pk>/', RantDelete.as_view(queryset=Rant.objects.all(), serializer_class=RantSerializer)),
]
现在,我们可以使用DRF软件包在浏览器中查看API端点,但我个人更喜欢使用另一个是drf-yasg
软件包的软件包查看API端点。让我们安装和配置软件包:
python -m pip install drf-yasg
# settings.py
INSTALLED_APPS = [
....
'rest_framework',
'drf_yasg',
]
# urls.py
from django.urls import path, include
from rest_framework import permissions
from drf_yasg.views import get_schema_view
from drf_yasg import openapi
schema_view = get_schema_view(
openapi.Info(
title="Rants API",
default_version='v1',
description="Rants",
terms_of_service="https://www.google.com/policies/terms/",
contact=openapi.Contact(email="contact@snippets.local"),
license=openapi.License(name="BSD License"),
),
public=True,
permission_classes=[permissions.AllowAny],
)
urlpatterns = [path('api/', schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'),]
现在我们运行python -m manage runserver
,然后前往http://localhost:8000/api/,看看我们创建了什么
但是我们有问题,尽管在该领域输入了str
,但类别字段仍有错误。
{
"categories": [
"Expected a list of items but got type \"str\"."
]
}
要解决此问题,我们将在应用程序中安装drf-nested-writable
以序列化类别字段,然后更新serializers.py
文件以在我们的RantSerializer
中包含WritableNestedModelSerializer
python -m pip install drf-nested-writable
# serializers.py
from drf_writable_nested.serializers import WritableNestedModelSerializer
class RantSerializer(WritableNestedModelSerializer):
categories = CategorySerializer(many=True)
slug = serializers.SlugField(read_only=True)
class Meta:
model = Rant
fields = ('id', 'title', 'slug', 'categories')
many = True
现在,当我们使用rants_create
端点为应用程序添加新数据时,我们将不再收到超过的错误,而是。我们还覆盖了slug
字段的模型中的save()
方法,以自动填充数据库
在我们的模型中覆盖save()
方法的代码
# models.py
...
from django.utils.text import slugify
...
def save(self, *args, **kwargs):
self.slug = slugify(self.title)
super(Category, self).save(*args, **kwargs)
return self.slug
...
def save(self, *args, **kwargs):
self.slug = slugify(self.title)
super(Rant, self).save(*args, **kwargs)
return self.slug
...
结论:
这花了我一段时间来解决,因为我在GMT+8,但是嘿,至少它已经解决了,我学会了如何覆盖模型中的保存方法,并了解了DRF-wardible-Nest-Nest-Nest-Nest-Nest-Nest-Nest-Nest-Nest-Nest-Nest-nest套件以解决我的问题。