كيف يمكن حفظ بيانات سلة التسوق بعد تسجيل الخروج في Django

السلام عليكم ورحمة الله وبركاته،

اقوم ببناء متجر الكتروني باستخدام Django، استخدمت sessions في عربة التسوق وهي تعمل حاليًا بشكل جيد ، باستثناء مشكلة واحدة عندما يعمل المستخدم logout من الموقع قبل عمل order ثم يقوم بتسجيل الدخول مرة أخرى ، جميع البيانات الموجودة في سلة التسوق تحذف .
كيف يمكن حفظ بيانات سلة التسوق بعد تسجيل الخروج ، بحيث يمكن للمستخدم العثور عليها عند تسجيل الدخول مرة أخرى؟

الملفات التي قمت بانشائها في cart app هي:

  1. cart.py
    from decimal import Decimal
    from django.conf import settings
    from shop.models import Product
    from coupons.models import Coupons

    class Cart(object):
    """docstring for Cart"""
    def __init__(self, request):
    """initalize the cart"""
       self.session = request.session
       cart = self.session.get(settings.CART_SESSION_ID)

       if not cart:
           cart = self.session[settings.CART_SESSION_ID] = {}
       self.cart = cart
       self.coupon_id = self.session.get('coupon_id')


   def add(self,product,quantity=1,update_quantity=False):
       product_id = str(product.id)
       if product_id not in self.cart:
           self.cart[product_id] = {'quantity':0,'price':str(product.price)}

       if update_quantity:
           self.cart[product_id]['quantity'] = quantity

       else:
           self.cart[product_id]['quantity'] += quantity

       self.save()

   def save(self):
       self.session[settings.CART_SESSION_ID] = self.cart
       self.session.modified = True

   def remove(self,product):
       product_id = str(product.id)
       if product_id in self.cart:
          del self.cart[product_id]
          self.save()

   def __iter__(self):
       product_ids = self.cart.keys()
       products = Product.objects.filter(id__in=product_ids)

       for product in products:
          self.cart[str(product.id)]['product'] = product

       for item in self.cart.values():
          item['price'] = Decimal(item['price'])
          item['total_price'] = item['price'] *  item['quantity']
          yield item

   def __len__(self):
       return sum(item['quantity'] for item in self.cart.values())

   def get_total_price(self):
       return sum(Decimal(item['price']) * item['quantity'] for item in self.cart.values())


   def clear(self):
       del self.session[settings.CART_SESSION_ID]
       self.session.modified = True

   @property
   def coupon(self):
       if self.coupon_id:
          return Coupons.objects.get(id=self.coupon_id)
       return None

   def get_discount(self):
       if self.coupon:
          return (self.coupon.discount / Decimal('100')) * self.get_total_price()
       return Decimal('0')

   def get_total_price_after_discount(self):
       return self.get_total_price() - self.get_discount()
  1. views.py
   from django.shortcuts import render,redirect,get_object_or_404
   from django.views.decorators.http import require_POST
   from shop.models import Product
   from .cart import Cart
   from .forms import CartAddProductForm
   from coupons.forms import CouponApplyForm

   # Create your views here.

   @require_POST
   def cart_add(request,product_id):
      cart = Cart(request)
      product = get_object_or_404(Product,id=product_id)
      form = CartAddProductForm(request.POST)
      if form.is_valid():
         cd = form.cleaned_data
         cart.add(
            product=product,
            quantity=cd['quantity'],
            update_quantity=cd['update']
            )
      return redirect('cart_detail')

   def cart_remove(request,product_id):
      cart = Cart(request)
      product = get_object_or_404(Product,id=product_id)
      cart.remove(product)
      return redirect('cart_detail')

   def cart_detail(request):
      cart = Cart(request)
      for item in cart:
          item['update_quantity_form'] = CartAddProductForm(initial={'quantity':item['quantity'],'update':True})

      coupon_apply_form = CouponApplyForm()

      return render(request,'cart_detail.html',context = {'cart':cart,'coupon_apply_form':coupon_apply_form})
  1. form.py
   from django import forms

   PRODUCT_QUANTITY_CHOICES = [(i,str(i)) for i in range(1,21)]

   class CartAddProductForm(forms.Form):
       # Define form fields here
       quantity = forms.TypedChoiceField(choices=PRODUCT_QUANTITY_CHOICES,coerce=int)
       update = forms.BooleanField(required=False,initial=False,widget=forms.HiddenInput)
  1. cart_detail.html
   {% extends "base.html" %}
   {% load static %}
   {% block title_ %}
       Your Shopping Cart
   {% endblock title_ %}
   {% block breadcrumb %}
     <li class="breadcrumb-item active"><a href="{% url 'index'%}">Flowers Website</a></li>

   {% endblock %}
   {% block content %}

    <div class="container">

<div class="row">

  <div class="col-sm-12 col-lg-12 col-md-12">
