跳转到主要内容

Django REST framework的各种技巧集合。

项目描述

收集了Django REST framework的各种技巧。

PyPI Version Supported Python versions Supported Django versions Build Status Documentation Status GPL-2.0-only OR LGPL-2.1-or-later Coverage

先决条件

  • Django 2.2, 3.0, 3.1, 3.2, 4.0和4.1。

  • Python 3.7, 3.8, 3.9, 3.10和3.11。

依赖项

  • djangorestframework: 初始版本为3.6.3编写,但如今使用>=3.10,<3.14进行测试。可能在早期或更高版本上(甚至)支持,但无法保证。

安装

  1. 从PyPI安装最新稳定版本

    pip install django-rest-framework-tricks

    或从GitHub安装最新开发版本

    pip install https://github.com/barseghyanartur/django-rest-framework-tricks/archive/master.tar.gz
  2. 将rest_framework和rest_framework_tricks添加到INSTALLED_APPS

    INSTALLED_APPS = (
        # ...
        # REST framework
        'rest_framework',
    
        # REST framework tricks (this package)
        'rest_framework_tricks',
    
        # ...
    )

文档

文档可在Read the Docs上找到。

主要功能和亮点

使用示例

嵌套序列化器

非关系型字段的嵌套序列化器。

我们的虚构 Book 模型包含以下(非关系型)Django 模型字段

  • title: CharField

  • description: TextField

  • summary: TextField

  • publication_date: DateTimeField

  • state: CharField(带选项)

  • isbn: CharField

  • price: DecimalField

  • pages: IntegerField

  • stock_count: IntegerField

在我们的 REST API 中,我们想使用嵌套序列化器将 Book 序列化器拆分为部分,以获得以下结构

{
    "id": "",
    "title": "",
    "description": "",
    "summary": "",
    "publishing_information": {
        "publication_date": "",
        "isbn": "",
        "pages": ""
    },
    "stock_information": {
        "stock_count": "",
        "price": "",
        "state": ""
    }
}

示例模型

此处与标准实现的不同之处在于,我们在 Book 模型级别声明了两个 NestedProxyField 字段,用于在 BookSerializer 序列化器中声明。

注意,这种更改不会导致模型更改(无需迁移等)。

必需导入
from django.db import models

from rest_framework_tricks.models.fields import NestedProxyField
模型定义
BOOK_PUBLISHING_STATUS_PUBLISHED = 'published'
BOOK_PUBLISHING_STATUS_NOT_PUBLISHED = 'not_published'
BOOK_PUBLISHING_STATUS_IN_PROGRESS = 'in_progress'
BOOK_PUBLISHING_STATUS_CHOICES = (
    (BOOK_PUBLISHING_STATUS_PUBLISHED, "Published"),
    (BOOK_PUBLISHING_STATUS_NOT_PUBLISHED, "Not published"),
    (BOOK_PUBLISHING_STATUS_IN_PROGRESS, "In progress"),
)
BOOK_PUBLISHING_STATUS_DEFAULT = BOOK_PUBLISHING_STATUS_PUBLISHED


class Book(models.Model):
    """Book."""

    title = models.CharField(max_length=100)
    description = models.TextField(null=True, blank=True)
    summary = models.TextField(null=True, blank=True)
    publication_date = models.DateField()
    state = models.CharField(max_length=100,
                             choices=BOOK_PUBLISHING_STATUS_CHOICES,
                             default=BOOK_PUBLISHING_STATUS_DEFAULT)
    isbn = models.CharField(max_length=100, unique=True)
    price = models.DecimalField(max_digits=10, decimal_places=2)
    pages = models.PositiveIntegerField(default=200)
    stock_count = models.PositiveIntegerField(default=30)

    # List the fields for `PublishingInformationSerializer` nested
    # serializer. This does not cause a model change.
    publishing_information = NestedProxyField(
        'publication_date',
        'isbn',
        'pages',
    )

    # List the fields for `StockInformationSerializer` nested serializer.
    # This does not cause a model change.
    stock_information = NestedProxyField(
        'stock_count',
        'price',
        'state',
    )

    class Meta:
        """Meta options."""

        ordering = ["isbn"]

    def __str__(self):
        return self.title

