DjangoRestFrameworkNotes

title: Django Rest Framework ็ฌ”่ฎฐ tags:

  • Django

  • Django Rest Framework

    categories:

  • Python

Serializers

RelationShip

# coding: utf-8
# @author   bovenson
# @email    [email protected]
# @desc     Django Rest Framework Serializers

from rest_framework import serializers
from book.models import *
from cloudlibraryserver.settings import IMAGE_SOURCE, IMG_URL


class ScoreSerializer(serializers.ModelSerializer):
    """ไนฆ็ฑ่ฏ„ๅˆ†"""
    class Meta:
        model = BookScore
        fields = '__all__'


class BookAuthorSerializer(serializers.ModelSerializer):
    """ไนฆ็ฑไฝœ่€…"""
    class Meta:
        model = BookAuthor
        fields = '__all__'


class BookTagSerializer(serializers.ModelSerializer):
    """ไนฆ็ฑๆ ‡็ญพ"""
    class Meta:
        model = BookTag
        fields = '__all__'


class BookSerializer(serializers.ModelSerializer):
    """ไนฆ็ฑ"""
    score = ScoreSerializer(many=False, read_only=True)
    author = BookAuthorSerializer(many=True, read_only=True)
    tags = BookTagSerializer(many=True, read_only=True)

    class Meta:
        model = Book
        fields = ['name', 'summary', 'pic', 'score', 'author', 'tags']

    def to_representation(self, instance):
        # ไฟฎๆ”นๅ›พ็‰‡URL
        ret = super().to_representation(instance)
        # ไธƒ็‰›ๅ‚จๅญ˜
        if IMAGE_SOURCE == 'QINIU':
            ret['pic'] = IMG_URL + ret['pic'][len('/media'):]
        return ret


class BooklistSerializer(serializers.HyperlinkedModelSerializer):
    """ไนฆๅ•"""
    class Meta:
        model = BookList
        fields = ['id']

Order

class Track(models.Model):
    album = models.ForeignKey(Album, related_name='tracks', on_delete=models.CASCADE)
    order = models.IntegerField()
    title = models.CharField(max_length=100)
    duration = models.IntegerField()

    class Meta:
        unique_together = ('album', 'order')
        ordering = ['order']    # ๅœจModelๅฎšไน‰ไธญ่ฎพ็ฝฎordering

่Žทๅ–ๅ•ไธช่ฎฐๅฝ•

่ฎพ็ฝฎModelViewSetไน‹ๅŽ๏ผŒไผš้ป˜่ฎคๅขžๅŠ view_url/pk/

ไฝฟ็”จไธๅŒSerilizerๅŒไธ€ๆจกๅž‹

urls.py

# route
router.register(r'book', BookViewSet)
router.register(r'bookdetail', BookDetailViewSet, 'bookdetail')

# view set
class BookViewSet(viewsets.ModelViewSet):
    """ไนฆ็ฑ View Set"""
    queryset = Book.objects.all().order_by('id')
    serializer_class = BookSerializer
    pagination_class = StandardResultSetPagination


class BookDetailViewSet(viewsets.ModelViewSet):
    """ไนฆ็ฑ่ฏฆๆƒ…"""
    queryset = Book.objects.all().order_by('id')
    serializer_class = BookDetailSerializer
    pagination_class = StandardResultSetPagination


# serilizer
class BookSerializer(serializers.ModelSerializer):
    """ไนฆ็ฑ"""
    score = ScoreSerializer(many=False, read_only=True)
    author = BookAuthorSerializer(many=True, read_only=True)
    tags = BookTagSerializer(many=True, read_only=True)

    class Meta:
        model = Book
        fields = ['id', 'name', 'summary', 'pic', 'score', 'author', 'tags']

    def to_representation(self, instance):
        # ไฟฎๆ”นๅ›พ็‰‡URL
        ret = super().to_representation(instance)
        # ไธƒ็‰›ๅ‚จๅญ˜
        if IMAGE_SOURCE == 'QINIU':
            ret['pic'] = IMG_URL + ret['pic'][len('/media'):]
        return ret


class BookDetailSerializer(BookSerializer):    # ่ฟ™้‡Œ็ปงๆ‰ฟ BookSerializer
    info = BookInfoSerializer(many=False, read_only=True)
    """ไนฆ็ฑ่ฏฆๆƒ…"""
    class Meta:
        model = Book
        fields = ['id', 'name', 'summary', 'pic', 'score', 'author', 'tags', 'info']

่ฟ”ๅ›žๆ ‘

้œ€ๆฑ‚ๆ่ฟฐ

่ฟ”ๅ›žๆ•ฐๆฎๅบ“่กจไธญๆ่ฟฐ็š„ๅˆ†็ฑปๆ ‘

Model

class ArticleCategory(models.Model):
    """ๆ–‡็ซ ๅˆ†็ฑป"""
    name = models.CharField('ๅˆ†็ฑปๅ็งฐ', max_length=50)
    children = models.ManyToManyField('self', symmetrical=False, blank=True)

    def __str__(self):
        return self.name

Serializer

from rest_framework import serializers
from django.contrib.auth.models import User, Group
from rest_framework_recursive.fields import RecursiveField

class ArticleCategorySerializer(serializers.ModelSerializer):
    """ๆ–‡็ซ ๅˆ†็ฑป"""
    children = RecursiveField(many=True)

    class Meta:
        model = ArticleCategory
        fields = '__all__'

