django rest framework- association and hyperlinks API

Now our relationship is represented in the API by using the primary key. In this part of the tutorial, we will improve the relationship between cohesion and can be found through the use of hyperlinks.

Using the source property

model type class

models.py

# 文章
class Article(ModelBase):
    # null是在数据库上表现NULL,而不是一个空字符串,所以对空字符串的限制,还需要通过blank,是否能为空字符串控制
    title = models.CharField(max_length=35, validators=[MinLengthValidator(1), ], unique=True, verbose_name='标题')
    keywords = models.CharField(max_length=50, validators=[MinLengthValidator(1), ], verbose_name='关键词')
    description = models.CharField(verbose_name='描述', max_length=120, validators=[MinLengthValidator(1), ], blank=True)  #选填,如果不填默认抓取正文前54个字
    content = models.TextField(verbose_name='内容')
    cover_img = models.URLField(verbose_name='封面图', blank=True)
    #PositiveIntegerField,该类型的值只允许为正整数或 0,毕竟阅读量不可能为负值。
    read_num = models.PositiveIntegerField(verbose_name='浏览量', default=0)
    like_num = models.IntegerField(verbose_name='点赞数', default=0)

    category = models.ForeignKey(Category, on_delete=models.DO_NOTHING, verbose_name='所属类别')  #多对一关系

    tag = models.ManyToManyField(Tag) #多对多关系

    #当外键指向的数据对象被删除“on_delete”时,models.DOTHING,即用户删除时,文章不做任何处理
    author = models.ForeignKey(Account, on_delete=models.DO_NOTHING, related_name='articles', verbose_name='作者')

    class Meta:
        db_table = 'tb_article'
        ordering = ['-create_time']
        verbose_name = u'文章'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.title
Serialization

serializers.py


class ArticleSerializer(serializers.Serializer):  # 与django的表单类相似
    id = serializers.IntegerField()
    title = serializers.CharField(label='标题', max_length=35, required=True, error_messages={'required': '标题不能为空', 'max_length': '标题不能超过35个字符'})
    keywords = serializers.CharField(label='关键字', max_length=50, required=False)
    description = serializers.CharField(label='描述', max_length=120, allow_blank=True, required=False)
    # content = serializers.CharField()
    cover_img = serializers.URLField(label='封面图', allow_blank=True)
    read_num = serializers.IntegerField(label='浏览量', default=0)
    like_num = serializers.IntegerField(label='点赞数', default=0)
    # 分类名称
    category = serializers.CharField(source='category.name', label='所属类别')  #多对一关系
    author = serializers.CharField(source='author.nick_name', label='作者')

    # SerializerMethodField(),表示自定义显示 然后写一个自定义的方法get_字段名
    tag = serializers.SerializerMethodField() #多对多关系

    def get_tag(self, obj):  # 注意这里get_对应上面字段
        tags = obj.tag.all()
        tag_list = []
        for tag in tags:
            tag_list.append({'pk':tag.pk, 'name': tag.name})  # 列表里面需要序列化形式

        return tag_list

url configuration

urls.py

urlpatterns = [
    path('articles/', ArticListleView.as_view(), name='article_list' ),
    path('articles/<int:pk>/', ArticleDetailView.as_view(), name='article_detail'),
]
view

views.py

class ArticListleView(generics.ListCreateAPIView):
    queryset = Article.objects.all()  # 查询结果集
    serializer_class = ArticleSerializer # 序列化类

class ArticleDetailView(generics.RetrieveUpdateDestroyAPIView):
    queryset = Article.objects.all()  # 查询结果集
    serializer_class = ArticleSerializer  # 序列化类
Test results
9286065-36f7c8baa6d05cbc.png
image.png

Through the above examples, you can see the query out the relevant foreign key field by field source

Note: Sourse parameter control attribute is used to fill the field and may refer to any property on the sequence of instances. It can also be used in dot notation shown in the above .way will traverse the given attribute, using Django template language similar in this case. For many relationships taguse SerializerMethodField(), represents the custom display and then write a custom method name get_ field to achieve access to the object corresponding to the field

Use PrimaryKeyRelatedField

Use PrimaryKeyRelatedField to return to the main key to a correspondence relationship model.

    cateogry = serializers.PrimaryKeyRelatedField(queryset=Category.objects.all())
    author = serializers.PrimaryKeyRelatedField(queryset=Account.objects.all())  # 一方不需要用many
    # 不过这样只是用户获得的只是一个外键类别的id,并不能获取到详细的信息,如果想要获取到具体信息,那需要嵌套serializer
    #author = AccountSerializer()   # author一定要是article model中存在的字段
    tag = serializers.PrimaryKeyRelatedField(many=True, queryset=Tag.objects.all())  # 多对多用many=True

Use PrimaryKeyRelatedField just get foreign key category id, and can not get into the details, if you want to get to the specific information it would need to be nested serializer

Nested serializer

from rest_framework import serializers
from article.models import Article, Category, Tag, Column
from user.models import Account

class ColumnSerializer(serializers.ModelSerializer):
    class Meta:
        model = Column
        fields = '__all__'

class CategorySerializer(serializers.ModelSerializer):
    column = ColumnSerializer()
    class Meta:
        model = Category
        fields = ['id','name', 'column']

