Django电商:实现登录用户在商品页添加商品到指定心愿单
问题
需求:实现已登录用户可将当前商品添加至自己此前创建的指定心愿单,需在商品页提供一个带复选框的下拉菜单,展示该用户的所有心愿单。
尝试两种方案均未达预期:
- 在
forms.py中使用request.user过滤Wishlist查询集时,出现「request not defined」错误; - 采用自定义字段后,查询集会获取所有心愿单,而非当前登录用户的。
附相关代码:
models.py
class Wishlist(models.Model): user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, null=True, blank=True) title = models.CharField(max_length=50, null=True,blank=True) slug = models.SlugField(max_length=50, null=True,blank=True) wishlist_cover_image = models.ImageField(upload_to='media/WISHLIST_COVER_IMAGES/', null=True,blank=True) description = RichTextField(max_length=500, null=True,blank=True) products = models.ManyToManyField(Product, null=True,blank=True) date_created = models.DateTimeField(auto_now_add=True) date_updated = models.DateTimeField(auto_now_add=False ,null=True,blank=True) def get_absolute_url(self): return reverse('ecommerce:wishlist', args=[self.slug]) def __str__(self): return self.title
第一种尝试的forms.py
class AddToWishlistForm(forms.ModelForm): wishlists = CustomWLMenu(queryset=Wishlist.objects.filter(user=request.user), widget=forms.CheckboxSelectMultiple) class Meta: model = Profile fields = ['wishlists']
第二种尝试的forms.py
class CustomWLMenu(forms.ModelMultipleChoiceField): def label_from_instance(self, user): return "%s" % user class AddToWishlistForm(forms.ModelForm): wishlists = CustomWLMenu(queryset=Wishlist.objects.filter(), widget=forms.CheckboxSelectMultiple) class Meta: model = Profile fields = ['wishlists']
解决方案
核心问题是表单定义阶段无法直接获取request对象,必须在实例化表单时动态传入用户信息过滤查询集。以下是正确实现步骤:
1. 修正表单定义
先定义自定义字段,表单中不直接指定queryset,留到实例化时设置:
class CustomWLMenu(forms.ModelMultipleChoiceField): def label_from_instance(self, wishlist): return wishlist.title # 修正:参数是Wishlist实例,之前命名为user是错误的 class AddToWishlistForm(forms.Form): # 初始设为空查询集,后续动态赋值 wishlists = CustomWLMenu(queryset=Wishlist.objects.none(), widget=forms.CheckboxSelectMultiple)
2. 在视图中动态过滤查询集
在商品详情视图里,给登录用户实例化表单时,动态设置wishlists字段的查询集:
from django.contrib.auth.decorators import login_required from django.shortcuts import get_object_or_404, render from .models import Product, Wishlist from .forms import AddToWishlistForm @login_required def product_detail(request, slug): product = get_object_or_404(Product, slug=slug) form = AddToWishlistForm() # 过滤当前用户的心愿单 form.fields['wishlists'].queryset = Wishlist.objects.filter(user=request.user) if request.method == 'POST': form = AddToWishlistForm(request.POST) if form.is_valid(): selected_wishlists = form.cleaned_data['wishlists'] # 将商品添加到选中的所有心愿单 for wishlist in selected_wishlists: wishlist.products.add(product) return render(request, 'product_detail.html', {'product': product, 'form': form, 'success': True}) return render(request, 'product_detail.html', {'product': product, 'form': form})
3. 模板渲染表单
在商品页模板中渲染带复选框的心愿单选择菜单:
<form method="post"> {% csrf_token %} {{ form.as_p }} <button type="submit">添加到选中的心愿单</button> </form> {% if success %} <p>商品已成功添加到选中的心愿单!</p> {% endif %}
关键说明
- 表单定义时用
Wishlist.objects.none()作为初始空查询集,避免加载无关数据; - 自定义字段的
label_from_instance方法参数是Wishlist实例,需返回其title作为显示标签; - 视图必须用
@login_required装饰,确保只有登录用户能访问该功能; - 提交表单后,遍历选中的心愿单,通过
add()方法完成商品与心愿单的多对多关联。
内容的提问来源于stack exchange,提问作者Arnold Schwartzkopf
相关产品推荐
相关产品推荐

