Django序列化器显示所有要检索的字段,但隐藏列表中的字段

时间:2019-11-21 22:34:32

标签: django python-3.x django-rest-framework django-serializer

我有一个Product模型,正在使用该模型来检索所有产品和单个产品。查询单个记录时,我需要返回所有列,但查询全部时,只返回一些列。

# models.py

class Product(models.Model):
    product_id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=100)
    description = models.CharField(max_length=1000)
    price = models.DecimalField(max_digits=10, decimal_places=2)
    discounted_price = models.DecimalField(max_digits=10, decimal_places=2)
    image = models.CharField(max_length=150, blank=True, null=True)
    image_2 = models.CharField(max_length=150, blank=True, null=True)
    thumbnail = models.CharField(max_length=150, blank=True, null=True)
    display = models.SmallIntegerField()

    class Meta:
        managed = False
        db_table = 'product'
# serializers.py

class ProductSerializer(serializers.ModelSerializer):
    class Meta:
        model = Product
        fields = ('product_id', 'name', 'description', 'price', 'discounted_price', 'image', 'thumbnail')
# products.py

import logging

from django.db.models import F
from django.contrib.auth.models import AnonymousUser
from drf_yasg import openapi
from drf_yasg.utils import swagger_auto_schema
from rest_framework import viewsets
from rest_framework.decorators import action
from rest_framework.filters import SearchFilter
from rest_framework.pagination import PageNumberPagination
from rest_framework.response import Response

from api import errors
from api.models import Category, Product, Review, ProductCategory
from api.serializers import ProductSerializer, ReviewSerializer

logger = logging.getLogger(__name__)


class ProductSetPagination(PageNumberPagination):
    page_size = 20
    page_query_description = 'Inform the page. Starting with 1. Default: 1'
    page_size_query_param = 'limit'
    page_size_query_description = 'Limit per page, Default: 20.'
    max_page_size = 200


class ProductViewSet(viewsets.ReadOnlyModelViewSet):
    """
    list: Return a list of products
    retrieve: Return a product by ID.
    """
    queryset = Product.objects.all().order_by('product_id')
    serializer_class = ProductSerializer
    pagination_class = ProductSetPagination
    filter_backends = (SearchFilter,)
    search_fields = ('name', 'description')

    @action(methods=['GET'], detail=False, url_path='search', url_name='Search products')
    def search(self, request, *args, **kwargs):
        """        
        Search products
        """
        return super().list(request, *args, **kwargs)

    def get_products_by_category(self, request, category_id):
        """
        Get a list of Products by Categories
        """
        # Filter queryset to find all products in category
        response = ProductCategory.objects.filter(category_id=category_id).values(
          'product_id', name=F('product__name'), description=F('product__description'), price=F('product__price'), discounted_price=F('product__discounted_price'), thumbnail=F('product__thumbnail'))

        # Return response
        if response.exists():
          return Response(response, 200)
        else:
          return Response(response, 204)


    def get_products_by_department(self, request, department_id):
        """
        Get a list of Products of Departments
        """
        categories = Category.objects.filter(department_id=department_id).values('category_id')

        for item in categories:
          category_id = item['category_id']
          products = ProductCategory.objects.filter(category_id=category_id).values(
            'product_id', name=F('product__name'), description=F('product__description'),
          price=F('product__price'), discounted_price=F('product__discounted_price'), thumbnail=F('product__thumbnail'))

        # Return response
        if products.exists():
          return Response(products, 200)
        else:
          return Response(products, 204)

    def render_product_review_row(self, row):
        row["review"] = row.pop("tmp_review")
        row["rating"] = row.pop("tmp_rating")
        row["created_on"] = row.pop("tmp_created_on")
        return row    

    @action(methods=['GET'], detail=True, url_path='<int:product_id>/reviews', url_name='List reviews')
    def reviews(self, request, *args, **kwargs):
        """
        Return a list of reviews
        """
        product_id = int(kwargs['product_id'])

        # Filter all reviews for product
        queryset = Review.objects.filter(product_id=product_id)

        queryset = queryset.annotate(
          original_review=F('review'),
          original_rating=F('rating'),
          original_created_on=F('created_on'),
        )

        queryset = queryset.values(
          name=F('customer__name'),
          tmp_review=F('review'),
          tmp_rating=F('rating'),
          tmp_created_on=F('created_on'),
        )

        if queryset.exists():
            status_code = 200
        else:
            status_code = 204

        response = [self.render_product_review_row(row) for row in queryset]

        return Response(response, status_code)

    @swagger_auto_schema(method='POST', request_body=openapi.Schema(
        type=openapi.TYPE_OBJECT,
        properties={
            'review': openapi.Schema(type=openapi.TYPE_STRING, description='Review Text of Product', required=['true']),
            'rating': openapi.Schema(type=openapi.TYPE_INTEGER, description='Rating of Product', required=['true']),
        }
    ))

列出所有产品的回复应为:

 {
    ​"paginationMeta"​: {
​        "currentPage"​: ​integer​,
    ​    "currentPageSize"​: ​integer​,
        "totalPages"​: ​integer​,
        "totalRecords"​: ​integer​
    },
​    "rows"​: [ {
​        "product_id"​: ​integer​,
        "name"​: ​string​,
        ​"description"​: ​string​,
    ​    "price"​: ​string​,
    ​    "discounted_price"​: ​string​,
        "thumbnail"​: ​string​
    }
}

单个产品的响应应为:

params:
{
    ​"description_length"​: ​integer​ //Limit of the description, default: 200
}

{
    ​"product_id"​: ​integer​,
    "name"​: ​string​,
    "description"​: ​string​,
    ​"price"​: ​string​,
    ​"discounted_price"​: ​string​,
    "image"​: ​string​,
    "image_2"​: ​string​,
    "thumbnail"​: ​string​
} ​ 

我应该覆盖这些方法并为此使用自定义序列化程序,还是有一种更简单/更好的方法来获得上述结果?

1 个答案:

答案 0 :(得分:1)

您可以编写2个Serializer,一个用于获取列表,一个用于检索1个项目。

我假设ProductSerializer用于检索,而ProductListSerializer用于列表。

class ProductListSerializer(serializers.ModelSerializer):
    class Meta:
        model = Product
        fields = ('product_id', 'name',)
        # only show 2 field when get all item

您需要覆盖get_serializer_class。我认为,我们可以创建如下的mixin类:

class MultiSerializerViewSetMixin(object):
    def get_serializer_class(self):
        try:
            return self.serializer_action_classes[self.action]
        except (KeyError, AttributeError):
            return super(MultiSerializerViewSetMixin, self).get_serializer_class()

并与您的ProductViewSet

一起使用
class ProductViewSet(MultiSerializerViewSetMixin, viewsets.ReadOnlyModelViewSet):
    queryset = Product.objects.all().order_by('product_id')
    serializer_class = ProductSerializer
    serializer_action_classes = {
        'list': ProductListSerializer,
        'retrieve': ProductSerializer,
    }