Django添加到购物车和购物车视图错误

问题描述:

当我通过scan_to_cart视图向购物车中添加1个对象并想要添加第二个对象时,出现 NoneType对象不可迭代错误。当我实际上想要查看购物车中的物品时,也会遇到相同的错误。
我找不到解决方案的常见问题...是我处理的python版本,还是有逻辑或代码错误?

I get a 'NoneType' object is not iterable error when I add 1 object to the cart via the scan_to_cart view and want to add a second object. Also I get the same error when I want to view my cart when there are actually objects in it. I could not find a common problem with a solution... Is the python version I work with the issue, or is there a logic or code error?

感谢您提出建议/建议!

Thanks in advance for suggestions/advice!

型号:

from manageinv.models import Child

User = settings.AUTH_USER_MODEL

class CartManager(models.Manager):  
    def new_or_get(self, request):
        cart_id = request.session.get("cart_id", None)
        qs = self.get_queryset().filter(id=cart_id)
        if qs.count() == 1:
            new_obj = False
            cart_obj = qs.first()
            if request.user.is_authenticated() and cart_obj.user is None:
                cart_obj.user = request.user
                cart_obj.save()
        else:
            cart_obj = Cart.objects.new(user=request.user)
            new_obj = True
            request.session['cart_id'] = cart_obj.id
            return cart_obj, new_obj

    def new(self, user=None):
        user_obj = None
        if user is not None:
            if user.is_authenticated():
                user_obj = user
        return self.model.objects.create(user=user_obj)


class Cart(models.Model):
    user        = models.ForeignKey(User, null=True, blank=True)
    products    = models.ManyToManyField(Child, blank=True)
    subtotal    = models.DecimalField(default=0.00, max_digits=100, decimal_places=2)
    total       = models.DecimalField(default=0.00, max_digits=100, decimal_places=2)
    updated     = models.DateTimeField(auto_now=True)
    timestamp   = models.DateTimeField(auto_now_add=True)

    objects = CartManager()

    def __str__(self):
        return str(self.id)


def m2m_changed_cart_receiver(sender, instance, action, *args, **kwargs):
    if action == 'post_add' or action == 'post_remove' or action == 'post_clear':
        products = instance.products.all()
        total = 0 
        for x in products:
            total += x.retail_price
        if instance.subtotal != total:
            instance.subtotal = total
            instance.save()

m2m_changed.connect(m2m_changed_cart_receiver, sender=Cart.products.through)

def pre_save_cart_receiver(sender, instance, *args, **kwargs):
    instance.total = instance.subtotal

pre_save.connect(pre_save_cart_receiver, sender=Cart)   

浏览次数:

def cart_home(request):
cart_obj, new_obj = Cart.objects.new_or_get(request)
products = cart_obj.products.all()
return render(request, 'stockscan/scan_session.html', {"cart":
cart_obj})

def scan_to_cart(request):
    form = forms.ScanSessionForm()
    if request.method == 'POST':
        product = None
        barcode = request.POST.get('barcode_input')
        queryset = Child.objects.filter(product_id_code=barcode)
        if queryset.exists():
            try:
                # the queryset is already filtered by the barcode
                # now we apply an extra filter to check if this user has the product
                product = queryset.get(user=request.user)
            except Child.DoesNotExist:
                # here we are sure this product exists, but this user doesnt have it in the stock.
                messages.error(request, 'I can\'t find any inventory with this barcode')
        else:
            # here we know this product doesnt exist
            messages.error(request, 'I can\'t find any inventory with this barcode')
        if product is not None:
            form = forms.ScanSessionForm(request.POST, instance=product)
            if form.is_valid():
                #####
                #ADD TO CART
                print(product.id)
                product_obj = product.id
                cart_obj, new_obj = Cart.objects.new_or_get(request)
                products = cart_obj.products.all()
                cart_obj.products.add(product_obj)
                #####
                messages.success(request, '%s - %s was successfully added to cart' % (product.product_name, product.sku))   
                return HttpResponseRedirect('/scan/stock/')
    else:
        form = forms.ScanSessionForm()
    return render(request, 'stockscan/scan_to_cart.html', {'form': form})