ViewSet

class ArticleCategoryViewSet(viewsets.ModelViewSet):
    """ๆ–‡็ซ ๅˆ†็ฑปๅˆ—่กจ"""
    queryset = ArticleCategory.objects.all()
    serializer_class = ArticleCategorySerializer

    @action(methods=['GET'], detail=False)
    def tree(self, request):
        prefetch = ArticleCategory.objects.all().prefetch_related()
        childs = list(map(lambda x: x.get('children'), prefetch.filter(children__isnull=False).values('children')))
        query = prefetch.exclude(pk__in=childs)
        serializer = self.get_serializer(query, many=True)
        return Response(serializer.data)

้ข„่งˆ

GET /api/article/category/tree/

HTTP 200 OK
Allow: GET, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

[
    {
        "id": 4,
        "children": [
            {
                "id": 3,
                "children": [
                    {
                        "id": 1,
                        "children": [],
                        "name": "A"
                    },
                    {
                        "id": 2,
                        "children": [],
                        "name": "Q"
                    }
                ],
                "name": "B"
            }
        ],
        "name": "D"
    }
]

ๅˆ†้กต

File Tree

bovenson@ThinkCentre:~/Git/isite/Server$ tree
.
โ”œโ”€โ”€ db.sqlite3
โ”œโ”€โ”€ isite
โ”‚   โ”œโ”€โ”€ admin.py
โ”‚   โ”œโ”€โ”€ apps.py
โ”‚   โ”œโ”€โ”€ core
โ”‚   โ”‚   โ”œโ”€โ”€ __init__.py
โ”‚   โ”‚   โ”œโ”€โ”€ pagination.py
โ”‚   โ”œโ”€โ”€ __init__.py
โ”‚   โ”œโ”€โ”€ models.py
โ”‚   โ”œโ”€โ”€ permissions
โ”‚   โ”‚   โ”œโ”€โ”€ permissions.py
โ”‚   โ”œโ”€โ”€ __pycache__
โ”‚   โ”‚   โ”œโ”€โ”€ admin.cpython-35.pyc
โ”‚   โ”‚   โ”œโ”€โ”€ apps.cpython-35.pyc
โ”‚   โ”‚   โ”œโ”€โ”€ __init__.cpython-35.pyc
โ”‚   โ”‚   โ”œโ”€โ”€ models.cpython-35.pyc
โ”‚   โ”‚   โ””โ”€โ”€ urls.cpython-35.pyc
โ”‚   โ”œโ”€โ”€ serializers
โ”‚   โ”‚   โ””โ”€โ”€ serializers.py
โ”‚   โ”œโ”€โ”€ tests.py
โ”‚   โ”œโ”€โ”€ urls.py
โ”‚   โ””โ”€โ”€ views
โ”‚       โ””โ”€โ”€ viewsets.py
โ”œโ”€โ”€ isite_server
โ”‚   โ”œโ”€โ”€ __init__.py
โ”‚   โ”œโ”€โ”€ settings.py
โ”‚   โ”œโ”€โ”€ urls.py
โ”‚   โ””โ”€โ”€ wsgi.py
โ”œโ”€โ”€ manage.py
โ””โ”€โ”€ templates

่‡ชๅฎšไน‰ๅˆ†้กต็ฑป

pagination.py

# coding: utf-8
# @author   bovenson
# @email    [email protected]
# @desc     ๅˆ†้กต
from rest_framework.pagination import PageNumberPagination
from rest_framework.response import Response


class StandardResultSetPagination(PageNumberPagination):
    """่‡ชๅฎšไน‰ๅˆ†้กต"""
    page_size = 10
    page_query_param = 'page'
    max_page_size = 1000

    def get_paginated_response(self, data):
        """่‡ชๅฎšไน‰่ฟ”ๅ›žไฟกๆฏ"""
        return Response({
            'links': {
               'next': self.get_next_link(),
               'previous': self.get_previous_link()
            },
            'count': self.page.paginator.count,
            'pages': self.page.paginator.num_pages,
            'results': data
        })

settings

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework.authentication.TokenAuthentication',
    ),
    'DEFAULT_PAGINATION_CLASS': 'isite.core.pagination.StandardResultSetPagination',  # ่ฎพ็ฝฎ้ป˜่ฎคๅˆ†้กต็ฑป
    'PAGE_SIZE': 10
}

ๅฏนไบŽ่‡ชๅฎšไน‰action่ฟ›่กŒๅˆ†้กต

class ArticleViewSet(viewsets.ModelViewSet):
    """ๆ–‡็ซ ViewSet"""
    queryset = Article.objects.all().order_by('-create_datetime')
    serializer_class = ArticleSerializer
    authentication_classes = ()

    @action(methods=['GET'], detail=False)
    def summary(self, request):
        """่Žทๅ–ๅธฆๆœ‰้™ๅฎšๅญ—็ฌฆ็ฎ€ไป‹็š„ๅˆ—่กจ"""
        articles = Article.objects.all()
        for article in articles:
            article.content = article.content[:120]

        # ๅˆ†้กต
        page = self.paginate_queryset(articles)
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            return self.get_paginated_response(serializer.data)
        else:
            serializer = self.get_serializer(articles, many=True)
            return Response(serializer.data)

ๅ‚่€ƒ

ๆœ€ๅŽๆ›ดๆ–ฐไบŽ

่ฟ™ๆœ‰ๅธฎๅŠฉๅ—๏ผŸ