如何在Django模板上仅显示集合中第一次出现的项?
我正在学习Django,所以这可能不是我想要的最好的方法 我在这里尝试的是显示购物车中多次选择的项目,仅显示一次(以及在旁边选择的次数) 我一整天都在试图找到一种方法,但我能做的最接近的事情是,在视图中,生成两个集合:单个_项和多个_项 我在显示一个只被选中一次的项目时没有问题,但是当涉及到多次被选中的项目时,我只能显示n次,并且旁边出现的项目的数量,如图所示 尽管我更愿意使用python代码(在views.py中)进行所有计算,但使用Django模板语言的解决方案对我来说也行如何在Django模板上仅显示集合中第一次出现的项?,django,django-templates,django-views,Django,Django Templates,Django Views,我正在学习Django,所以这可能不是我想要的最好的方法 我在这里尝试的是显示购物车中多次选择的项目,仅显示一次(以及在旁边选择的次数) 我一整天都在试图找到一种方法,但我能做的最接近的事情是,在视图中,生成两个集合:单个_项和多个_项 我在显示一个只被选中一次的项目时没有问题,但是当涉及到多次被选中的项目时,我只能显示n次,并且旁边出现的项目的数量,如图所示 尽管我更愿意使用python代码(在views.py中)进行所有计算,但使用Django模板语言的解决方案对我来说也行 请考虑在URL
请考虑在URL中传递项目ID,以便使删除链接工作。
这里是views.py from django.shortcuts import render, redirect
from .models import Cart, Item, CartItem
from django.db.models import Sum
# Create your views here.
def home(request):
items = Item.objects.all()
carts = Cart.objects.all()
length = len(Cart.objects.all())
cart = carts[length - 1]
cart_items = cart.items.all()
total = cart_items.aggregate(Sum('price'))['price__sum']
if total is None:
total = 0
number_of_items = cart_items.count()
deletable_items = CartItem.objects.all()
occurrences = None
single_items = set()
multiple_items = set()
for deletable_item in deletable_items:
occurrences = deletable_items.filter(item__name=deletable_item.item).count()
if occurrences > 1:
deletable_item.occurrences = occurrences
multiple_items.add(deletable_item)
elif occurrences == 1:
deletable_item.occurrences = occurrences
single_items.add(deletable_item)
return render(request, 'cart/home.html', {'cart': cart,
'items': items,
'cart_items': cart_items,
'total': total,
'number_of_items': number_of_items,
'deletable_items': deletable_items,
'multiple_items': multiple_items,
'single_items': single_items,
'occurrences': occurrences
})
def add_to_cart(request, item_id):
item_id = Item.objects.get(id=item_id)
carts = Cart.objects.all()
length = len(Cart.objects.all())
cart = carts[length - 1]
cart_item = CartItem.objects.create(item=item_id, cart=cart)
return redirect(home)
def remove_from_cart(request, item_id):
item_to_remove = CartItem.objects.get(id=item_id)
item_to_remove.delete(
)
return redirect(home)
还有我的模板
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Home page</title>
</head>
<body>
<h1>My Restaurant</h1>
<div><h1>Menu</h1></div>
{% for item in items %}
<ul>{{ item }} £{{ item.price}} <a href="{% url 'add_to_cart' item.id %}">Add</a></ul>
{% endfor %}
<div><h1>Order</h1></div>
{{ cart }}
<br>
<h2>items selected: {{ number_of_items }}</h2>
{% for single_item in single_items %}
<ul>{{ single_item }} x {{ single_item.occurrences }} <a href="{% url 'remove_from_cart' single_item.id %}">Remove</a></ul>
{% endfor %}
{% for multiple_item in multiple_items %}
<ul>{{ multiple_item }} x {{ multiple_item.occurrences }} <a href="{% url 'remove_from_cart' multiple_item.id %}">Remove</a></ul>
{% endfor %}
<h2>Total</h2>
{{ total|floatformat:2 }}
</body>
</html>
编辑
目前,我正在使用Willem Van Onsem建议的view.py
from django.shortcuts import render, redirect
from .models import Cart, Item, CartItem
from django.db.models import Sum, Count, F
# Create your views here.
def home(request):
cart = Cart.objects.filter(user=request.user).last()
items = Item.objects.all()
cart_items = Item.objects.filter(
cartitem__cart=cart
).annotate(
ncount=Count('cartitem')
)
total = cart_items.aggregate(total=Sum(F('price') * F(float('ncount'))))['total']
context = {
'items': items,
'total': total,
'cart_items': cart_items
}
return render(request, 'cart/home.html', context)
def add_to_cart(request, item_id):
item_id = Item.objects.get(id=item_id)
carts = Cart.objects.all()
length = len(Cart.objects.all())
cart = carts[length - 1]
cart_item = CartItem.objects.create(item=item_id, cart=cart)
return redirect(home)
def remove_from_cart(request, item_id):
item_to_remove = CartItem.objects.get(id=item_id)
item_to_remove.delete()
return redirect(home)
我认为最好在这里开发两个查询集,如:
from django.db.models import Count, F, Sum
def home(request):
cart = Cart.objects.filter(user=request.user).last()
items = Item.objects.all()
cart_items = Item.objects.filter(
cartitem__cart=cart
).annotate(
ncount=Count('cartitem', output_field=DecimalField(max_digits=5, decimal_places=0))
)
total = cart_items.aggregate(total=Sum(F('price') * F('ncount')))['total']
context = {
'items': items,
'total': total,
'cart_items': cart_items
}
return return render(request, 'cart/home.html', context)
从django.db.models导入计数F和
def home(请求):
cart=cart.objects.filter(user=request.user).last()
items=Item.objects.all()
购物车\商品=Item.objects.filter(
cartitem\uuu cart=购物车
).注释(
ncount=Count('cartitem',output\u field=DecimalField(最大位数=5,小数位数=0))
)
总计=购物车项目。合计(总计=总和(F(‘价格’)*F(‘ncount’)[‘总计’]
上下文={
“项目”:项目,
“总计”:总计,
“购物车项目”:购物车项目
}
返回渲染(请求“cart/home.html”,上下文)
在模板中,您可以使用以下内容呈现购物车:
<h2>items selected: {{ cart_items|length }}</h2>
{% for item in cart_items %}
<ul>{{ item }} x {{ item.ncount }} <a href="{% url 'remove_from_cart' item.id %}">Remove</a></ul>
{% endfor %}
<h2>Total</h2>
{{ total|floatformat:2 }}
所选项目:{{cart_items | length}
{购物车中商品的%u%}
{item}x{{item.ncount}
{%endfor%}
全部的
{{total | floatformat:2}}
因此,没有理由区分一次性或多次购买的物品
您可以通过以下方式实现删除功能:
def remove_from_cart(request, item_id):
cart = Cart.objects.filter(user=request.user).last()
item_to_remove = CartItem.objects.filter(
item_id=item_id,
cart=cart
).delete()
return redirect(home)
def从购物车中删除(请求,项目id):
cart=cart.objects.filter(user=request.user).last()
item_to_remove=CartItem.objects.filter(
项目标识=项目标识,
购物车
)1.删除()
return redirect(home)
我认为在这里最好开发两个查询集,如:
from django.db.models import Count, F, Sum
def home(request):
cart = Cart.objects.filter(user=request.user).last()
items = Item.objects.all()
cart_items = Item.objects.filter(
cartitem__cart=cart
).annotate(
ncount=Count('cartitem', output_field=DecimalField(max_digits=5, decimal_places=0))
)
total = cart_items.aggregate(total=Sum(F('price') * F('ncount')))['total']
context = {
'items': items,
'total': total,
'cart_items': cart_items
}
return return render(request, 'cart/home.html', context)
从django.db.models导入计数F和
def home(请求):
cart=cart.objects.filter(user=request.user).last()
items=Item.objects.all()
购物车\商品=Item.objects.filter(
cartitem\uuu cart=购物车
).注释(
ncount=Count('cartitem',output\u field=DecimalField(最大位数=5,小数位数=0))
)
总计=购物车项目。合计(总计=总和(F(‘价格’)*F(‘ncount’)[‘总计’]
上下文={
“项目”:项目,
“总计”:总计,
“购物车项目”:购物车项目
}
返回渲染(请求“cart/home.html”,上下文)
在模板中,您可以使用以下内容呈现购物车:
<h2>items selected: {{ cart_items|length }}</h2>
{% for item in cart_items %}
<ul>{{ item }} x {{ item.ncount }} <a href="{% url 'remove_from_cart' item.id %}">Remove</a></ul>
{% endfor %}
<h2>Total</h2>
{{ total|floatformat:2 }}
所选项目:{{cart_items | length}
{购物车中商品的%u%}
{item}x{{item.ncount}
{%endfor%}
全部的
{{total | floatformat:2}}
因此,没有理由区分一次性或多次购买的物品
您可以通过以下方式实现删除功能:
def remove_from_cart(request, item_id):
cart = Cart.objects.filter(user=request.user).last()
item_to_remove = CartItem.objects.filter(
item_id=item_id,
cart=cart
).delete()
return redirect(home)
def从购物车中删除(请求,项目id):
cart=cart.objects.filter(user=request.user).last()
item_to_remove=CartItem.objects.filter(
项目标识=项目标识,
购物车
)1.删除()
return redirect(home)
如果您甚至在用户签出之前就在数据库中保存所选项目,我不建议这样做,那么您可以在模型中进行类似的操作
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class Item(models.Model):
name = models.CharField(max_length=25)
price = models.DecimalField(max_digits=5, decimal_places=2)
def __str__(self):
return self.name
class Cart(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add=True)
items = models.ManyToManyField(Item, through='CartItem')
def __str__(self):
return 'Order number: %s' % self.id
class CartItem(models.Model):
item = models.ForeignKey(Item, on_delete=models.CASCADE)
cart = models.ForeignKey(Cart, on_delete=models.CASCADE)
def __str__(self):
return str(self.item)
class Product(models.Model):
#model info
class Order(models.Model):
item = modelS.ForeignKey(Product, on_delete=models.CASCADE)
user = modelS.ForeignKey(User, on_delete=models.CASCADE)
times = models.IntagerField(default=1)
#..... other relevant fields
class Cart(models.Model):
orders = models.ManyToManyField(Order)
user = modelS.ForeignKey(User,related_name='cart_user' on_delete=models.CASCADE)
#other details like date etc....
然后是一个检查模型是否已存在的视图
def add_order(request,id):
user = request.user
item = Product.objects.get(id=id)
try:
order = Order.objects.get(item=item, user=user)
order.times+=1
order.save()
except:
order = Order.objects.create(
item = item,
user = user
)
try:
my_cart = Cart.objects.get(user=user)
except:
my_cart = Cart.objects.create(user=user)
my_cart.orders.add(order)
#return http reeponse with the new data
我建议您使用ajax将请求提交到调用视图更新的url,以便在将来减少页面刷新如果您甚至在用户签出之前就在数据库中保存所选项目(我不建议这样做),那么您可以在模型中执行类似操作
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class Item(models.Model):
name = models.CharField(max_length=25)
price = models.DecimalField(max_digits=5, decimal_places=2)
def __str__(self):
return self.name
class Cart(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add=True)
items = models.ManyToManyField(Item, through='CartItem')
def __str__(self):
return 'Order number: %s' % self.id
class CartItem(models.Model):
item = models.ForeignKey(Item, on_delete=models.CASCADE)
cart = models.ForeignKey(Cart, on_delete=models.CASCADE)
def __str__(self):
return str(self.item)
class Product(models.Model):
#model info
class Order(models.Model):
item = modelS.ForeignKey(Product, on_delete=models.CASCADE)
user = modelS.ForeignKey(User, on_delete=models.CASCADE)
times = models.IntagerField(default=1)
#..... other relevant fields
class Cart(models.Model):
orders = models.ManyToManyField(Order)
user = modelS.ForeignKey(User,related_name='cart_user' on_delete=models.CASCADE)
#other details like date etc....
然后是一个检查模型是否已存在的视图
def add_order(request,id):
user = request.user
item = Product.objects.get(id=id)
try:
order = Order.objects.get(item=item, user=user)
order.times+=1
order.save()
except:
order = Order.objects.create(
item = item,
user = user
)
try:
my_cart = Cart.objects.get(user=user)
except:
my_cart = Cart.objects.create(user=user)
my_cart.orders.add(order)
#return http reeponse with the new data
我建议您使用ajax将请求提交到调用视图更新的url,以便在将来减少页面刷新次数。这只是另一种方法:为什么不在models.py中为CartItem模型添加一个名为“quantity”的字段或类似的字段?例如:
class CartItem(models.Model):
item = models.ForeignKey(Item, on_delete=models.CASCADE)
cart = models.ForeignKey(Cart, on_delete=models.CASCADE)
quantity = models.IntegerField(default=0)
然后在“添加到购物车”视图中,执行以下操作:
def add_to_cart(request, item_id):
item = Item.objects.get(id=item_id)
cart = Cart.objects.filter(user=request.user).last()
cart_item_qs = CartItem.objects.filter(cart__pk=cart.pk)
if cart_item_qs.exists():
cart_item_qs.update(quantity=F('quantity') + 1)
else:
cart.items.add(item)
cart.save()
return redirect(home)
之后,您可以在模板中使用CartItem模型的实例在上下文数据中传递它,从而从那里访问quantity字段值。另一种方法:为什么不在models.py中为CartItem模型添加一个名为“quantity”的字段或类似的内容?例如:
class CartItem(models.Model):
item = models.ForeignKey(Item, on_delete=models.CASCADE)
cart = models.ForeignKey(Cart, on_delete=models.CASCADE)
quantity = models.IntegerField(default=0)
然后在“添加到购物车”视图中,执行以下操作:
def add_to_cart(request, item_id):
item = Item.objects.get(id=item_id)
cart = Cart.objects.filter(user=request.user).last()
cart_item_qs = CartItem.objects.filter(cart__pk=cart.pk)
if cart_item_qs.exists():
cart_item_qs.update(quantity=F('quantity') + 1)
else:
cart.items.add(item)
cart.save()
return redirect(home)
之后,您可以在模板中使用CartItem模型的实例在上下文数据中传递它,从而从那里访问quantity字段值。问题是,您每次都要计算项目的数量。但是它们是不同的
CartItem
s,因此set(…)
不会将它们视为不同的。我想你应该说set()会将它们视为不同的,这就是为什么允许重复(它们是具有相同名称属性的不同对象)的原因carts[length-1]
在做什么?如果有多个用户,他们将看到最后一个购物车,因此一个用户将看到另一个用户的购物车。因为两个人的名字都是Mirko
,本质上不是同一个人。只是为了得到创建的最后一个购物车(订单)…问题是你每次都要计算物品的数量。但是这些是不同的CartItem
s,因此集合(…)
没有看到