模板:

{% if cart.products.exists %}
<table class="table">
  <thead>
    <tr>
      <th scope="col">#</th>
      <th scope="col">Product Name</th>
      <th scope="col">Product Price</th>
    </tr>
  </thead>
  <tbody>
    {% for product in cart.products.all %}
    <tr>
      <th scope="row">{{ forloop.counter }}</th>
      <td>{{ product.product_name }} <small><a href="#">Remove</a></small></td>
      <td>{{ product.retail_price }}</td>
    </tr>
    {% endfor %}
    <tr>
      <td colspan="2"></td>
      <td><b>Subtotal</b>  {{ cart.subtotal }}</td>
    </tr>
    <tr>
      <td colspan="2"></td>
      <td><b>Total</b> {{ cart.total }}</td>
    </tr>
  </tbody>
</table>
{% else %}
Cart is empty
<p>
{% endif %}

错误:/ scan / stock中的
TypeError /

Error: TypeError at /scan/stock/

'NoneType' object is not iterable

Request Method:     POST
Request URL:    http://localhost:8000/scan/stock/
Django Version:     1.11
Exception Type:     TypeError
Exception Value:    

'NoneType' object is not iterable

Exception Location:     /Users/sp_env/stockpilot/src/stockscan/views.py in scan_to_cart, line 41
Python Executable:  /Users/sp_env/bin/python

跟踪:

Environment:


Request Method: POST
Request URL: http://localhost:8000/scan/stock/

Django Version: 1.11
Python Version: 2.7.10
Installed Applications:
['django.contrib.admin',
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.staticfiles',
 'mathfilters',
 'bootstrapform',
 'colorfield',
 'gunicorn',
 'crispy_forms',
 'storages',
 'manageinv',
 'categories',
 'stockscan',
 'orderstock',
 'accounts']
Installed Middleware:
['django.middleware.security.SecurityMiddleware',
 'whitenoise.middleware.WhiteNoiseMiddleware',
 '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:

    File "/Users/sp_env/lib/python2.7/site-packages/django/core/handlers/exception.py" in inner
      41.             response = get_response(request)

    File "/Users/sp_env/lib/python2.7/site-packages/django/core/handlers/base.py" in _get_response
      187.                 response = self.process_exception_by_middleware(e, request)

    File "/Users/sp_env/lib/python2.7/site-packages/django/core/handlers/base.py" in _get_response
      185.                 response = wrapped_callback(request, *callback_args, **callback_kwargs)

    File "/Users/sp_env/stockpilot/src/stockscan/views.py" in scan_to_cart
      41.               cart_obj, new_obj = Cart.objects.new_or_get(request)

    Exception Type: TypeError at /scan/stock/
    Exception Value: 'NoneType' object is not iterable


在Cart.new_or_get中,此处:

In Cart.new_or_get, here:

if qs.count() == 1:
   # ...
else:
   # ...
   return cart_obj, new_obj

如果有购物车,则不返回任何内容,因此该函数最终返回 None ,这确实是不可迭代的,因此在尝试取消定位时k您在此处看到的结果:

if a cart exists you do not return anything, so the function ends up returning None, which is indeed not iterable, so when trying to unpack the result in your view here:

 cart_obj, new_obj = Cart.objects.new_or_get(request)

您会遇到此异常。

TL; DR:您应该取消缩排

TL;DR: you should unindent the return statement so it executed for both branches.

这就是说,您的 Cart.new_or_get 方法是错误的-模型代码不应依赖于请求,会话等。所有这些代码都应该存在于您的视图中(如果这是唯一的使用位置)或作为实用工具功能(或在充当模型代理的实用工具类中)。

This being said, your Cart.new_or_get method is plain wrong - model code should not depend on the request, session etc. All this code should live either in your view (if that's the only place it's used) or as an utility function (or in an utility class acting as proxy over the model).