首页 > 解决方案 > 如何在模型名称订单的单个字段中由用户获取购物车的所有项目

问题描述

现在我可以保存数据,但所有项目都单独保存而不是在一个字段中,所以我如何实现这一点,我使用购物车作为会话将其 id 和大小保存为键和值

我要保存订单的models.py

class Order(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE,)
    item = models.ForeignKey(Item, on_delete=models.CASCADE )
    status = models.IntegerField(choices = status_choices, default=1)
    method = models.CharField(max_length=50, blank=False,)
    size = models.CharField(max_length=20, blank=False)
    price = models.FloatField(blank=False)
    created_at = models.DateField(auto_now=True, editable=False)
    payment_status = models.IntegerField(choices = payment_status_choices, default=3)
    order_id = models.CharField(unique=True, max_length=200, null=True, blank=True, default=None) 
    datetime_of_payment = models.DateTimeField(default=timezone.now)
    

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

我的views.py 来保存数据

以及我的购物车显示的 html

<tbody style="margin-bottom: 20px;">
                              {% for item in items %}
                              <tr>
                                <th scope="row">{{forloop.counter}}</th>
                                <td> <img src="{{item.first.url}}" alt="" height="100px"></td>
                                <td>{{item.name}}</td>
                                {% if item.swag %}
                                 <td>{{item|cart_size:request.session.cart}}</td>
                                 {% endif %}
                                 {% if not item.swag %}
                                 <td>Regular </td>
                                 {% endif %}
                                <td>{{item.price|currency}}</td>
                                <td> <a href="#">Remove</a> </td>
                              </tr>
                              {% endfor %}
                            </tbody>
                        </table>
                    </div>
                </div>
            </aside>
            <aside class="col-lg-3">
                <div class="card mb-3">
                    <div class="card-body">
                        <form>
                            <div class="form-group"> <label>Have coupon?</label>
                                <div class="input-group"> <input type="text" class="form-control coupon" name="" placeholder="Coupon code"> <span class="input-group-append"> <button class="btn btn-primary btn-apply coupon">Apply</button> </span> </div>
                            </div>
                        </form>
                    </div>
                </div>
                <div class="card">
                    <div class="card-body">
                        <dl class="dlist-align">
                            <dt style="float: left; font-size:20px; margin-right:10px;">Total price:</dt>
                            <dd style="font-size: 20px; color:#025;" class="text-right">{{items|total_actual_price:request.session.cart|currency}}</dd>
                        </dl>
                        <dl class="dlist-align">
                            <dt style="float: left; font-size:20px; margin-right:10px;">Discount:</dt>
                            <dd style="font-size: 20px; color:#025;" class="text-right text-danger">{{items|discount_price:request.session.cart|currency}}</dd>
                        </dl>
                        <dl class="dlist-align">
                            <dt style="float: left; font-size:20px; margin-right:10px;">Total Paying Amount:</dt>
                            <dd style="font-size: 20px; color:#025;" class="text-right"><strong name="price" >{{items|total_price:request.session.cart|currency}}</strong></dd>
                        </dl>
                        <hr>
                        <a href="#" class="btn btn-out btn-primary btn-square btn-main" data-bs-toggle="modal" data-bs-target="#exampleModal"> Make Purchase </a> <a href="#" class="btn btn-out btn-success btn-square btn-main mt-2" data-abc="true">Continue Shopping</a>
                    </div>
                </div>
            </aside>
        </div>
    </div>

正如您所看到的,我正在使用过滤器来显示用户购物车的总价格,所以我想要的是保存项目字段中所有项目的项目 ID 和大小字段中的大小,根据他们的项目,而不是总价格得到保存。但是现在它正在为项目保存单独的字段,我不想要那个

它现在的样子

我用于结帐和保存订单的 html 表单

<div class="modal-body">
           <form action="{% url 'orders:checkout' %}" method="Post">
             {% csrf_token %}
             <h3>Please Select Your Payment Method</h3>  <br>
             <div class="method" style="font-size: 23px;">
              <input type="radio" value="postpaid" name="payment" style="height: 20px; width: 20px;">
              <label for="postpaid">Cash On Delivery</label>
              <input type="radio" value="Prepaid" name="payment" style="height: 20px; width: 20px;">
              <label for="prepaid">Online Payment</label>
            </div>
          </div>
          <input type="submit" class="btn float-right btn-primary" value='Go Ahead'>
        </form>

项目模型

