Django用户激活时自动创建免费会员报错求助
Django用户激活时自动创建免费会员的问题解决
问题描述
我有一套运行正常的Django认证系统,用户注册后会收到含激活令牌的确认邮件,功能正常。现在想添加代码实现用户点击激活链接时自动创建免费会员,但遇到两个错误:
- 使用
user_membership = UserMembership.objects.create(user=user, membership=free_membership)时,报错fromisoformat: argument must be str - 使用
user_membership = UserMembership.objects.create(user=user, membership='Free')时,报错Cannot assign "'Free'": "UserMembership.membership" must be a "Membership" instance
相关代码
MEMBERSHIP_CHOICES = (('Premium', 'PREMIUM'), ('Free', 'FREE') ) class Membership(models.Model): slug = models.SlugField(null=True, blank=True) # name = models.CharField(max_length=100) description = models.TextField() membership_type = models.CharField(choices=MEMBERSHIP_CHOICES, default='Free',max_length=30) price = models.DecimalField(default=0.00, max_digits=5, decimal_places=2) def __str__(self): return self.membership_type class UserMembership(models.Model): user = models.OneToOneField(Customer, related_name='user_membership', on_delete=models.CASCADE) membership = models.ForeignKey(Membership, related_name='user_membership', on_delete=models.SET_NULL, null=True) start_date = models.DateTimeField(auto_now_add=True) end_date = models.DateTimeField(default=18000) # Calculate based on start_date + 30 days def __str__(self): return self.user.username def account_activate(request, uidb64, token): try: uid = force_str(urlsafe_base64_decode(uidb64)) user = Customer.objects.get(pk=uid) except (TypeError, ValueError, OverflowError, user.DoesNotExist): user = None if user is not None and account_activation_token.check_token(user, token): user.is_active = True user.save() # Create a free membership free_membership = Membership.objects.get(membership_type='Free') # Convert the Membership object to string # free_membership_str = str(free_membership) print(free_membership) # Create a new UserMembership user_membership = UserMembership.objects.create(user=user, membership=free_membership) # user_membership = UserMembership.objects.create(user=user, membership=free_membership.membership_type) # user_membership = UserMembership.objects.create(user=user, membership='Free') # user_membership = UserMembership.objects.create(user=user, membership=self.free_membership) user_membership.save() # # Creating a new UserSubscription # user_subscription = Subscription.objects.create(user_membership=user_membership) # # user_subscription = Subscription() # # user_subscription.user_membership = user_membership # user_subscription.save() # # return user login(request, user) return redirect("homepage:homepage") else: return render(request, "account/registration/activation_invalid.html")
错误原因分析
- 第二个错误:
UserMembership.membership是ForeignKey字段,关联到Membership模型,必须传入Membership实例,不能直接传字符串'Free',这是Django外键字段的基本要求。 - 第一个错误:根源在
UserMembership的end_date字段,设置了default=18000,但DateTimeField需要的是datetime对象或ISO格式的字符串,整数18000无法被解析为datetime,导致抛出fromisoformat: argument must be str错误。
修复方案
1. 修正end_date字段的默认值问题
可以通过两种方式处理:
方式一:在模型重写save方法自动计算
from datetime import timedelta from django.utils import timezone class UserMembership(models.Model): user = models.OneToOneField(Customer, related_name='user_membership', on_delete=models.CASCADE) membership = models.ForeignKey(Membership, related_name='user_membership', on_delete=models.SET_NULL, null=True) start_date = models.DateTimeField(auto_now_add=True) end_date = models.DateTimeField(null=True) # 移除错误的default值 def __str__(self): return self.user.username def save(self, *args, **kwargs): # 若end_date未设置,自动计算为start_date+30天 if not self.end_date: base_date = self.start_date if self.start_date else timezone.now() self.end_date = base_date + timedelta(days=30) super().save(*args, **kwargs)
方式二:创建UserMembership时手动指定end_date
from datetime import timedelta from django.utils import timezone # 在account_activate函数中创建UserMembership时: user_membership = UserMembership.objects.create( user=user, membership=free_membership, end_date=timezone.now() + timedelta(days=30) )
2. 确保Membership实例存在
直接用get方法可能因为数据库中没有membership_type='Free'的记录而抛出异常,改用get_or_create可以自动创建缺失的免费会员记录:
# 在account_activate函数中替换原有的free_membership获取代码 free_membership, created = Membership.objects.get_or_create( membership_type='Free', defaults={ 'description': '免费会员权益', 'price': 0.00, # 可以添加slug等其他字段的默认值 } )
3. 修正模型的__str__方法缩进
原代码中Membership类的__str__方法缩进错误,不在类内部,修正后:
class Membership(models.Model): slug = models.SlugField(null=True, blank=True) # name = models.CharField(max_length=100) description = models.TextField() membership_type = models.CharField(choices=MEMBERSHIP_CHOICES, default='Free',max_length=30) price = models.DecimalField(default=0.00, max_digits=5, decimal_places=2) def __str__(self): return self.membership_type
修正后的完整account_activate函数
from datetime import timedelta from django.utils import timezone def account_activate(request, uidb64, token): try: uid = force_str(urlsafe_base64_decode(uidb64)) user = Customer.objects.get(pk=uid) except (TypeError, ValueError, OverflowError, Customer.DoesNotExist): user = None if user is not None and account_activation_token.check_token(user, token): user.is_active = True user.save() # 获取或创建免费会员实例 free_membership, created = Membership.objects.get_or_create( membership_type='Free', defaults={ 'description': '免费会员权益', 'price': 0.00 } ) # 创建UserMembership并设置end_date user_membership = UserMembership.objects.create( user=user, membership=free_membership, end_date=timezone.now() + timedelta(days=30) ) login(request, user) return redirect("homepage:homepage") else: return render(request, "account/registration/activation_invalid.html")
内容的提问来源于stack exchange,提问作者Steve
相关产品推荐
相关产品推荐

