清除 django 应用程序中使用 clery 任务保存在会话中的购物车

问题描述 投票:0回答:1

你好,我尝试使用 Django 构建一个电子商务应用程序,我有一个购物车类,可以与会话一起使用,这是我的购物车类:

from django.conf import settings
from shop.models import Product, ProductColor
from django.shortcuts import get_object_or_404
from django.utils import timezone

class Cart:
    def __init__(self, request_or_session_data):
        if hasattr(request_or_session_data, 'session'):  # Check if it's a request
            self.session = request_or_session_data.session
        else:
            # If it's session data, use it directly
            self.session = request_or_session_data
        cart = self.session.get(settings.CART_SESSION_ID)
        if not cart:
            cart = self.session[settings.CART_SESSION_ID] = {}
        self.cart = cart
        self.total_discount = None
        self.discount_code = None
        self.have_discount_code = self.session.get("have_discount_code", False)
        self.discount_code_amount = self.session.get("discount_code_amount", 0)
        self.last_updated = self.session.get("last_updated")
        if hasattr(request_or_session_data, 'user') and request_or_session_data.user.is_authenticated:
            self.user = request_or_session_data.user



    def add(self, product, color_id, quantity=1, override_quantity=False):
        product_id = str(product.id)
        color = get_object_or_404(ProductColor, id=color_id)
        cart_key = f"{product_id}_{color_id}"

        if cart_key not in self.cart:
            self.cart[cart_key] = {
                'color_id': str(color.id),
                'quantity': 0,
                'price': str(product.price),
                'discount': str(product.discount),
                'discount_price': str(product.get_discounted_price()),
            }

        if override_quantity:
            self.cart[cart_key]['quantity'] = quantity
        else:
            self.cart[cart_key]['quantity'] += quantity

        self.total_discount = self.get_total_discount()
        self.save()

    def mark_session_modified(self):
        # Mark session as modified if `self.session` is a Django session object
        if hasattr(self.session, 'modified'):
            self.session.modified = True

    def save(self):
        # mark the session as "modified" to make sure it gets saved
        self.last_updated = timezone.now()
        self.session[settings.CART_SESSION_ID] = self.cart
        self.session['have_discount_code'] = self.have_discount_code
        self.session['discount_code_amount'] = self.discount_code_amount
        self.session['last_updated'] = self.last_updated.isoformat()
        if hasattr(self, 'user') and self.user:
            self.session["user_id"] = self.user.id
        self.mark_session_modified()

    def remove(self, product, color_id=None):
        product_id = str(product.id)
        if color_id:
            cart_key = f"{product_id}_{color_id}"
            if cart_key in self.cart:
                del self.cart[cart_key]
        else:
            # If no color_id is provided, remove all items related to the product_id
            keys_to_remove = [key for key in self.cart if key.startswith(product_id)]
            for key in keys_to_remove:
                del self.cart[key]

        if len(self.cart) == 0:
            self.clear()  # Call the clear method to remove discount codes and other data

        else:
            self.total_discount = self.get_total_discount()  # Update total discount
            self.save()

    def __iter__(self):
        cart = self.cart.copy()
        product_ids = {key.split('_')[0] for key in cart.keys()}  # Extract product IDs
        products = Product.objects.filter(id__in=product_ids)

        for product in products:
            for key in cart.keys():
                if key.startswith(str(product.id)):
                    item = cart[key]
                    item["product"] = product

                    # Extract color ID from the key
                    color_id = key.split('_')[1] if '_' in key else None

                    # Get the corresponding ProductColor instance
                    if color_id:
                        try:
                            product_color = ProductColor.objects.get(id=color_id, product=product)
                            item["color_name"] = product_color.color  # Use the color from ColorChoices
                        except ProductColor.DoesNotExist:
                            item["color_name"] = "Unknown Color"
                    else:
                        item["color_name"] = "No Color"

                    item["color_id"] = str(color_id)
                    item["product_id"] = str(product.id)
                    item["price"] = int(item["price"])
                    item["discount_price"] = int(item["discount_price"])
                    if item["discount"] == "0":
                        item["total_price"] = item["price"] * item["quantity"]
                    else:
                        item["total_price"] = item["discount_price"] * item["quantity"]

                    yield item

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

    def get_total_price(self):
        total_price = 0
        for item in self:
            total_price += item["total_price"]
        if self.have_discount_code:
            discount_factor = self.discount_code_amount / 100
            total_price = int(total_price * (1 - discount_factor))
        return total_price

    def add_coupon(self, amount, code):
        self.discount_code_amount = amount
        self.have_discount_code = True
        self.discount_code = code
        self.save()

    def get_total_discount(self):
        total_discount = 0
        for item in self.cart.values():
            if item["discount"] != "0":
                discount = int(item["price"]) - int(item["discount_price"])
                total_discount += discount * item["quantity"]
        return total_discount

    @property
    def total_get_price_of_discount(self):
        total_price = 0
        for item in self:
            total_price += item["total_price"]
        price = self.get_total_price()

        return total_price - price

    def clear(self):
        # remove cart from session
        del self.session[settings.CART_SESSION_ID]
        self.have_discount_code = False
        self.discount_code = None
        self.discount_code_amount = 0
        self.total_discount = None
        self.save()