示例序列化器

首先,我们将 nested_proxy_field 属性添加到嵌套序列化器 PublishingInformationSerializerStockInformationSerializerMeta 类定义中。

然后我们定义我们的(主要)BookSerializer 类,它将被用作 BookViewSetserializer_class。我们从 rest_framework_tricks.serializers.HyperlinkedModelSerializer 继承 BookSerializer,而不是从 Django REST framework 继承。还有一个可用的 rest_framework_tricks.serializers.ModelSerializer

必需导入
from rest_framework import serializers
from rest_framework_tricks.serializers import (
    HyperlinkedModelSerializer,
)

from .models import Book
定义序列化器

嵌套序列化器

class PublishingInformationSerializer(serializers.ModelSerializer):
    """Publishing information serializer."""

    publication_date = serializers.DateField(required=False)
    isbn = serializers.CharField(required=False)
    pages = serializers.IntegerField(required=False)

    class Meta:
        """Meta options."""

        model = Book
        fields = (
            'publication_date',
            'isbn',
            'pages',
        )
        # Note, that this should be set to True to identify that
        # this serializer is going to be used as `NestedProxyField`.
        nested_proxy_field = True

嵌套序列化器

class StockInformationSerializer(serializers.ModelSerializer):
    """Stock information serializer."""

    class Meta:
        """Meta options."""

        model = Book
        fields = (
            'stock_count',
            'price',
            'state',
        )
        # Note, that this should be set to True to identify that
        # this serializer is going to be used as `NestedProxyField`.
        nested_proxy_field = True

用于 ViewSet 的主要序列化器

# Note, that we are importing the ``HyperlinkedModelSerializer`` from
# the `rest_framework_tricks.serializers`. Names of the serializers
# should match the names of model properties set with ``NestedProxyField``
# fields.
class BookSerializer(HyperlinkedModelSerializer):
    """Book serializer."""

    publishing_information = PublishingInformationSerializer(required=False)
    stock_information = StockInformationSerializer(required=False)

    class Meta:
        """Meta options."""

        model = Book
        fields = (
            'url',
            'id',
            'title',
            'description',
            'summary',
            'publishing_information',
            'stock_information',
        )

示例 ViewSet

此处没有任何与标准实现的不同之处。

必需导入
from rest_framework.viewsets import ModelViewSet
from rest_framework.permissions import AllowAny

from .models import Book
from .serializers import BookSerializer
ViewSet 定义
class BookViewSet(ModelViewSet):
    """Book ViewSet."""

    queryset = Book.objects.all()
    serializer_class = BookSerializer
    permission_classes = [AllowAny]
示例 OPTIONS 调用
OPTIONS /books/api/books/
HTTP 200 OK
Allow: GET, POST, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept
{
    "name": "Book List",
    "description": "Book ViewSet.",
    "renders": [
        "application/json",
        "text/html"
    ],
    "parses": [
        "application/json",
        "application/x-www-form-urlencoded",
        "multipart/form-data"
    ],
    "actions": {
        "POST": {
            "id": {
                "type": "integer",
                "required": false,
                "read_only": true,
                "label": "ID"
            },
            "title": {
                "type": "string",
                "required": true,
                "read_only": false,
                "label": "Title",
                "max_length": 100
            },
            "description": {
                "type": "string",
                "required": false,
                "read_only": false,
                "label": "Description"
            },
            "summary": {
                "type": "string",
                "required": false,
                "read_only": false,
                "label": "Summary"
            },
            "publishing_information": {
                "type": "nested object",
                "required": false,
                "read_only": false,
                "label": "Publishing information",
                "children": {
                    "publication_date": {
                        "type": "date",
                        "required": false,
                        "read_only": false,
                        "label": "Publication date"
                    },
                    "isbn": {
                        "type": "string",
                        "required": false,
                        "read_only": false,
                        "label": "Isbn"
                    },
                    "pages": {
                        "type": "integer",
                        "required": false,
                        "read_only": false,
                        "label": "Pages"
                    }
                }
            },
            "stock_information": {
                "type": "nested object",
                "required": false,
                "read_only": false,
                "label": "Stock information",
                "children": {
                    "stock_count": {
                        "type": "integer",
                        "required": false,
                        "read_only": false,
                        "label": "Stock count"
                    },
                    "price": {
                        "type": "decimal",
                        "required": true,
                        "read_only": false,
                        "label": "Price"
                    },
                    "state": {
                        "type": "choice",
                        "required": false,
                        "read_only": false,
                        "label": "State",
                        "choices": [
                            {
                                "value": "published",
                                "display_name": "Published"
                            },
                            {
                                "value": "not_published",
                                "display_name": "Not published"
                            },
                            {
                                "value": "in_progress",
                                "display_name": "In progress"
                            }
                        ]
                    }
                }
            }
        }
    }
}

