You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django ViewSet重写:Inventory变更自动更新InventoryHistory的实现疑问

解决方案

1. 示例模型结构

假设你的模型定义如下:

from django.db import models

class Inventory(models.Model):
    product = models.ForeignKey(Product, on_delete=models.CASCADE)
    quantity = models.IntegerField()
    last_updated = models.DateTimeField(auto_now=True)

class InventoryHistory(models.Model):
    inventory = models.ForeignKey(Inventory, on_delete=models.CASCADE, related_name='history')
    old_quantity = models.IntegerField()
    new_quantity = models.IntegerField()
    changed_at = models.DateTimeField(auto_now_add=True)
    changed_by = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)

2. 定义序列化器

from rest_framework import serializers
from .models import Inventory, InventoryHistory

class InventorySerializer(serializers.ModelSerializer):
    class Meta:
        model = Inventory
        fields = ['id', 'product', 'quantity', 'last_updated']

class InventoryHistorySerializer(serializers.ModelSerializer):
    class Meta:
        model = InventoryHistory
        fields = ['id', 'old_quantity', 'new_quantity', 'changed_at', 'changed_by']

3. 重写ViewSet实现自动记录历史

ViewSet仅用InventorySerializer处理前端请求,历史记录逻辑在内部自动完成:

from rest_framework import viewsets
from .models import Inventory, InventoryHistory
from .serializers import InventorySerializer
from rest_framework.response import Response
from rest_framework import status

class InventoryViewSet(viewsets.ModelViewSet):
    queryset = Inventory.objects.all()
    serializer_class = InventorySerializer

    def create(self, request, *args, **kwargs):
        # 处理库存创建
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        inventory = serializer.save()
        # 创建初始历史记录(旧数量为0)
        InventoryHistory.objects.create(
            inventory=inventory,
            old_quantity=0,
            new_quantity=inventory.quantity,
            changed_by=request.user if request.user.is_authenticated else None
        )
        headers = self.get_success_headers(serializer.data)
        return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)

    def update(self, request, *args, **kwargs):
        partial = kwargs.pop('partial', False)
        instance = self.get_object()
        # 保存更新前的库存数量
        old_quantity = instance.quantity
        # 执行库存更新
        serializer = self.get_serializer(instance, data=request.data, partial=partial)
        serializer.is_valid(raise_exception=True)
        inventory = serializer.save()
        # 仅当数量发生变化时创建历史记录
        if old_quantity != inventory.quantity:
            InventoryHistory.objects.create(
                inventory=inventory,
                old_quantity=old_quantity,
                new_quantity=inventory.quantity,
                changed_by=request.user if request.user.is_authenticated else None
            )
        return Response(serializer.data)

核心要点

  • 无需在ViewSet中暴露InventoryHistorySerializer,历史记录完全由后端自动生成,不接收前端提交的历史数据。
  • 更新操作中增加数量对比逻辑,避免生成无意义的重复历史记录。
  • 操作人字段直接通过request.user获取,兼容未登录场景(设为None)。
  • 如果需要支持批量更新、删除等操作,可在对应的ViewSet方法中添加类似的历史记录创建逻辑。

内容的提问来源于stack exchange,提问作者M Abbas Baloch

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 03:32:04