Django外键模型字段未正确更新

4 投票
1 回答
4533 浏览
提问于 2025-04-18 10:46

我在更新一个外键模型的字段时遇到了麻烦。我想通过另一个模型的方法来更新这个字段,但运行我的tests.py时,得到的值不对。我想更新“total_purchased”的值。下面是我想实现的一个例子:

我使用的是Django 1.6.4

如果问题太长,能不能用以下两行来总结?我是在一个Django类模型的方法中这么做的:

Ex: Model.ForeignKeyModel.field = some_value
    Model.ForeignKeyModel.save()

有以下三个模型:

class Meal (models.Model):
    name = models.CharField(max_length=255)
    total_purchased = models.IntegerField(default=0, validators=[MaxValueValidator(capacity)])
    capacity = models.IntegerField(default=500)

class Item (models.Model):
    cart = models.ForeignKey(Cart)
    meal = models.ForeignKey(Meal)
    quantity = models.IntegerField(validators=[MinValueValidator(0)], default=0)

class Cart (models.Model):
    delivery = models.ForeignKey(DeliveryInfo)
    subscription = models.BooleanField(default=False)
    customer = models.ForeignKey(User)

    def add(self, meal, quantity):
        """ Dual Add/Remove from cart method, (quantity replaces current quantity) """
        item = Item.objects.get_or_create(cart=self, meal=meal)[0]
        remaining_capacity = item.meal.capacity - item.meal.total_purchased

        # Meal exists on our cart, so proceed with adding or removing
        if quantity <= remaining_capacity:

            if quantity == 0:
                # Add back whatever quantity the user didn't buy
                item.meal.total_purchased = 0
                item.meal.save()

                # Remove entire item from cart (quantity = 0)
                item.delete()

            elif quantity == item.quantity:
                # Do nothing if cart quantity equals current quantity
                pass

            else:
                if quantity < item.quantity:
                    # Decrement total purchased
                    item.meal.total_purchased -= (item.quantity - quantity)
                    item.meal.save()

                else:
                    # Increment total_purchased by the quantity we're adding to the cart
                    item.meal.total_purchased += (quantity - item.quantity)
                    item.meal.save()

            # Update the Cart
            item.quantity = quantity
            item.save()

            remaining_capacity = item.meal.capacity - item.meal.total_purchased

    else:
        exceeded = abs(remaining_capacity - quantity)
        raise ValidationError("Your cart exceeds the total remaining quantity by {0}!".format(exceeded))

在第一次更新时是有效的,但似乎在下一次调用“添加到购物车”方法时就被忽略了,结果在我的tests.py中出现了以下内容: self.assertEqual(item.total_purchased, 2) AssertionError: 1 != 2

我不确定这是否是因为购物车的更新发生在tests.py中,还是我以某种方式保存数据不正确。任何帮助都非常感谢。

根据要求,这是我运行测试的tests.py:

customer = User.objects.filter(pk=1)[0]
delivery_info = DeliveryInfo.objects.filter(owner=customer)[0]
cart_order = CartOrder.objects.create(owner=customer, delivery=delivery_info, subscription=False)

# Query the meal_items
curry_item = Meal.objects.get(pk=1)
burger_item = Meal.objects.get(pk=2)

# Add some meal items to our cart, the cart_order add method creates Items
cart_order.add(curry_item, 2)
cart_order.add(burger_item, 1)

self.assertEqual(burger_item.total_purchased, 1)

# Removing one item from the cart
cart_order.add(curry_item, 1)

# Doing nothing to the cart
cart_order.add(curry_item, 1)

** 这里是更新值失败的地方: **

# Adding an item to the cart
cart_order.add(burger_item, 2)
self.assertEqual(burger_item.total_purchased, 2)

1 个回答

5

这个问题发生的原因是你使用的模型实例没有被更新。
第一次调用 get_or_create 时,它会创建一个 Item,并使用来自 meal=mealMeal;而第二次调用时,它获取的是 Item,却没有使用同一个 Meal 实例。

因为你已经有一个 meal 的实例作为参数,你可以把 item.meal 替换成 meal,这样你应该能看到想要的结果。或者,你也可以在添加后重新加载 burger_item 或任何餐点。

不过,你真的应该考虑使用 F() 表达式来进行增量操作,因为这些操作只在数据库端执行,可以帮助防止竞争条件。要注意的是,使用 F() 表达式后,你需要重新加载 Meal 才能看到它的新值。

另外,注意

# Update the Cart
item.quantity = quantity
item.save()

quantity == 0 的情况下被调用,并且你删除了 Item,因为这会重新创建 Item

撰写回答