class Item(models.Model):
    categories = models.ForeignKey(Categories, on_delete=models.CASCADE, related_name='our_items')
    subcategories = models.ForeignKey(Subcategories, on_delete=models.CASCADE, related_name='products')
    name = models.CharField(max_length=200, blank=False)
    contain_size = models.CharField(max_length=50, blank=True)
    brand_name = models.CharField(max_length=100, blank=False, default='Bagh')
    swag = models.BooleanField(blank=False, default=False)
    male = models.BooleanField(blank=False, default=False)
    female = models.BooleanField(blank=False, default=False)
    unisex = models.BooleanField(blank=False, default=False)
    first = models.ImageField(upload_to='items', blank=False)
    second = models.ImageField(upload_to='items', blank=False)
    third = models.ImageField(upload_to='items', blank=True)
    fourth = models.ImageField(upload_to='items', blank=True)
    fifth = models.ImageField(upload_to='items', blank=True)
    sixth = models.ImageField(upload_to='items', blank=True)
    seventh = models.ImageField(upload_to='items', blank=True)
    rate = models.CharField(max_length=5, choices=rating, default='⭐⭐⭐⭐')
    stock = models.CharField(max_length=50, blank=False, default='In Stock')
    authentic = models.CharField(max_length=1,blank=False,choices=auth, default='✔')
    price = models.FloatField(blank=False,)
    actual_price = models.FloatField(blank=False)
    type = models.CharField(blank=False, max_length=100, default='Cloth')
    joined_date = models.DateTimeField(default=timezone.now,editable=False)
    update_at = models.DateTimeField(auto_now=True)
    description = models.TextField(blank=True)
    
    @staticmethod
    def get_items_by_id(ids):
        return Item.objects.filter(id__in = ids)
    
    def __str__(self):
        return self.name

和购物车视图,用户选择后所有项目都在哪里

class Cart(View):
    def get (self, request): 
        cart = request.session.get('cart', None)
        if not cart:
            cart = {}
        request.session['cart'] = cart
        ids = (list(cart.keys()))
        ids = (list(request.session.get('cart').keys()))
        item = Item.get_items_by_id(ids)
        address = Address.objects.filter(user=request.user)
        print(item)
        return render(request, 'cart.html', {'items': item, 'addresses':address })

在此处输入图像描述

它确实将项目保存在其中,但我想在该字段中获取汽车的所有项目

adding updated model as told



      class Order(models.Model):
    status_choices = (
        (1, 'PENDING'),
        (2, 'CONFIRMED'),
        (3, 'PACKED'),
        (4, 'SHIPPED'),
        (5, 'IN WAY'),
        (6, 'ARRIVED DESTINATION'),
        (7, 'RECIEVED'),
        (8, 'COMPLETED')
    )
    payment_status_choices = (
        (1, 'SUCCESS'),
        (2, 'FAILURE' ),
        (3, 'PENDING'),
    )
    user = models.ForeignKey(User, on_delete=models.CASCADE,)
    address = models.ForeignKey(Address, default= True, on_delete=models.CASCADE )
    status = models.IntegerField(choices = status_choices, default=1)
    method = models.CharField(max_length=50, blank=False,)
    total_price = models.FloatField(blank=False, default=0)
    created_at = models.DateField(auto_now=True, editable=False)
    payment_status = models.IntegerField(choices = payment_status_choices, default=3)
    order_id = models.CharField(unique=True, max_length=200, null=True, default=None) 
    datetime_of_payment = models.DateTimeField(default=timezone.now)
    # related to razorpay
    razorpay_order_id = models.CharField(max_length=1000, null=True, blank=True)
    razorpay_payment_id = models.CharField(max_length=1000, null=True, blank=True)
    razorpay_signature = models.CharField(max_length=1000, null=True, blank=True)

    def save(self, *args, **kwargs):
        if self.order_id is None and self.datetime_of_payment and self.id:
            self.order_id = self.datetime_of_payment.strftime('CODER%Y%m%dODR') + str(self.id)
            return super().save(*args, **kwargs)

    def __str__(self):
        return self.user.username + " " + str(self.order_id) + " " + str(self.created_at)

class OrderItem(models.Model):
    order = models.ForeignKey(Order, on_delete=models.CASCADE,)
    item = models.ForeignKey(Item, on_delete=models.CASCADE )
    size = models.CharField(max_length=20, blank=False)
    price = models.FloatField(blank=False)
    
    
    def __str__(self):
        return self.order.order_id

更新的views.py

class Checkout(View):
def post (self, request,):
    user = request.user
    address = Address.objects.filter(default=True, user=request.user)
    cart = request.session.get('cart')
    items = Item.get_items_by_id(list(cart.keys()))
    prefer = request.POST.get('payment')
    total_price = request.POST.get('paying_price')
    total_price = json.loads(total_price)

    with transaction.atomic():
        order = Order.objects.create(
                user=user,
                total_price=total_price,
                address=address.first(),
                method = prefer,
                )
        for item in items:
            item_order = OrderItem.objects.create(
                order=order,
                item=item,
                size=cart.get(str(item.id)),
                price=item.price,
            )
        request.session['cart'] = {}
    return redirect('orders:cart',)

