注销后如何保存购物车数据的会话,以便用户在 Django 中再次登录时可以找到它们?

Posted

技术标签:

【中文标题】注销后如何保存购物车数据的会话,以便用户在 Django 中再次登录时可以找到它们?【英文标题】:How can save session of shopping cart data after logout, so the user can find them when login again in Django? 【发布时间】:2020-09-14 19:48:30 【问题描述】:

我正在使用 Django 开发电子商务网站,我正在开发使用会话实现的购物车,目前工作正常,除了经过身份验证的用户从网站注销并再次登录时出现问题,所有数据都在购物车丢失。 退出后如何保存session的购物车数据,方便用户再次登录时找到?

我的购物车应用文件是:

1) 购物车.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()

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

3) 表单.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)

4) 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 %'
                                     >
                            </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 %

5) 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'),
    ]

@John Meinken,我也遇到了同样的问题:

How to save and restore session data across logout/relogin in Django?

您的解决方案可能会解决我的问题,但是,您能否为我解释一下,我应该在哪里创建此表?我应该在哪里使用这个功能?例如我的项目包含许多应用程序(帐户、商店、购物车、订单)

提前致谢。

【问题讨论】:

【参考方案1】:

我遇到了同样的问题并通过以下程序解决了它: 您可以保留当前购物车的深层副本,并在注销后将其设置为会话,如下所示:

import copy

from django.contrib.auth import logout


def logout_user(request):
    cart = copy.deepcopy(Cart(request).cart)
    logout(request)
    session = request.session
    session[settings.CART_SESSION_ID] = cart
    session.modified = True
    return redirect('login')

【讨论】:

以上是关于注销后如何保存购物车数据的会话,以便用户在 Django 中再次登录时可以找到它们?的主要内容,如果未能解决你的问题,请参考以下文章

Laravel 5 - 用户在会话生命周期后不注销

注销时如何使用户会话无效?

Laravel 5.0 扩展了“注销”功能

如何使用php制作涉及会话cookie的注销页面?

在 iPhone 中保存 Spotify 登录的用户会话

如何记录 tomcat 会话失效或用户注销