Python DJANGO电子商务网站需要帮助。不同的订单具有相同的订单项

Python DJANGO电子商务网站需要帮助。不同的订单具有相同的订单项,python,django,Python,Django,所以我跟随YouTube上的教程,用DJANGO制作一个电子商务网站,但问题是,现在我已经完成了教程,我意识到有些地方出了问题。因此,每当我下一个新订单时,该订单中都有订单项,因为订单模型有一个带有订单项的manytomanyfield。所以我下了一个订单并保存了它。但是如果我下了第二个订单,然后保存它,第一个订单的订单项将与第二个订单项相等,这是不应该发生的。我已经做了4个小时了,我不知道该怎么办,所以我非常感谢你的帮助。两个订单都有不同的ref_代码,因此至少可以正常工作。随附两份订单的管理

所以我跟随YouTube上的教程,用DJANGO制作一个电子商务网站,但问题是,现在我已经完成了教程,我意识到有些地方出了问题。因此,每当我下一个新订单时,该订单中都有订单项,因为订单模型有一个带有订单项的manytomanyfield。所以我下了一个订单并保存了它。但是如果我下了第二个订单,然后保存它,第一个订单的订单项将与第二个订单项相等,这是不应该发生的。我已经做了4个小时了,我不知道该怎么办,所以我非常感谢你的帮助。两个订单都有不同的ref_代码,因此至少可以正常工作。随附两份订单的管理员视图截图。
Youtube教程:

Models.py

from django.db import models
from django.conf import settings
from django.shortcuts import reverse

# Create your models here.

CATEGORY_CHOICES = (
    ('S', 'Shirt'),
    ('SW', 'Sport Wear'),
    ('OW', 'Outwear'),

)

LABEL_CHOICES = (
    ('P', 'primary'),
    ('S', 'secondary'),
    ('D', 'danger'),

)


class Item(models.Model):
    title = models.CharField(max_length=100)
    price = models.FloatField()
    discount_price = models.FloatField(default=0)
    category = models.CharField(choices=CATEGORY_CHOICES, max_length=2)
    label = models.CharField(choices=LABEL_CHOICES, max_length=1)
    slug = models.SlugField()
    description = models.TextField()

    def __str__(self):
        return self.title

    def get_absolute_url(self):
        return reverse("core:product", kwargs={
            'slug': self.slug
        })

    def get_add_to_cart_url(self):
        return reverse("core:add-to-cart", kwargs={
            'slug': self.slug
        })

    def get_remove_from_cart_url(self):
        return reverse("core:remove-from-cart", kwargs={
            'slug': self.slug
        })


class OrderItem(models.Model):
    user = models.ForeignKey(settings.AUTH_USER_MODEL,
                             on_delete=models.CASCADE)
    ordered = models.BooleanField(default=False)
    item = models.ForeignKey(Item, on_delete=models.CASCADE)
    quantity = models.IntegerField(default=1)

    def get_total_item_price(self):
        return self.quantity * self.item.price

    def get_total_discounted_item_price(self):
        return self.quantity * self.item.discount_price

    def get_amount_saved(self):
        return self.get_total_item_price() - self.get_total_discounted_item_price()

    def get_final_price(self):
        if self.item.discount_price:
            return self.get_total_discounted_item_price()
        return self.get_total_item_price()

    def __str__(self):
        return f"{self.quantity} of {self.item.title}"


class Order(models.Model):
    user = models.ForeignKey(settings.AUTH_USER_MODEL,
                             on_delete=models.CASCADE)
    ref_code = models.CharField(max_length=20,default="0")
    items = models.ManyToManyField(OrderItem)
    start_date = models.DateTimeField(auto_now_add=True)
    ordered_date = models.DateTimeField()
    ordered = models.BooleanField(default=False)
    billing_address = models.ForeignKey('BillingAddress', on_delete=models.SET_NULL, blank=True, null=True)
    being_delivered = models.BooleanField(default=False)
    received = models.BooleanField(default=False)
    refund_requested = models.BooleanField(default=False)
    refund_granted = models.BooleanField(default=False)





    def __str__(self):
        return self.user.username

    def get_total(self):
        total = 0
        for order_item in self.items.all():
            total += order_item.get_final_price()
        return total
Views.py

from django.shortcuts import render, get_object_or_404, redirect
from django.views.generic import ListView, DetailView, View
from django.contrib import messages
from .models import *
from django.utils import timezone
from django.core.exceptions import ObjectDoesNotExist
from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin
from .forms import *
import random
import string


