Django中用user_passes_test校验用户订阅有效性遇无订阅报错
解决Django订阅校验装饰器的问题
你的问题出在两个关键地方:一是捕获了错误的异常类型,二是没有正确调用订阅有效性检查的方法。以下是具体修正方案:
问题分析
- 异常捕获错误:当用户没有订阅时,访问
user.subscription会抛出Subscription.DoesNotExist异常(而非user.DoesNotExist),你原代码的except块无法捕获这个错误,导致直接报错。 - 方法调用错误:代码里的
user.subscription.is_subscription_valid没有加括号,这只是引用了方法对象而非执行方法,会导致无论订阅是否过期,这个值的布尔判断永远为True,完全失去校验作用。
修正后的校验函数
方案一:捕获正确的异常
from .models import Subscription # 确保导入Subscription模型 def subscription_valid(user): # 超级用户直接跳过校验 if user.is_superuser: return True try: # 调用订阅有效性检查方法(必须加括号执行) return user.subscription.is_subscription_valid() except Subscription.DoesNotExist: # 用户无订阅记录,返回False return False
方案二:先检查订阅是否存在
如果不想用异常捕获,也可以用hasattr先判断用户是否有订阅关联:
def subscription_valid(user): if user.is_superuser: return True # 先确认用户存在订阅记录 if hasattr(user, 'subscription'): return user.subscription.is_subscription_valid() # 无订阅则返回False return False
装饰器的使用
将校验函数传入user_passes_test,指定重定向的仪表盘URL:
from django.contrib.auth.decorators import user_passes_test def subscription_required(view_func): return user_passes_test( subscription_valid, login_url='/dashboard/' # 替换为你的仪表盘实际URL )(view_func)
然后在需要校验的视图上使用装饰器:
@subscription_required def premium_content_view(request): # 你的视图逻辑代码 ...
额外优化建议
可以简化Subscription模型的is_subscription_valid方法,保持逻辑清晰:
def is_subscription_valid(self): return timezone.now() < self.expiration_date
内容的提问来源于stack exchange,提问作者Giorgio Scarso
相关产品推荐
相关产品推荐

