from rest_framework.generics import ListAPIView from rest_framework.pagination import LimitOffsetPagination from rest_framework import filters, serializers from django_filters.rest_framework import DjangoFilterBackend from django_filters import rest_framework as django_filters from stock import models class StockSnapshotSerializer(serializers.ModelSerializer): """库存快照序列化器""" product_name = serializers.CharField(source='product.name', read_only=True) product_code = serializers.CharField(source='product.code', read_only=True) warehouse_name = serializers.CharField(source='warehouse.name', read_only=True) unit_display = serializers.CharField(source='get_unit_display', read_only=True) stock_change_record_type = serializers.CharField( source='stock_change_record.get_type_display', read_only=True ) stock_change_record_source = serializers.CharField( source='stock_change_record.get_source_type_display', read_only=True ) class Meta: model = models.StockSnapshot fields = [ 'id', 'product', 'product_name', 'product_code', 'warehouse', 'warehouse_name', 'delta', 'quantity_before', 'quantity_after', 'stock_change_record', 'stock_change_record_type', 'stock_change_record_source', 'unit', 'unit_display', 'num_of_rolls', 'offset_to', 'offset_at', 'cancelled', 'cancelled_at', 'offset_id', 'created_at', 'updated_at' ] class StockSnapshotFilterSet(django_filters.FilterSet): """库存快照过滤器""" product_name = django_filters.CharFilter(field_name='product__name', lookup_expr='icontains') product_code = django_filters.CharFilter(field_name='product__code', lookup_expr='icontains') warehouse_name = django_filters.CharFilter(field_name='warehouse__name', lookup_expr='icontains') cancelled = django_filters.BooleanFilter() has_offset = django_filters.BooleanFilter(method='filter_has_offset') date_from = django_filters.DateFilter(field_name='created_at', lookup_expr='gte') date_to = django_filters.DateFilter(field_name='created_at', lookup_expr='lte') def filter_has_offset(self, queryset, name, value): """过滤是否有冲抵记录""" if value: return queryset.exclude(offset_to__isnull=True) else: return queryset.filter(offset_to__isnull=True) class Meta: model = models.StockSnapshot fields = [ 'product', 'warehouse', 'stock_change_record', 'unit', 'cancelled' ] class StockSnapshotListView(ListAPIView): """ 库存快照列表视图(只读) 提供库存变动快照的查询功能 查询参数: - product: 产品ID - product_name: 产品名称(模糊查询) - product_code: 产品编码(模糊查询) - warehouse: 仓库ID - warehouse_name: 仓库名称(模糊查询) - stock_change_record: 关联的库存变动记录ID - unit: 单位 - cancelled: 是否已取消(true/false) - has_offset: 是否有冲抵记录(true/false) - date_from: 开始日期(格式:YYYY-MM-DD) - date_to: 结束日期(格式:YYYY-MM-DD) - search: 全文搜索(产品名称、产品编码、仓库名称) - ordering: 排序字段 """ serializer_class = StockSnapshotSerializer pagination_class = LimitOffsetPagination filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter] filterset_class = StockSnapshotFilterSet search_fields = ['product__name', 'product__code', 'warehouse__name'] ordering_fields = [ 'id', 'delta', 'quantity_before', 'quantity_after', 'created_at', 'updated_at', 'offset_at', 'cancelled_at' ] ordering = ['-created_at'] def get_queryset(self): """优化查询,预加载关联数据""" return models.StockSnapshot.objects.select_related( 'product', 'warehouse', 'stock_change_record' ).all()