Две (почти) идентичные функции Veiw.py ведут себя по-разному
Итак, я разрабатываю систему корзины для сайта электронной коммерции, используя Django. Есть две отдельные функции для обработки добавления и удаления элементов корзины. (Я не могу объединить их в одну функцию, не изменив структуру базы данных и шаблона)
Первая функция, 'update_cart', работает просто отлично. Она правильно обновляет соответствующую модель.
Однако, вторая функция 'remove_item' запускается, когда пользователь нажимает кнопку 'remove' в списке элементов, и функция действительно выполняется и перенаправляет правильно.
Однако при этом не удается обновить объект модели "многие-ко-многим", идентифицированный по внешнему ключу и связанный с элементом.
Это так странно, потому что я обращаюсь к объекту одинаково в обеих функциях. Разница лишь в том, что в первой используется .add(), а во второй .remove().
Кроме того, шаблон должен загружать id товара в данные GET, но не показывает его в URL, как в другом шаблоне, который запускает функцию 'update_cart'.
Но он показывает mycart/?id=86 при наведении курсора на кнопку. (это особенность хрома). Это очень сбивает с толку.
Можете ли вы, ребята, помочь мне понять, что я упускаю из виду? Спасибо за ваше время :)
view.py functions:
def update_cart(request):
context={}
if request.user.is_authenticated:
print('triggered')
owner = request.user.id
cart = Cart.objects.get(cart_owner=owner)
productID = request.GET['id']
product = Product.objects.get(pk=productID)
cart.products.add(product)
new_total = 0.00
for item in cart.products.all():
new_total += float(item.priceNotax)
cart.total = new_total
cart.save()
def remove_item(request):
if request.user.is_authenticated:
owner = request.user.id
cart = Cart.objects.get(cart_owner=owner)
productID = request.GET['id']
print(productID)
product = Product.objects.get(pk=productID)
cart.products.remove(product)
cart.save()
new_total = 0.00
for item in cart.products.all():
new_total += float(item.priceNotax)
cart.total = new_total
cart.save()
return HttpResponseRedirect(reverse("myCart"))
else:
return HttpResponseRedirect(reverse("login"))
Файл model.py, содержащий затронутую модель 'Cart':
class Cart(models.Model):
cart_owner = models.ForeignKey(User, on_delete=models.CASCADE, null=True)
products = models.ManyToManyField(Product, null=True, blank=True)
#held_items = models.ManyToManyField(Order_holding, null=True, blank=True)
total = models.DecimalField(max_digits=100, decimal_places=2, default=0.00)
timestamp = models.DateTimeField(auto_now_add=False, auto_now=True)
updated = models.DateTimeField(auto_now_add=False, auto_now=True)
active = models.BooleanField(default=True)
def __unicode__(self):
return "Cart id: %s" %(self.id)
Шаблон, вызывающий функцию 'remove_item':
{% extends 'base.html' %}
{% load static %}
{% block content %}
<div class="container-fluid mb-2">
<div class="card">
<div class="card-header"><h3>Shopping Cart</h3></div>
</div>
</div>
{% for item in cart.products.all %}
<div class="container-fluid mb-2">
<div class=".row-4 .row-sm-4 m-4 card justify-content-center">
<div><h4>{{ item.name }}</h4></div>
<div><h4>Price: ${{ item.priceNotax }}</h4><a href="{% url 'remove_item'%}?id={{item.id}}"><button class='btn-danger justify-content-right'>Remove</button></div></a>
</div>
</div>
{% endfor %}
<h2>Sub-Total: ${{total}}</h2>
<a href="{% url 'products'%}"><button class="btn-primary">Continue Shoping</button></a>
{% endblock content %}
Не видя остальной части вашего кода, я не могу ответить на первоначальный вопрос, почему две функции представления ведут себя по-разному.
Что касается проблемы с якорем, вы можете просто стилизовать ссылку под кнопку в bootstrap, например, так:
<a href="{% url 'remove_item'%}?id={{item.id}}" class='btn btn-danger justify-content-right'>Remove</a>
Или, вы можете обернуть кнопку в тег формы, например, так (я не тестировал это):
<form style="display: inline" action="{% url 'remove_item' %}" method="get">
<button class='btn-danger justify-content-right'>Remove</button>
</form>
Но GET-запросы небезопасны и никогда не должны использоваться для изменения базы данных. Вместо этого вы можете использовать POST-запрос, например, такой:
<form action="{% url 'remove_item' %}" method="post">
{% csrf_token %}
<input type="hidden" name="item_id" value="{{ item.id }}">
<button type='submit' class='btn-danger justify-content-right'>Remove</button>
</form>
Это отправит id элемента через скрытый ввод, а затем в ваших представлениях вы сможете получить доступ к той же информации более безопасным способом, чем как часть URL, что происходит при GET-запросе.
def remove_item(request):
if request.method == 'POST':
item_id = request.POST.get('item_id')
# Here you have your code that actually removes the item
Я понял это, ребята. Я пропустил URL файла главного приложения. У меня вызывались разные представления, но у них был один и тот же путь, и неправильное представление было указано первым, поэтому оно вызывалось раньше, чем то, которое было нужно. lol Извините!