Как отобразить только первое вхождение элемента в наборе в шаблоне Django? - PullRequest
1 голос
/ 27 января 2020

Я учусь Django, так что, возможно, это не лучший способ сделать то, что я хочу.

То, что я пытаюсь сделать здесь, это отобразить элемент, который был выбран несколько раз в корзина, только один раз (и количество раз, когда она была выбрана рядом с ней)

Я целый день пытался найти способ, но самое близкое, что мне удалось сделать, это внутри представлений произвести два набора: single_items и множественные_items.

У меня нет проблем с отображением элемента, который был выбран только один раз, но когда дело доходит до элементов, выбранных несколько раз, я могу отображать их только n раз с количеством появлений в следующем к нему, как показано на рисунке

enter image description here

Хотя я бы предпочел сделать все вычисления с кодом python (в views.py) решение с Django мне подойдет язык шаблонов.

Пожалуйста, примите во внимание, что мне нужно передать идентификатор элемента в URL, чтобы заставить работать ссылку на удаление.

вот виды. 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)
* 102 0 * и мой шаблон
<!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>

и на всякий случай модели

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)

РЕДАКТИРОВАТЬ

на данный момент я использую этот 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)

Ответы [ 3 ]

0 голосов
/ 27 января 2020

Если вы сохраняете выбранные элементы в базе данных еще до того, как пользователь их проверит, что я бы не советовал, то вы можете сделать что-то подобное в моделях

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, который вызывает представление для обновления, чтобы в будущем было меньше ссылок на страницы sh 1007 *

0 голосов
/ 27 января 2020

Еще один подход: почему бы вам не добавить модель Field к CartItem в вашем models.py, названную «количество» или что-то в этом роде? Например:

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)

А затем в представлении add_to_cart вы должны сделать:

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, передавая его в контекстные данные и, следовательно, доступ к значению поля количества оттуда.

0 голосов
/ 27 января 2020

Я думаю, что здесь было бы лучше разработать два набора запросов, таких как:

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(
        <b>ncount=Count('cartitem', output_field=DecimalField(max_digits=5, decimal_places=0))</b>
    )
    <b>total = cart_items.aggregate(total=Sum(F('price') * F('ncount')))['total']</b>
    context = {
        'items': items,
        'total': total,
        'cart_items': cart_items
    }
    return return render(request, 'cart/home.html', context)

В вашем шаблоне вы можете отобразить корзину с помощью:

<h2>items selected: {{ cart_items|length }}</h2>
{% for item in <b>cart_items</b> %}
    <ul>{{ item }} x {{ item.ncount }} <a href="{% url 'remove_from_cart' item.id %}">Remove</a></ul>
{% endfor %}
<h2>Total</h2>
{{ total|floatformat:2 }}

, так что нет причина проводить различие между объектами, купленными один раз или несколько раз.

Вы можете реализовать функцию удаления с помощью:

def remove_from_cart(request, item_id):
    cart = Cart.objects.filter(user=request.user).last()
    item_to_remove = CartItem.objects<b>.filter(
        item_id=item_id,
        cart=cart
    ).delete()</b>
    return redirect(home)
...