无限嵌套深度

支持无限嵌套深度。

我们的虚构 Author 模型可以包含以下(非关系型)Django 模型字段

  • salutation: CharField

  • name: CharField

  • email: EmailField

  • birth_date: DateField

  • biography: TextField

  • phone_number: CharField

  • website: URLField

  • company: CharField

  • company_phone_number: CharField

  • company_email: EmailField

  • company_website: URLField

在我们的 REST API 中,我们可以使用嵌套序列化器将 Author 序列化器拆分为部分,以获得以下结构

{
    "id": "",
    "salutation": "",
    "name": "",
    "birth_date": "",
    "biography": "",
    "contact_information": {
        "personal_contact_information": {
            "email": "",
            "phone_number": "",
            "website": ""
        },
        "business_contact_information": {
            "company": "",
            "company_email": "",
            "company_phone_number": "",
            "company_website": ""
        }
    }
}

我们的模型定义如下(完整模型定义请参阅 高级用法示例

class Author(models.Model):
    """Author."""

    # ...

    # List the fields for `PersonalContactInformationSerializer` nested
    # serializer. This does not cause a model change.
    personal_contact_information = NestedProxyField(
        'email',
        'phone_number',
        'website',
    )

    # List the fields for `BusinessContactInformationSerializer` nested
    # serializer. This does not cause a model change.
    business_contact_information = NestedProxyField(
        'company',
        'company_email',
        'company_phone_number',
        'company_website',
    )

    # List the fields for `ContactInformationSerializer` nested
    # serializer. This does not cause a model change.
    contact_information = NestedProxyField(
        'personal_contact_information',
        'business_contact_information',
    )

    # ...

查看完整示例,请参阅 高级用法示例

排序过滤器

为排序选项提供开发者友好的名称(例如,对于相关字段名称),以创建更好的API。

示例模型

此处没有任何与标准实现的不同之处。

必需导入
from django.db import models
模型定义
class Profile(models.Model):
    """Profile."""

    user = models.ForeignKey('auth.User')
    biography = models.TextField()
    hobbies = models.TextField()

示例序列化器

此处没有任何与标准实现的不同之处。

必需导入
from rest_framework import serializers

from .models import Profile
定义序列化器
class ProfileSerializer(serializers.ModelSerializer):
    """Profile serializer."""

    username = serializers.CharField(source='user.username', read_only=True)
    full_name = serializers.SerializerMethodField()
    email = serializers.CharField(source='user.email', read_only=True)

    class Meta(object):

    model = Profile
    fields = (
        'id',
        'username',
        'full_name',
        'email',
        'biography',
        'hobbies',
    )

    def get_full_name(self, obj):
        return obj.user.get_full_name()

示例 ViewSet

这里与标准实现唯一的区别是我们使用 rest_frameworks_tricks.filters.OrderingFilter 而不是 rest_framework.filters.OrderingFilter

必需导入
from rest_framework.viewsets import ModelViewSet
from rest_framework.permissions import AllowAny
from rest_framework_tricks.filters import OrderingFilter

from .models import Profile
from .serializers import ProfileSerializer
ViewSet 定义
class ProfileViewSet(ModelViewSet):
    """Profile ViewSet."""

    queryset = Profile.objects.all()
    serializer_class = ProfileSerializer
    permission_classes = [AllowAny]
    filter_backends = (OrderingFilter,)
    ordering_fields = {
        'id': 'id',
        'username': 'user__username',
        'email': 'user__email',
        'full_name': ['user__first_name', 'user__last_name']
    }
    ordering = ('id',)
示例 GET 调用

注意,我们的排序选项现在与序列化器(JSON响应)中的字段名称相等。这样,API 就更容易使用和理解。

GET /api/profile/?ordering=email
GET /api/profile/?ordering=-username
GET /api/profile/?ordering=full_name
GET /api/profile/?ordering=-full_name

受限的文件字段

示例模型

此处没有任何与标准实现的不同之处。

必需导入
from django.db import models
模型定义
class Profile(models.Model):
    """Upload."""

    username = models.CharField(max_length=255)
    resume = models.FileField()

示例序列化器

必需导入
from rest_framework import serializers
from rest_framework_tricks.fields import ConstrainedFileField

from .models import Upload
定义序列化器
class ProfileSerializer(serializers.ModelSerializer):
    """Profile serializer."""

    username = serializers.CharField()
    # Restrict resume to 5Mb
    resume = ConstrainedFileField(max_upload_size=5_242_880)

    class Meta(object):

    model = Profile
    fields = (
        'id',
        'username',
        'resume',
    )

演示

在本地运行演示

为了能够快速评估 django-rest-framework-tricks,已创建一个演示应用程序(带有快速安装程序)(在 Ubuntu/Debian 上运行,也可能在其他 Linux 系统上运行,但不保证)。按照以下说明在不到一分钟的时间内运行演示。

获取并运行最新的 rest_framework_tricks_demo_installer.sh 演示安装程序

wget -O - https://raw.github.com/barseghyanartur/django-rest-framework-tricks/master/examples/rest_framework_tricks_demo_installer.sh | bash

打开您的浏览器并测试应用程序。

http://127.0.0.1:8001/books/api/

测试

项目已涵盖测试。

要测试所有支持的 Python/Django 版本,请输入

tox

要针对特定环境进行测试,请输入

tox -e py39-django32

要仅测试您的工作环境,请输入

pytest -vvv

要在工作环境中运行单个测试,请输入

pytest -vvv src/rest_framework_tricks/tests/test_nested_proxy_field.py
pip install -r examples/requirements/test.txt

编写文档

请保持以下层次结构。

=====
title
=====

header
======

sub-header
----------

sub-sub-header
~~~~~~~~~~~~~~

sub-sub-sub-header
^^^^^^^^^^^^^^^^^^

sub-sub-sub-sub-header
++++++++++++++++++++++

sub-sub-sub-sub-sub-header
**************************

许可证

GPL-2.0-only OR LGPL-2.1-or-later

支持

有关任何问题,请联系作者部分提供的电子邮件。

作者

Artur Barseghyan <artur.barseghyan@gmail.com>

项目详情


下载文件

下载您平台上的文件。如果您不确定选择哪个,请了解更多关于 安装软件包 的信息。

源分发

django-rest-framework-tricks-0.2.14.tar.gz (288.4 kB 查看散列值)

上传时间

构建分发

django_rest_framework_tricks-0.2.14-py2.py3-none-any.whl (39.0 kB 查看散列值)

上传时间 Python 2 Python 3

由以下支持

AWSAWS 云计算和安全赞助商 DatadogDatadog 监控 FastlyFastly CDN GoogleGoogle 下载分析 MicrosoftMicrosoft PSF赞助商 PingdomPingdom 监控 SentrySentry 错误日志 StatusPageStatusPage 状态页面