Django书店项目:用户订单展示、修改及个人资料编辑求助
书店Web应用个人中心开发问题解答
用户问题描述
我是Python新手,正在开发书店Web应用,已完成购物车和下单流程,现在开发用户个人中心时遇到三个问题:
设计逻辑:用户创建购物车,下单后购物车仍保留在数据库中。
具体问题:
- 如何将订单关联的购物车全部信息展示到用户个人中心?
- 如何实现用户资料、订单/购物车信息在个人中心可修改?
- 如何在HTML表格中每行单独显示一个用户订单(当前模板所有订单都在同一行)?
现有代码实现
购物车模型(Cart models)
User = get_user_model() class Cart(models.Model): customer = models.ForeignKey( User, null=True, blank=True, related_name="Customer", verbose_name="Customer", on_delete=models.PROTECT ) @property def total_price_cart(self): goods = self.goods.all() total_price_cart = 0 for good in goods: total_price_cart += good.total_price return total_price_cart def __str__(self): return str(self.pk) class BooksInCart(models.Model): cart = models.ForeignKey( Cart, related_name="goods", on_delete=models.CASCADE, verbose_name="Cart" ) book = models.ForeignKey( Book, on_delete=models.PROTECT, verbose_name='Book', ) quantity = models.IntegerField( verbose_name="Quantity", default=1 ) price = models.DecimalField( verbose_name='Price', max_digits=5, decimal_places=2, ) @property def total_price(self): return self.price * self.quantity
购物车视图(Cart views)
class CartUpdate(View): def post(self, request): action = request.POST.get('submit') if action == "save_cart": cart_id = self.request.session.get('cart_id') cart, created = models.Cart.objects.get_or_create( pk=cart_id, defaults={}, ) if created: self.request.session['cart_id'] = cart.pk goods = cart.goods.all() if goods: for key, value in request.POST.items(): if "quantityforgood_" in key: pk = int(key.split('_')[1]) good = goods.get(pk=pk) good.quantity = int(value) good.save() return HttpResponseRedirect(reverse_lazy("carts:cart_edit")) elif action == "create_order": return HttpResponseRedirect(reverse_lazy('order:create_order')) else: return HttpResponseRedirect(reverse_lazy("carts:cart_edit")) class CartView(generic.DetailView): template_name = 'carts/cart_edit.html' model = models.Cart def get_object(self, queryset=None): cart_id = self.request.session.get('cart_id') cart, created = models.Cart.objects.get_or_create( pk=cart_id, defaults={}, ) if created: self.request.session['cart_id'] = cart.pk book_id = self.request.GET.get('book_pk') if book_id: book = Book.objects.get(pk=int(book_id)) book_in_cart, flat_created = models.BooksInCart.objects.update_or_create( cart=cart, book=book, defaults={ 'price': book.price } ) if not flat_created: q = book_in_cart.quantity + 1 book_in_cart.quantity = q book_in_cart.price = book_in_cart.book.price * q else: book_in_cart.price = book.price book_in_cart.save() return cart class DeleteGoodInCartView(generic.DeleteView): model = models.BooksInCart template_name = 'carts/delete_book_in_cart.html' success_url = reverse_lazy("carts:cart_edit")
订单模型(Order models)
User = get_user_model() class CustomSession(Session): cart = models.ForeignKey( Cart, on_delete=models.CASCADE ) class Meta: app_label = 'cart_id' class Status(models.Model): name = models.CharField(max_length=30) def __str__(self): return self.name class Meta: verbose_name = "Status" verbose_name_plural = "Statuses" class Order(models.Model): user = models.ForeignKey( User, on_delete=models.PROTECT, related_name='orders' ) cart = models.OneToOneField( Cart, on_delete=models.PROTECT, verbose_name="Cart" ) status = models.ForeignKey( Status, on_delete=models.PROTECT ) contact_info = models.TextField( verbose_name="Contact info", ) created = models.DateTimeField( verbose_name="Created", auto_now=False, auto_now_add=True ) updated = models.DateTimeField( verbose_name="Updated", auto_now=True, auto_now_add=False ) def __str__(self): return self.contact_info class Meta: verbose_name = "Order" verbose_name_plural = "Orders"
订单视图(Order views)
class CreateOrderView(generic.FormView): form_class = forms.OrderCreateForm template_name = 'order/create_order.html' success_url = reverse_lazy("order:success") def form_valid(self, form): cart_id = self.request.session.get('cart_id') cart, created = carts_models.Cart.objects.get_or_create( pk=cart_id, defaults={}, ) if created: return HttpResponseRedirect(reverse_lazy('carts:cart_edit')) info = form.cleaned_data.get('contact_info') status = models.Status.objects.get(pk=1) user = self.request.user order = models.Order.objects.update_or_create( cart=cart, contact_info=info, status=status, user=user, ) self.request.session.delete('cart_id') if self.request.user.is_authenticated: cart_id = self.request.session.get('cart_id') customer1 = carts_models.Cart.objects.get(pk=cart_id) customer1.customer = self.request.user customer1.save() return super().form_valid(form) def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) cart_id = self.request.session.get('cart_id') cart, created = carts_models.Cart.objects.get_or_create( pk=cart_id, defaults={}, ) context['object'] = cart return context def get_success_url(self) -> str: del self.request.session['cart_id'] return super().get_success_url() def success(requsest): return render(requsest, 'order/success.html')
用户个人中心视图(User profile views)
class ProfileView(generic.DetailView): def get(self, request, *args, **kwargs): user = get_object_or_404(AppUser, pk=kwargs['pk']) return render(request, 'app_profiles/profile_view.html', context={ 'user': user, 'order': Order.objects.filter(user=request.user), })
用户个人中心模板(User profile template)
<thead> <tr> <th scope="col">Goods</th> <th scope="col">Quantity</th> <th scope="col">Total price</th> <th scope="col">Status</th> <th scope="col">Created</th> <th scope="col">Updated</th> </tr> </thead> <tbody> <tr> {% for order in order.all %} <td>{{ order.created }}</td> <td>{{ order.updated }}</td> <td>{{ order.status }}</td> {% endfor %}
问题解决方案
1. 展示订单关联的购物车全部信息
在个人中心视图中,已通过Order.objects.filter(user=request.user)获取用户订单,每个订单通过cart字段关联购物车,购物车又通过goods关联所有商品。
- 优化视图查询性能:使用
select_related和prefetch_related减少数据库查询次数:
# 修改ProfileView的context部分 'orders': Order.objects.filter(user=request.user).select_related('cart').prefetch_related('cart__goods', 'cart__goods__book')
(建议把变量名从order改为orders,避免与模型类名混淆)
- 模板中展示购物车详情:在订单循环内,通过
order.cart访问购物车,遍历order.cart.goods获取商品信息:
{% for order in orders %} <tr> <td> {% for good in order.cart.goods.all %} {{ good.book.name }}<br> {% endfor %} </td> <td> {% for good in order.cart.goods.all %} {{ good.quantity }}<br> {% endfor %} </td> <td>{{ order.cart.total_price_cart }}</td> <td>{{ order.status.name }}</td> <td>{{ order.created|date:"Y-m-d H:i" }}</td> <td>{{ order.updated|date:"Y-m-d H:i" }}</td> </tr> {% endfor %}
2. 实现个人中心信息修改功能
分三部分实现:用户资料修改、订单信息修改、未下单购物车修改。
用户资料修改
- 创建用户资料表单:
# forms.py from django.contrib.auth.forms import UserChangeForm from .models import AppUser class ProfileEditForm(UserChangeForm): class Meta: model = AppUser fields = ['username', 'email', 'first_name', 'last_name'] # 根据实际用户模型字段调整
- 添加编辑视图:
# views.py class ProfileEditView(generic.UpdateView): model = AppUser form_class = ProfileEditForm template_name = 'app_profiles/profile_edit.html' success_url = reverse_lazy('profiles:profile_view') def get_object(self, queryset=None): return self.request.user
- 在个人中心模板添加编辑入口:
<a href="{% url 'profiles:profile_edit' %}">编辑个人资料</a>
订单信息修改
- 创建订单编辑表单(仅开放可修改字段):
# forms.py from .models import Order class OrderEditForm(forms.ModelForm): class Meta: model = Order fields = ['contact_info'] # 订单状态建议由后台管理,不开放给用户修改
- 添加订单编辑视图:
# views.py class OrderEditView(generic.UpdateView): model = Order form_class = OrderEditForm template_name = 'app_profiles/order_edit.html' success_url = reverse_lazy('profiles:profile_view') def get_queryset(self): # 限制用户只能修改自己的订单 return Order.objects.filter(user=self.request.user)
- 在订单表格添加编辑按钮:
<td><a href="{% url 'profiles:order_edit' order.pk %}">编辑</a></td>
未下单购物车修改
直接复用已有的CartView和CartUpdate视图,在个人中心添加购物车入口:
<a href="{% url 'carts:cart_edit' %}">查看/编辑购物车</a>
3. 表格每行显示一个订单
当前模板的问题是所有订单字段都放在同一个<tr>内,只需将{% for order in orders %}循环移到<tr>标签外,确保每个订单生成独立行:
修改后的模板代码:
<thead> <tr> <th scope="col">商品</th> <th scope="col">数量</th> <th scope="col">总价</th> <th scope="col">状态</th> <th scope="col">创建时间</th> <th scope="col">更新时间</th> <th scope="col">操作</th> </tr> </thead> <tbody> {% for order in orders %} <tr> <td> {% for good in order.cart.goods.all %} {{ good.book.name }}<br> {% endfor %} </td> <td> {% for good in order.cart.goods.all %} {{ good.quantity }}<br> {% endfor %} </td> <td>{{ order.cart.total_price_cart }}</td> <td>{{ order.status.name }}</td> <td>{{ order.created|date:"Y-m-d H:i" }}</td> <td>{{ order.updated|date:"Y-m-d H:i" }}</td> <td><a href="{% url 'profiles:order_edit' order.pk %}">编辑</a></td> </tr> {% empty %} <tr> <td colspan="7">暂无订单</td> </tr> {% endfor %} </tbody>
内容的提问来源于stack exchange,提问作者Alex
相关产品推荐
相关产品推荐

