Django Error: объект 'dict' не имеет атрибута 'availability'
У меня есть представление корзины, где я пытаюсь проверить, есть ли у товаров, добавленных в корзину, хотя бы один элемент в списке, у которого product.availability
установлен в False и работать соответственно в Template, проблема заключается в доступе к доступности продукта в списке объектов корзины, Итак, как мне проверить доступность продуктов, которые люди добавили в корзину?
P.S Я сократил код для утилиты, я добавлю больше, если это необходимо для понимания
Модель
class Product(models.Model):
availability = models.BooleanField()
Utils
def cookieCart(request):
try:
cart = json.loads(request.COOKIES['cart'])
except:
cart = {}
items = []
for i in cart:
try:
product = Product.objects.get(id=i)
item = {
'product':{
'id':product.id,
'name':product.name,
'final_price':product.final_price,
'image_URL':product.image_URL,
'availability':product.availability,
},
}
items.append(item)
except:
pass
return {"items": items}
def cartData(request):
if request.user.is_authenticated:
customer = request.user.customer
order, created = Order.objects.get_or_create(customer=customer, complete=False)
items = order.orderitem_set.all()
else:
cookieData = cookieCart(request)
items = cookieData['items']
return {'items':items}
Виды
def cart(request):
data = cartData(request)
#products added to cart
items = data['items']
#Checking if even one product added to cart has availability set to False
available = all(x.availability for x in items)
context = {'items': items, 'available': available}
Шаблон
<p>{{items.product.name}}</p>
{% if available %}
<a href="#">Checkout</a>
{% else %}
<p>Out of stock</p>
{% endif %}
Traceback
Traceback (most recent call last):
File "D:\test\lib\site-packages\django\core\handlers\exception.py", line 47, in inner
response = get_response(request)
File "D:\test\lib\site-packages\django\core\handlers\base.py", line 181, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "D:\test\shop\views.py", line 101, in cart
available = all(x.availability for x in items)
File "D:\test\shop\views.py", line 101, in <genexpr>
available = all(x.availability for x in items)
Exception Type: AttributeError at /shop/cart
Exception Value: 'dict' object has no attribute 'availability'
Все очень просто, в функции cookieCart вы добавляете к списку товаров словарь, а не объект Product.
Изменить на:
def cookieCart(request):
try:
cart = json.loads(request.COOKIES['cart'])
except:
cart = {}
items = []
for i in cart:
try:
product = Product.objects.get(id=i)
items.append(product)
except:
pass
return {"items": items}
Вместо того, чтобы создавать ad-hoc dict, который действительно имеет необходимый availability
атрибут, вы должны просто вернуть QuerySet
из Product
объектов после фильтрации товаров по ID:
def cookieCart(request):
try:
cart = json.loads(request.COOKIES['cart'])
except:
cart = {}
return {"items": Product.objects.filter(id__in=cart)}
Эта часть создает проблему
def cookieCart(request):
try:
cart = json.loads(request.COOKIES['cart'])
except:
cart = {}
items = []
for i in cart:
try:
product = Product.objects.get(id=i)
item = {
'product':{
'id':product.id,
'name':product.name,
'final_price':product.final_price,
'image_URL':product.image_URL,
'availability':product.availability,
},
}
items.append(item)
except:
pass
return {"items": items} # here your items is like this {"items": [{'product':{'id':product.id,'name':product.name,'final_price':product.final_price,'image_URL':product.image_URL,'availability':product.availability}}]}
Поскольку ошибка предполагает, что вы выбрали элемент из COOKIES
Теперь, поскольку вы выполняете цикл all(x.availability for x in items)
x будет выглядеть как {price: {...}}
, который является объектом dict, поэтому он говорит, что объект dict не имеет доступности атрибутов
Для решения этой проблемы используйте SimpleNameSpace
следующим образом
from types import SimpleNamespace
def cookieCart(request):
try:
cart = json.loads(request.COOKIES['cart'])
except:
cart = {}
items = []
for i in cart:
try:
product = Product.objects.get(id=i)
item = SimpleNamespace(**{
'id':product.id,
'name':product.name,
'final_price':product.final_price,
'image_URL':product.image_URL,
'availability':product.availability,
})
items.append(item)
except:
pass
return {"items": items}
Для оптимизированного способа вы можете проверить решение @blhsing
Ошибка говорит о том, что вы пытаетесь получить доступ к элементу dict как к атрибуту (x.y
вместо x['y']
).
Это должно быть:
available = all(x['availability'] for x in items)
При этом, как упоминал @blhsing, лучше делать запросы в одном наборе запросов
products = Product.objects.filter(pk__in=cart)
items = [
{
'product': p,
'quantity': cart[p.pk],
'get_total': p.final_price * cart[p.pk],
}
for p in products
}
available = all(x['product'].availability for x in items)
# or
# available = all(p.availability for p in products)
# or
# available = not products.filter(availability=False).exists()
return {'items': items, 'available': available}
Кроме того, вы должны убедиться, что в обоих случаях вашего if/else
в cartData()
, items
установлена одна и та же структура данных. В данном случае это не так, поскольку в if
, items
является QuerySet
, тогда как в else
, items
является списком словарей.