# Create your views here.

def create_ref_code():
    return ''.join(random.choices(string.ascii_lowercase + string.digits, k=20))


class CheckoutView(View):
    def get(self, *args, **kwargs):
        form = CheckoutForm()
        order = Order.objects.get(user=self.request.user, ordered=False)
        stuff_for_frontend = {
            'form': form,
            'order': order,
        }
        return render(self.request, 'checkout.html', stuff_for_frontend)

    def post(self, *args, **kwargs):
        form = CheckoutForm(self.request.POST or None)
        try:
            order = Order.objects.get(user=self.request.user, ordered=False)
            if form.is_valid():

                if not ('0' <= form.cleaned_data.get('mobile_number') <= '99999999999'):
                    messages.warning(self.request, "Mobile Number is invalid")

                    messages.warning(self.request, "Failed Checkout")
                    return redirect('core:checkout')

                street_address = form.cleaned_data.get('street_address')
                apartment_address = form.cleaned_data.get('apartment_address')
                mobile_number = form.cleaned_data.get('mobile_number')
                city = form.cleaned_data.get('city')
                zip = form.cleaned_data.get('zip')
                # same_shipping_address = form.cleaned_data.get('same_shipping_address')
                # save_info = form.cleaned_data.get('save_info')
                payment_option = form.cleaned_data.get('payment_option')
                billing_address = BillingAddress(
                    user=self.request.user,
                    street_address=street_address,
                    apartment_address=apartment_address,
                    mobile_number=mobile_number,
                    city=city,
                    zip=zip

                )
                billing_address.save()
                order.billing_address = billing_address
                order.ordered = True
                order.ref_code = create_ref_code()
                order.save()

                messages.success(self.request, "Your order was successful")
                return redirect('/')
            messages.warning(self.request, "Failed Checkout")
            return redirect('core:checkout')
        except ObjectDoesNotExist:
            messages.error(self.request, "You do not have an active order")
            return redirect("core:order-summary")


class HomeView(ListView):
    model = Item
    paginate_by = 10
    template_name = "home.html"


class ItemDetailView(DetailView):
    model = Item
    template_name = 'product.html'


class OrderSummary(LoginRequiredMixin, View):
    def get(self, *args, **kwargs):
        try:
            order = Order.objects.get(user=self.request.user, ordered=False)
            stuff_for_frontend = {
                'object': order
            }
            return render(self.request, 'order_summary.html', stuff_for_frontend)
        except ObjectDoesNotExist:
            messages.error(self.request, "You do not have an active order")
            return redirect("/")


@login_required
def add_to_cart(request, slug):
    item = get_object_or_404(Item, slug=slug)
    order_item, created = OrderItem.objects.get_or_create(item=item, user=request.user, ordered=False)
    order_qs = Order.objects.filter(user=request.user, ordered=False)
    if order_qs.exists():
        order = order_qs[0]
        print(order_qs)
        if order.items.filter(item__slug=item.slug).exists():
            order_item.quantity += 1
            order_item.save()
            messages.info(request, "This item's quantity was updated")
            return redirect("core:order-summary")
        else:
            order.items.add(order_item)
            messages.info(request, "This item was added to your cart")
            return redirect("core:order-summary")

    else:

        order = Order.objects.create(user=request.user, ordered_date=timezone.now())
        order.items.add(order_item)
        messages.info(request, "This item was added to your cart")
        return redirect("core:order-summary")


@login_required
def remove_from_cart(request, slug):
    item = get_object_or_404(Item, slug=slug)
    order_qs = Order.objects.filter(user=request.user, ordered=False)
    if order_qs.exists():
        order = order_qs[0]

        if order.items.filter(item__slug=item.slug).exists():
            order_item = OrderItem.objects.filter(item=item, user=request.user, ordered=False)[0]

            order.items.remove(order_item)
            messages.info(request, "This item was removed from your cart")
            return redirect("core:order-summary")
        else:
            messages.info(request, "This item was not in your cart")
            return redirect("core:product", slug=slug)
    else:
        messages.info(request, "You do not have an active order")
        return redirect("core:product", slug=slug)