每次用户将产品添加到购物车时,我都会减少产品数量,并且我有一个任务是检查他们的购物车是否闲置超过 30 分钟,首先向用户发送短信并提醒他们添加购物车,然后再进行操作1小时清除购物车并将数量添加回产品问题是在任务中我尝试循环到所有会话并使用 session_data["sms_sent"] = True 修改该会话之后当超过 1 小时时,也会再次发送短信,它将数量添加回数据库,但无法从会话中清除购物车

这是我正在使用的任务:

@shared_task
def clear_abandoned_carts():
    expired_time = timezone.now() - CART_EXPIRATION_TIME
    warning_time = timezone.now() - SEND_WARNING_TIME

    for session in Session.objects.filter(expire_date__gte=timezone.now()):
        data = session.get_decoded()
        last_updated_str = data.get("last_updated")
        cart = data.get(settings.CART_SESSION_ID)
        print("sms_sent flag before:", data.get("sms_sent"))  # Safe access

        if cart and last_updated_str:
            last_updated = timezone.datetime.fromisoformat(last_updated_str)

            if last_updated < expired_time:
                # Clear cart if expired
                for key, item in cart.items():
                    color_id = item["color_id"]
                    quantity = item["quantity"]
                    try:
                        remove_from_cart(color_id, int(quantity))
                    except ProductColor.DoesNotExist:
                        pass  # Handle as needed

                # Clear session data
                session_data = session.get_decoded()
                session_data.pop(settings.CART_SESSION_ID, None)
                session_data.pop("last_updated", None)
                session_data.pop("have_discount_code", None)
                session_data.pop("discount_code_amount", None)
                session_data.pop("sms_sent", None)
                session_data["modified"] = True

                session.save()
                cart_instance = Cart(data)
                cart_instance.clear()

            elif last_updated < warning_time:
                # Check if the SMS warning was already sent
                if not data.get("sms_sent"):  # Proceed only if SMS hasn't been sent
                    user_id = data.get("user_id")
                    if user_id:
                        try:
                            user = CustomUser.objects.get(id=user_id)
                            if user.phone_number:
                                phone_number = user.phone_number
                                send_cart_warning(int(phone_number))  # Send SMS

                                # Mark SMS as sent in session data
                                session_data = session.get_decoded()
                                session_data["sms_sent"] = True  # Safely update session
                                session_data["modified"] = True
                                session.modified = True
                                session.save()

                                print("sms_sent flag after:", session_data.get("sms_sent"))  # Safe access

                        except CustomUser.DoesNotExist:
                            pass

在控制台中,当其发送消息时,此 print("sms_sent flag after:", session_data.get("sms_sent")) 给我 True 但当它再次运行时,此 print("sms_sent flag before:", data.get( “sms_sent”))给我没有你们能帮我解决这个问题吗

python django celery
1个回答
0
投票

在 Celery 任务中更新会话数据时,请确保会话被标记为已修改并正确保存。例如:

@shared_task
def clear_abandoned_carts():
    expired_time = timezone.now() - CART_EXPIRATION_TIME
    warning_time = timezone.now() - SEND_WARNING_TIME

    for session in Session.objects.filter(expire_date__gte=timezone.now()):
        data = session.get_decoded()
        last_updated_str = data.get("last_updated")
        cart = data.get(settings.CART_SESSION_ID)
        print("sms_sent flag before:", data.get("sms_sent"))  # Safe access

        if cart and last_updated_str:
            last_updated = timezone.datetime.fromisoformat(last_updated_str)

            if last_updated < expired_time:
                # Clear cart if expired
                for key, item in cart.items():
                    color_id = item["color_id"]
                    quantity = item["quantity"]
                    try:
                        remove_from_cart(color_id, int(quantity))
                    except ProductColor.DoesNotExist:
                        pass  # Handle as needed

                # Clear session data
                session_data = session.get_decoded()
                session_data.pop(settings.CART_SESSION_ID, None)
                session_data.pop("last_updated", None)
                session_data.pop("have_discount_code", None)
                session_data.pop("discount_code_amount", None)
                session_data.pop("sms_sent", None)

                # Mark session as modified and save
                session_data["modified"] = True
                session.session_data = Session.objects.encode(session_data)
                session.save()

            elif last_updated < warning_time:
                # Check if the SMS warning was already sent
                if not data.get("sms_sent"):
                    user_id = data.get("user_id")
                    if user_id:
                        try:
                            user = CustomUser.objects.get(id=user_id)
                            if user.phone_number:
                                phone_number = user.phone_number
                                send_cart_warning(int(phone_number))  # Send SMS

                                # Mark SMS as sent in session data
                                session_data = session.get_decoded()
                                session_data["sms_sent"] = True
                                session_data["modified"] = True
                                session.session_data = Session.objects.encode(session_data)
                                session.save()

                        except CustomUser.DoesNotExist:
                            pass

确保从会话中删除购物车数据,然后保存会话。

def clear(self):
    # Remove cart-related data from session
    keys_to_remove = [
        settings.CART_SESSION_ID,
        'have_discount_code',
        'discount_code_amount',
        'last_updated',
        'sms_sent'
    ]
    for key in keys_to_remove:
        self.session.pop(key, None)

    # Mark session as modified and save
    self.mark_session_modified()
© www.soinside.com 2019 - 2024. All rights reserved.