как получить весь товар из корзины пользователем в одном поле заказов с названием модели

#django #django-models #django-views #django-templates #django-class-based-views

Вопрос:

Прямо сейчас я могу сохранить данные, но все товары сохраняются отдельно, а не в одном поле, так как я могу этого добиться, и я использую корзину в качестве сеанса, чтобы сохранить ее идентификатор и размер в качестве ключа и значения

мои модели.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>
 

Как вы можете видеть, я использую фильтр, чтобы показать общую цену пользователя в его корзине, поэтому я хочу сохранить идентификатор товара всех товаров в поле «Товары» и размер в поле «Размер» в соответствии с их товаром, а вместо цены была сохранена общая цена.
Но прямо сейчас он сохраняет отдельное поле для товара, я этого не хочу

как это выглядит прямо сейчас

моя 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:UsersmithleshDesktopcoolbuylibsite-packagesdjangocorehandlersexception.py", line 47, in inner
    response = get_response(request)
  File "C:UsersmithleshDesktopcoolbuylibsite-packagesdjangocorehandlersbase.py", line 181, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "C:UsersmithleshDesktopcoolbuylibsite-packagesdjangoviewsgenericbase.py", line 70, in view
    return self.dispatch(request, *args, **kwargs)
  File "C:UsersmithleshDesktopcoolbuylibsite-packagesdjangoviewsgenericbase.py", line 98, in dispatch
    return handler(request, *args, **kwargs)
  File "C:UsersmithleshDesktopcoolbuycoolbuyordersviews.py", line 61, in post
    item_order = OrderItem.objects.create(
  File "C:UsersmithleshDesktopcoolbuylibsite-packagesdjangodbmodelsmanager.py", line 85, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "C:UsersmithleshDesktopcoolbuylibsite-packagesdjangodbmodelsquery.py", line 453, in create
    obj.save(force_insert=True, using=self.db)
  File "C:UsersmithleshDesktopcoolbuylibsite-packagesdjangodbmodelsbase.py", line 682, in save
    self._prepare_related_fields_for_save(operation_name='save')
  File "C:UsersmithleshDesktopcoolbuylibsite-packagesdjangodbmodelsbase.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'.
 

Комментарии:

1. Вы хотите сказать, что Вам не нужны заказы в другой области ?

2. @Программист да, я имею в виду, что если человек создает заказ, все элементы этого заказа помещаются в одно поле вместо создания отдельного поля для каждого отдельного элемента в этом заказе

3. прежде всего, было бы лучше, если бы вы могли разделить модель. Один для заказа и один для элементов заказа. таким образом, у вас будет только одна строка для заказа.

4. вы предлагаете мне создать два разных названия модели заказа и элемента заказа

5. Не могли бы вы также опубликовать код для модели товара?

Ответ №1:

Как упоминалось в большинстве ответов, вы должны разделить модели на 2. Сценарий Order-OrderItem является хорошим примером отношений «Один ко многим».

Подумайте о том, чтобы заказать Роти, Панир (индийские блюда) и кока-колу в Swiggy (приложение для доставки индийской еды). Свигги говорит, что ваш идентификатор заказа #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 ...
 

Модель заказа указывает, что Заказ размещен пользователем Shreyas, способ оплаты-X, а текущий статус-это.

 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 сообщает, что этот товар — Кока — кола-является частью идентификатора заказа № 123456, а цена на момент заказа составляет Rs.X.

Ваша база данных после сохранения должна выглядеть следующим образом —

Таблица заказов

ID пользователь метод Статус
123456 шрейас (удостоверение личности) оплата упорядоченные_место

Таблица элементов заказа

ID идентификатор заказа item_id размер Цена
1 123456 роти (удостоверение личности) n 10.00
2 123456 панир (удостоверение личности) 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 ...
 

Комментарии:

1. сохранить() запрещено для предотвращения потери данных из-за несохраненного связанного объекта «заказ». это приводит к ошибке

2. Ваша обновленная модель не соответствует моему определению. Мое определение трактует отношения как «Один ко многим», ваше-как «Многие ко многим», которые будут иметь значение. Пожалуйста, обновите в соответствии с моим определением и попробуйте.

3. я уже изменил это на ключ foriegn и обновил свою модель здесь, теперь посмотрите

4. отступ прямо в модели, пожалуйста, не обращайте внимания

Ответ №2:

Здравствуйте, у меня есть опыт работы с электронной коммерцией , насколько я понимаю , вы хотите сохранить все детали товара ,такие как размер, цена, название, описание почты в одном поле .Это правда ?

если да , то я думаю, что напрямую это невозможно, вы можете попробовать одну вещь —

 1.You can take all the desired data and create a dictionary or list out of them
2. Create a single textfield with more maxlength and a FK with user or customer model  and then you can save the list or dict as text in that one field in db, and then can retrieve the all data as well as you can get by index also.
 

Но это будет более эффективно только для хранения данных , если вы хотите эффективно извлекать данные, а затем переходить к отдельным моделям, которые вы создали.

надеюсь, что так и будет , я применил ту же концепцию для хранения жалоб клиентов и платежных реквизитов пользователей, и мне нравится ваш код, вы следуете хорошей практике!

Комментарии:

1. я тоже так думал, но я думаю, что это не очень хороший способ для порядка просмотра, поэтому я ищу лучший и чистый метод

Ответ №3:

добавление ответа от @allexiusw

Лучшая практика для этого заключается в том, что вам нужно создать 2 модели с отношениями «многие ко многим» для product_order:

 class Order(models.Model):
    order_group_id = models.AutoField(primary_key=True)
    user = models.ForeignKey(User, on_delete=models.CASCADE, null=True)
    product_order = models.ManyToManyField(OrderItem, related_name='order', null=True)
    total_price = models.DecimalField(default=0, decimal_places=2, max_digits=10, null=True)
    datetime_of_payment = models.DateTimeField(default=timezone.now, null=True)
    ...
   

class OrderItem(models.Model):
    item = models.ForeignKey(Item, on_delete=models.CASCADE, null=True)
    size = models.CharField(max_length=20, blank=False, null=True)
    price = models.FloatField(blank=False, null=True)
    ...
 

Чтобы сохранить его в этих 2 моделях, вы можете сделать что-то вроде этого:

 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')


        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(
                item=item,
                size=item.size,
                price=price,
            )
            order.product_order.add(prod_order)
        order.save()
        ....
 

Комментарии:

1. вместо создания заказа он выдает ошибку НЕ НУЛЕВОЕ ограничение не удалось: orders_orderitem.order_id

2. Как ваш ответ виттена

3. я редактирую ответ, не забудьте добавить null=True во все поля, особенно если вы добавляете новое поле. и не забудьте до makemigrations и migrate после внести изменения в модель… @Шреяш

4. Я вижу ваше последнее обновление, в вашей новой модели все не совсем так, как я вам рассказывал об отношениях в модели, а также о представлениях. посмотри еще раз! вам следует удалить order поле из ProductOrder и добавить product_order = models.ManyToManyField(OrderItem, related_name='order', null=True) в модель OrderItem

5. он выдает ошибку «Нетип», объект не имеет атрибута «добавить», и одна вещь, которую я не могу использовать, много ко многим полям, которые я должен использовать для ключа

Ответ №4:

Вам нужно разделить модель Order на две модели:

 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,)
    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)
    created_at = models.DateField(auto_now=True, editable=False)

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


class ProductOrder(models.Model):
    order = models.ForeingKey(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)
 

Таким образом, у вас будет 1 заказ и много продуктов на заказ.

Комментарии:

1. итак, как я могу сохранить товар в корзине в этой модели заказа товара и все остальное в моей модели заказа