添加回溯

环境:

Request Method: POST
Request URL: http://localhost:8000/Check-Out/

Django Version: 3.2.6
Python Version: 3.8.5
Installed Applications:
['django.contrib.admin',
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.staticfiles',
 'crispy_forms',
 'xhtml2pdf',
 'accounts',
 'products',
 'orders']
Installed Middleware:
['django.middleware.security.SecurityMiddleware',
 'django.contrib.sessions.middleware.SessionMiddleware',
 'django.middleware.common.CommonMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware',
 'django.middleware.clickjacking.XFrameOptionsMiddleware']



Traceback (most recent call last):
  File "C:\Users\mithlesh\Desktop\coolbuy\lib\site-packages\django\core\handlers\exception.py", line 47, in inner
    response = get_response(request)
  File "C:\Users\mithlesh\Desktop\coolbuy\lib\site-packages\django\core\handlers\base.py", line 181, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "C:\Users\mithlesh\Desktop\coolbuy\lib\site-packages\django\views\generic\base.py", line 70, in view
    return self.dispatch(request, *args, **kwargs)
  File "C:\Users\mithlesh\Desktop\coolbuy\lib\site-packages\django\views\generic\base.py", line 98, in dispatch
    return handler(request, *args, **kwargs)
  File "C:\Users\mithlesh\Desktop\coolbuy\coolbuy\orders\views.py", line 61, in post
    item_order = OrderItem.objects.create(
  File "C:\Users\mithlesh\Desktop\coolbuy\lib\site-packages\django\db\models\manager.py", line 85, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "C:\Users\mithlesh\Desktop\coolbuy\lib\site-packages\django\db\models\query.py", line 453, in create
    obj.save(force_insert=True, using=self.db)
  File "C:\Users\mithlesh\Desktop\coolbuy\lib\site-packages\django\db\models\base.py", line 682, in save
    self._prepare_related_fields_for_save(operation_name='save')
  File "C:\Users\mithlesh\Desktop\coolbuy\lib\site-packages\django\db\models\base.py", line 932, in _prepare_related_fields_for_save
    raise ValueError(

Exception Type: ValueError at /Check-Out/
Exception Value: save() prohibited to prevent data loss due to unsaved related object 'order'.

标签: djangodjango-modelsdjango-viewsdjango-templatesdjango-class-based-views

解决方案


正如大多数答案中提到的,您必须将模型分成 2 个。 Order-OrderItem 场景是一对多关系的一个很好的例子。

假设您从 Swiggy(印度食品配送应用程序)订购 Roti、Paneer(印度菜)和可乐。Swiggy 说您的订单 ID 是 #123456。

模型应该是这样的。

class Order(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE,)
    status = models.IntegerField(choices = status_choices, default=1)
    method = models.CharField(max_length=50, blank=False,)
    ... other fields ...

Order 模型告诉用户 Shreyas 下订单,付款方式是 X,当前状态是 this。

class OrderItem(models.Model):
    order = models.ForeignKey(Order, on_delete=models.CASCADE,)
    item = models.ForeignKey(Item, on_delete=models.CASCADE )
    size = models.CharField(max_length=20, blank=False)
    price = models.FloatField(blank=False)
    ... any other fields ...

OrderItem 模型告诉这个项目 - 可乐 - 是订单 ID #123456 的一部分,订购时的价格是 Rs.X。

保存后的数据库应如下所示 -

订单表

ID 用户 方法 地位
123456 shreyas(身份证) 支付 订单已下

订单项表

ID order_id item_id 尺寸 价格
1 123456 烤肉(身份证) n 10.00
2 123456 芝士 (id) n 50.00
3 123456 可乐(身份证) n 25.00

保存您的订单

代码中有一条with transaction.atomic语句,这使您可以一次编写所有模型,并在任何写入语句失败时恢复。参考:Django 交易

class Checkout(View):
    def post (self, request):
        user = request.user
        address = Address.objects.filter(user=request.user)
        cart = request.session.get('cart')
        total_price = request.POST.get('price') 
        items = Item.get_items_by_id(list(cart.keys()))
        prefer = request.POST.get('payment')

        with transaction.atomic:
          order = Order.objects.create(
                user=user,
                date_of_payment=datetime.datetime.now(),
                total_price=total_price,
                address=address
              )

          for item in items:
              prod_order = OrderItem.objects.create(
                order=order
                item=item,
                size=item.size,
                price=price,
            )
   ... return the view ...

推荐阅读