<table>

    <thead class='t-head'>
        <h1>Your Shopping Cart</h1>
        <tr>
            <th>Image</th>
            <th>Product</th>
            <th>Quantity</th>
            <th>Remove</th>
            <th>Unit Price</th>
            <th>Price</th>
        </tr>
    </thead>
    <tbody>
        {% if cart %}
            {% for item in cart %}
                {% with  product=item.product %}
                    <tr>
                        <td>
                            <a href="{{ product.get_absolute_url }}">
                                <img src='
                                        {% if product.image %}
                                            {{ product.image.url }}
                                        {% else %}
                                            #
                                        {% endif %}'
                                     width="100px">
                            </a>

                        </td>
                        <td>{{product.name}}</td>
                        <td>
                            <form method="post" action="{% url 'cart_add' product.id %}">
                                {% csrf_token %}
                                {{item.update_quantity_form.quantity}}
                                {{item.update_quantity_form.update}}
                                <input type="submit" value="Update">
                            </form>
                        </td>
                        <td>
                            <a href="{% url 'cart_remove' product.id%}">
                                Remove
                            </a>
                        </td>
                        <td>
                            {{item.price}}
                        </td>
                        <td>
                            {{item.total_price}}
                        </td>
                    </tr>

                {% endwith %}
            {% endfor %}
        {% else %}
            <tr>
                <td colspan="4" style="width:100%;text-align:center;">there is no product !</td>
            </tr>
        {% endif %}

            {% if cart.coupon %}
                <tr class="gray">
                    <td>Subtotal</td>
                    <td colspan="4"></td>
                    <td class="num"> {{cart.get_total_price}}</td>
                </tr>
                <tr class="gray2">
                    {% block trans   %}
                        {% with code=cart.coupon.code discount=cart.coupon.discount%}
                            <td colspan="2">"{{code}}" coupon ({{discount}})% off</td>
                        {% endwith %}
                    {% endblock trans %}
                    <td colspan="3"></td>
                    <td class="num neg"> - ${{cart.get_discount|floatformat:"2"}}</td>
                </tr>
            {% endif %}
            <tr class="total">
                <td>Total</td>
                <td colspan="4"></td>
                <td class="num">${{cart.get_total_price_after_discount|floatformat:"2"}}.    </td>
            </tr>
    </tbody>
</table>
<div class="divo">
    <p>
        Apply a coupon
    </p>
    <form action="{% url 'coupon_apply' %}" method="post">
        {{coupon_apply_form}}
        {% csrf_token %}
        <input class="btn apply-button" type="submit" value="apply" >

    </form>
    <p class="text-right">
    <a href="{% url 'index' %}">Continu shopping</a>
    <a href="{% url 'orders:order_create' %}">Checkout</a>
    </p>
  </div>
  </div>
  </div>
 </div>
 {% endblock content %}
  1. url.py
    from django.urls import path
    from . import views


    urlpatterns=[
       path('cart_detail/',views.cart_detail,name='cart_detail'),
       path('add/<product_id>/',views.cart_add,name='cart_add'),
       path('remove/<product_id>/',views.cart_remove,name='cart_remove'),
    ]
2 Likes

مرحبا وفاء :wave: جميل جدا ما قمت به لحد الآن :heart_eyes: عمل رائع

فيما يخص مشكلتك فهي تظهر لك لأنك تستعملين ال sessions لتسجيل الكارت و المحافظة عليها. و بالتالي في حالة حذف ال session الحالية بعمل logout مثلا يذهب معها كل شيئ.

لحل هاته المشكلة يمكنك تسجيل ال cart في قاعدة البيانات بدلا من ال sessions و ذلك بعمل Cart model و ربطه بعلاقة OneToOne أي واحد لواحد مع جدول المستخدم أو User :ok_hand:

أتمنى نكون جاوبتك على سؤالك :grin:

1 Like

@hichem2h، شكرا لك
قمت بالتالي:

from django.db import models
from django.contrib.auth.models import User
from datetime import datetime
from shop.models import Product

class MyCart(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    created_at = models.DateTimeField(default=datetime.now)
    updated = models.DateTimeField(auto_now =True)
    timestamp = models.DateTimeField(auto_now_add  = True)

class CartItem(models.Model):
    cart = models.ForeignKey('MyCart', on_delete=models.CASCADE)
    product = models.ForeignKey(Product, blank= True, on_delete=models.CASCADE)
    quantity = models.IntegerField(default=1)
    price = models.FloatField(blank=True)

    class Meta:
        verbose_name = "CartItem"
        verbose_name_plural = "CartItems"

    def __str__(self):
        return '{}'.format(self.id)

    def get_cost(self):
        return self.price * self.quantity 

الان كيف احفظ القيم في الجدول ؟
القيم يتم اضافتها للعربة باستخدام القيم التي جاءت من Cart.py

@require_POST
def cart_add(request,product_id):
cart = Cart(request)
product = get_object_or_404(Product,id=product_id)
form = CartAddProductForm(request.POST)
if form.is_valid():
cd = form.cleaned_data
cart.add(
product=product,
quantity=cd[‘quantity’],
update_quantity=cd[‘update’]
)

الان كيف اضيفها لmodel التي انشاتها؟

3 Likes

مرحبا مجددا وفاء @wafa-b

أولا قمت ببعض التعديلات على منشوراتك ليكون الكود مقروءا أكثر لكل من يريد أن يستفيد من هاته المناقشة :ok_hand:

الآن نعود لسؤالك كودك هكذا يبدو جيد أو ربما لم أفهم جيدا ما الذي تريدين القيام به؟ ممكن تفهميني أكثر

1 Like