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

Django Rest Framework权限测试问题:如何刷新关联关系?

解决DRF权限类测试中反向关联QuerySet缓存导致的校验失败问题

看起来你遇到的问题是Django反向关联QuerySet的缓存机制在搞鬼!让我一步步帮你理清:

问题根源

当你调用self.restaurant.refresh_from_db()时,这个方法只会刷新Restaurant对象自身的字段(比如name、slug这些),不会刷新它的反向关联(比如table_set)。如果在测试中你之前访问过self.restaurant.table_set(哪怕只是打印它),Django会缓存这个QuerySet的结果,后续即使数据库里已经有了关联的Table记录,缓存的空结果也会被复用,导致restaurant.table_set.filter(...).exists()返回False。

而你看到table.restaurant == self.restaurant为True,是因为Table对象的restaurant外键字段是直接存在于Table表中的,它的关联是实时的,不受反向QuerySet缓存的影响。

解决方案1:优化权限类的校验逻辑(推荐)

其实你的权限校验完全不需要通过restaurant.table_set来查询,直接对比餐桌的餐厅和请求中指定的餐厅是否一致即可,这样不仅避免了缓存问题,还更高效:

from annoying.functions import get_object_or_None
from django.utils.translation import ugettext_lazy as _
from rest_framework import permissions
from restaurants.models import Restaurant

class TableBelongsToRestaurantPermission(permissions.BasePermission):
    """
    Permission to check if the table belongs to the restaurant in the request.
    This ensures (together with the UserOwnsRestaurantPermission) that owner can change the QR code of a restaurant that he doesn't own.
    """
    message = TABLE_BELONGS_TO_RESTAURANT_PERMISSION_DENIED_MESSAGE

    def has_object_permission(self, request, view, obj):
        if not obj.table:
            return True
        slug = request.data.get("restaurant_slug", "")
        restaurant = get_object_or_None(Restaurant, slug=slug)
        if restaurant:
            # 直接对比餐桌的餐厅和请求中的餐厅,跳过反向QuerySet查询
            return obj.table.restaurant == restaurant
        return False

解决方案2:在测试中刷新反向关联的QuerySet

如果你一定要保留原来的权限逻辑,那在测试中需要强制刷新table_set的缓存,而不是只刷新Restaurant对象。可以通过以下方式:

# 在测试方法中,创建Table并关联后,不要只调用refresh_from_db()
# 重新从数据库获取Restaurant对象,彻底绕过缓存
self.restaurant = Restaurant.objects.get(pk=self.restaurant.pk)

这样重新查询出来的Restaurant对象,它的table_set会重新从数据库加载数据,不会使用之前的缓存。

为什么推荐方案1?

  • 性能更好:不需要额外执行一次table_set.filter的数据库查询,直接对比外键对象即可
  • 避免缓存陷阱:完全绕开了Django反向关联QuerySet的缓存问题,后续不会再遇到类似的测试或生产环境问题
  • 逻辑更直观:校验逻辑直接表达了“餐桌的餐厅是否等于请求中的餐厅”,比通过反向查询存在性更清晰

内容的提问来源于stack exchange,提问作者J. Hesters

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 06:24:28