class ArticleSerializer(serializers.Serializer):  # 与django的表单类相似
    id = serializers.IntegerField()
    title = serializers.CharField(label='标题', max_length=35, required=True, error_messages={'required': '标题不能为空', 'max_length': '标题不能超过35个字符'})
    keywords = serializers.CharField(label='关键字', max_length=50, required=False)
    description = serializers.CharField(label='描述', max_length=120, allow_blank=True, required=False)
    # content = serializers.CharField()
    cover_img = serializers.URLField(label='封面图', allow_blank=True)
    read_num = serializers.IntegerField(label='浏览量', default=0)
    like_num = serializers.IntegerField(label='点赞数', default=0)
    # 分类名称
    #category = serializers.CharField(source='category.name', label='所属类别')  #多对一关系
    #author = serializers.CharField(source='author.nick_name', label='作者')

    # SerializerMethodField(),表示自定义显示 然后写一个自定义的方法get_字段名
    #tag = serializers.SerializerMethodField() #多对多关系

    category = CategorySerializer()

    author = serializers.PrimaryKeyRelatedField(queryset=Account.objects.all())  # 一方不需要用many
    # 不过这样只是用户获得的只是一个外键类别的id,并不能获取到详细的信息,如果想要获取到具体信息,那需要嵌套serializer
    #author = AccountSerializer()   # author一定要是article model中存在的字段
    tag = serializers.PrimaryKeyRelatedField(many=True, queryset=Tag.objects.all())  # 多对多用many=True


Test results
9286065-596e2fce543e2df0.png
image.png

By testing it can be seen by nested serializers we export all of the information a foreign key, otherwise just get id foreign key categories.

Use depth

If ModelSerializer to serialize model class, we can use the depth to return foreign key object details, modified sequence is as follows:

class ArticleSerializer(serializers.ModelSerializer):
        class Meta:
            model = Article
            fields = ['id', 'title', 'keywords', 'description', 'cover_img', 'read_num', 'like_num', 'category', 'tag', 'author']

            depth = 1
Test Results
9286065-37ea26e88aea0a95.png
image.png

It can be seen from the above sequence of ModelSerializer depth automatically connected through the table. Even where depth represents the depth of the table, such as the category of the corresponding foreign key column.
If you do not write depth and depth is 0, not information is not displayed column


9286065-962d9cb1883eab32.png
image.png

If depth = 1


9286065-f59b742e4e14bb66.png
image.png

If depth = 2
9286065-f56ff09d660c08c8.png
image.png

The official recommended maximum of 10 layers.

Use HyperlinkedIdentityField

We can also represent hyperlinks between entities.
Modify our previous

Serialization
class CategorySerializer(serializers.ModelSerializer):
    column = ColumnSerializer()
    class Meta:
        model = Category
        fields = ['id','name', 'column']

class ArticleSerializer(serializers.ModelSerializer):
        # view_name表示路由的别名,注意如果不是根目录下,则需要使用命名空间来:,
        # lookup_field:根据表指定字段,来拼路径,生成链接
        # lookup_url_kwarg:默认是pk,(urls.py中的指定的pk)可以不写,反向解析有名分组的名字。
        category = serializers.HyperlinkedIdentityField(view_name='api:category_detail', lookup_field='category_id', lookup_url_kwarg='pk')
        class Meta:
            model = Article
            fields = ['id', 'title', 'keywords', 'description', 'cover_img', 'read_num', 'like_num', 'category', 'tag', 'author']
url configuration
urlpatterns = [
    path('articles/', ArticListleView.as_view(), name='article_list' ),
    path('articles/<int:pk>/', ArticleDetailView.as_view(), name='article_detail'),

    path('categories/<int:pkx>/', CategoryDetailView.as_view(), name='category_detail'),
]

Note: the corresponding relationship in url name and sequence of the pkx

view
class CategoryDetailView(generics.RetrieveUpdateDestroyAPIView):
    queryset = Category.objects.all()  # 查询结果集
    serializer_class = CategorySerializer  # 序列化类

class ArticListleView(generics.ListCreateAPIView):

    queryset = Article.objects.all()  # 查询结果集
    serializer_class = ArticleSerializer # 序列化类

Reverse Lookup

For example, there are multiple types of category I a column next column, I have to check those species under the column, then use the reverse lookup

class ColumnSerializer(serializers.ModelSerializer):
    categories = serializers.StringRelatedField(many=True)  # 字段名必须设置related_name 或者使用表名_set 就行了
    class Meta:
        model = Column
        fields = ['id','name', 'link_url', 'index','categories']

class CategorySerializer(serializers.ModelSerializer):
    column = ColumnSerializer()
    class Meta:
        model = Category
        fields = ['id','name', 'column']

Note that
a reverse lookup table with a sequence field need related_name child or lowercase table names _set

Test results:
9286065-2fcd64f0e0d06d36.png
image.png

The relationship between entities

Many-to-: ForeignKey
many-: ManyToManyField
one: OneToOneField

Handle the relationship between entities is one of the most challenging aspects of Web API design. We can choose to represent the relationship of the following:
1. Using the primary keys;
2. hyperlinks between entities;
3. the unique slug field on the associated entities;
4. default string related entities;
5. the parent the expression using nested entity;
6. other custom expressions.

1, api reference
tracks = serializers.StringRelatedField (many = True) # string relationship field
tracks = serializers.PrimaryKeyRelatedField (many = True, read_only = True) # primary key in the form of a relationship field
tracks = serializers.HyperlinkedRelatedField (many = True, read_only = True, view_name = 'track- detail') # form hyperlink relationship field
tracks = serializers.SlugRelatedField (many = True, read_only = True, slug_field = 'title') # subtitled relationship in the form of
track_listing = serializers.HyperlinkedIdentityField (view_name = 'track-list') # hyperlink relationship status
2, the nested relationship between
the sequence class may reference other classes of sequences directly.

They are available through the above positive and negative.

Reproduced in: https: //www.jianshu.com/p/2c7dbf6a4ead

Guess you like

Origin blog.csdn.net/weixin_34414196/article/details/91315517