how to fetch all the item of a cart by a user in single field of model name orders

Solution for how to fetch all the item of a cart by a user in single field of model name orders
is Given Below:

Right now I’m able to save the data but all the items are saved separately instead of being in one field so how I can achieve that and I using cart as session to save it id and size as a key and value

my models.py where I want to save order

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 

my views.py to save the data

and my html where my cart is showing

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

As you can see I am using filter to show user total price of his cart so what i want is to save the item id of all the items in items field and size in size field acc to their item and in place of price total price got saved.
But right now it’s saving separate field for item, i don’t want that

how its look right now

my html form for checkout and save orders

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

item model

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

and cart view where all the item goes after selected by a user

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

enter image description here

It does save the item in it but I want to fetch all the items of the car in that field

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

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

adding the traceback

Environment:

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

Hello I have experience with e-commerce,
as much i have understand that you want to save all the details of item like size , price , name ,mail description in one single field .Is that right ?

if yes , then I think directly it’s not possible you can try one thing —

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.

But it will be more efficient for storing data only , if you want to retrieve the data efficiently then go for separate models as you have created.

hope it will have, I have applied same type of concept to store customer complain and payment details of users and I like your code , you are following good practice!

adding the answer from @allexiusw

The best practice for this is, you need to create 2 models with many to many relationship for 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)
    ...

To save it to that 2 models, you can do something like this:

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()
        ....

You need to split the model Order in two models:

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)

In that way you will have 1-Order and Many-Productos per Order.

As mentioned in most of the answers, you have to split the models into 2. The Order-OrderItem scenario is a good example for One-to-Many relationship.

Consider you ordering Roti, Paneer (Indian dishes) and Coke from Swiggy (Indian food delivery app). Swiggy says that your order id is #123456.

The models should look like this.

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 ...

The Order model tells that the Order is placed by the user Shreyas, method of payments is X and current status is 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 model tells that the this item – Coke – is part of Order ID #123456 and the price at the time of ordering is Rs.X.

Your database after saving should look like this –

Order table

idusermethodstatus
123456shreyas (id)paymentorder_placed

OrderItem table

idorder_iditem_idsizeprice
1123456roti (id)n10.00
2123456paneer (id)n50.00
3123456coke (id)n25.00

Saving your order

There is a with transaction.atomic statement in the code, this allows you to write all the models in one go, and revert if any of the write statements fail. Ref: Django transactions

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 ...