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

Django书店项目:用户订单展示、修改及个人资料编辑求助

书店Web应用个人中心开发问题解答

用户问题描述

我是Python新手,正在开发书店Web应用,已完成购物车和下单流程,现在开发用户个人中心时遇到三个问题:
设计逻辑:用户创建购物车,下单后购物车仍保留在数据库中。
具体问题:

  1. 如何将订单关联的购物车全部信息展示到用户个人中心?
  2. 如何实现用户资料、订单/购物车信息在个人中心可修改?
  3. 如何在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 02:35:54