@login_required
def remove_single_item_from_cart(request, slug):
    item = get_object_or_404(Item, slug=slug)
    order_qs = Order.objects.filter(user=request.user, ordered=False)
    if order_qs.exists():
        order = order_qs[0]

        if order.items.filter(item__slug=item.slug).exists():
            order_item = OrderItem.objects.filter(item=item, user=request.user, ordered=False)[0]
            if order_item.quantity > 1:
                order_item.quantity -= 1
                messages.info(request, "This item quantity was updated")
            else:
                order.items.remove(order_item)
                messages.info(request, "This item was removed from your cart")
            order_item.save()

            return redirect("core:order-summary")
        else:
            messages.info(request, "This item was not in your cart")
            return redirect("core:product", slug=slug)
    else:
        messages.info(request, "You do not have an active order")
        return redirect("core:product", slug=slug)


从django.shortcuts导入渲染,获取对象或重定向
从django.views.generic导入ListView、DetailView、View
从django.contrib导入消息
从。模型导入*
从django.utils导入时区
从django.core.exceptions导入ObjectDoesNotExist
从django.contrib.auth.decorators导入所需的登录名
从django.contrib.auth.mixins导入登录名RequiredMixin
从。表格导入*
随机输入
导入字符串
#在这里创建您的视图。
def create_ref_code():
返回“”。联接(随机.choices(string.ascii_小写+string.digits,k=20))
类签出视图(视图):
def get(自身、*args、**kwargs):
表单=CheckoutForm()
order=order.objects.get(user=self.request.user,ordered=False)
用于前端的内容={
“形式”:形式,
“秩序”:秩序,
}
返回渲染(self.request,'checkout.html',stuff_for_frontend)
def post(自我,*args,**kwargs):
表单=检查表单(self.request.POST或无)
尝试:
order=order.objects.get(user=self.request.user,ordered=False)
如果form.is_有效():
如果不是('0'
{%endblock内容%}

OrderItems应具有Order的ForeignKey;Orders不应具有OrderItems的ManyToManyField,因为一个OrderItem不应属于多个订单


此外,OrderItems应该缓存所订购商品的价格-否则,如果您以后要更改商品的价格,则无法运行随时间变化的商品价格报告。

谢谢。我如何缓存价格。我是否只创建一个字段“price=self.item.price”是的。我推荐
单价
数量
折扣
总价
,其中
总价=(单价*数量)-折扣
,但语义由您决定。
{% extends 'base.html' %}

  {%block content%}


  <!--Main layout-->
  <main>
    <div class="container">
        <div class="table-responsive text-nowrap">
          <h2>Order Summary</h2>
          <table class="table">
            <thead>
              <tr>
                  <th scope="col">#</th>
                <th scope="col">Item title</th>
                <th scope="col">Price</th>
                <th scope="col">Discounted Price</th>
                <th scope="col">Quantity</th>
                <th scope="col">Total Item Price</th>

              </tr>
            </thead>
            <tbody>
              <tr>
                {%for order_item in object.items.all%}
                  <th scope="row">{{forloop.counter}}</th>
                  <td>{{order_item.item.title}}</td>
                  <td>{{order_item.item.price}}</td>
                  <td>{{order_item.item.discount_price}}</td>
                  <td><a href="{% url 'core:remove-single-item-from-cart' order_item.item.slug  %}"><i class="fas fa-minus mr-2"></i></a>{{order_item.quantity}}<a href="{% url 'core:add-to-cart' order_item.item.slug  %}"><i class="fas fa-plus ml-2"></i></a></td>
                  <td>
                    {%if order_item.item.discount_price%}

                      ${{order_item.get_total_discounted_item_price}}
                      <span class="badge badge-success">Saving ${{order_item.get_amount_saved}}</span>

                    {%else%}

                      ${{order_item.get_total_item_price}}

                    {%endif%}
                    <a style="color:red;"  href="{% url 'core:remove-from-cart' order_item.item.slug  %}"><i class="fas fa-trash float-right"></i></a>
                  </td>
                </tr>
                {%empty%}
                <tr>
                  <td colspan='5'>Your cart is empty</td>
                </tr>
                <tr>
                  <td colspan="6">
                    <a class="btn btn-dark float-right " href="/">Continue Shopping</a>
                  </td>
                </tr>


              {%endfor%}
              {%if object.get_total %}
              <tr>
                <td colspan="5"><b>Order Total</b></td>
                <td colspan="5"><b>${{object.get_total}}</b></td>
              </tr>
              <tr>
                <td colspan="6">
                  <a class="btn btn-primary float-right ml-2" href="/checkout">Proceed to checkout</a>
                  <a class="btn btn-dark float-right " href="/">Continue Shopping</a>
                </td>
              </tr>
            {%endif%}
            </tbody>
          </table>

        </div>



    </div>
  </main>
  <!--Main layout-->

  {%endblock content%}