Django - кнопка добавления в избранное в ListView

Я хочу создать функцию добавления в избранное в ListView, но у меня возникают трудности с передачей slug продукта в каждом элементе.

У меня есть таблица с названием продукта и действием (кнопки Добавить/Удалить). Я хочу позволить пользователям добавлять определенный продукт в избранное или удалять его оттуда. enter image description here

models.py

class Product(models.Model):
    [...]
    favourite = models.ManyToManyField(User, default=None, blank=True, related_name='favourite_product')
    slug = models.SlugField(unique=True, blank=True, max_length=254)

views.py

@login_required
def products_in_favourites(request, slug):
    product = get_object_or_404(Product, slug=slug)
    added_to_favourite = False
    if product.favourite.filter(id=request.user.id).exists():
        product.favourite.remove(request.user)
        added_to_favourite = False
    else:
        product.favourite.add(request.user)
        added_to_favourite = True

    context = {
        'object': product,
        'added_to_favourite': added_to_favourite,
    }
    if request.is_ajax():
        html = render_to_string('favourite.html', context, request=request)
        return JsonResponse({'form': html})


class AddToFavourite(LoginRequiredMixin, ListView):
    template_name = "AddToFavourite.html"
    model = Product
    queryset = Product.objects.all()
    context_object_name = 'product_list'
    
    def get_context_data(self, **kwargs):
        context = super(AddToFavourite, self).get_context_data(**kwargs)
        product_item = get_object_or_404(Product, slug=self.kwargs['slug']) # how to pass slug of each product item here?

        added_to_favourite = False
        if product_item.cart.filter(id=self.request.user.id).exists():
            added_to_favourite = True
        
        context['added_to_favourite'] = added_to_favourite

AddToFavourite.html

{% block body %}

<section class="container">

<table class="table table-hover">
  <thead>
    <tr>
      <th scope="col">Product</th>
      <th scope="col">Action</th>
    </tr>
  </thead>
  <tbody id="favourite">
    {% for product in product_list %}
    <tr>
      <td>{{product.title}}</td>
      <td>
          {% include 'favourite.html' %}
      </td>
    </tr>
    {% endfor %}
  </tbody>
</table>

</section>

{% endblock body %}

{% block javascript_files %}

<script>
    $(document).ready(function(event){
      $(document).on('click', '#favourite', function(event){
        event.preventDefault();
        var slug = $(this).attr('value');
        $.ajax({
          type: 'POST',
          url: '{% url "products_in_favourites" product.slug %}',
          data: {
            'slug':slug, 
            'csrfmiddlewaretoken': '{{ csrf_token }}'
          },
          dataType: 'json',
          success: function(response){
            $('#favourite-section').html(response['form'])
          },
          error: function(rs, e){
            console.log(rs.responseText);
          },
        });
      });
    });
  </script>

{% endblock javascript_files %}

favourite.html

<form action="{% url 'products_in_favourites' product.slug %}" method="POST" class="mx-3">
  {% csrf_token %}
  {% if added_to_favourite %}
  <button type="submit" id="favourite" name="product_slug", value="{{product.slug}}">Remove</button>
  {% else %}
  <button type="submit" id="favourite" name="product_slug", value="{{product.slug}}">Add</button>
  {% endif %}
</form>

urls.py

urlpatterns = [
path('add-to-favourite/', views.AddToFavourite.as_view(), name='cost_calculator'),
path('add-to-favourite/<slug:slug>', views.products_in_favourites, name='products_in_favourites'),

]

Вы посылаете свою пулю не в ListView Вы посылаете ее

 <form action="{% url 'products_in_favourites' product.slug %}" method="POST" class="mx-3"> 

в функцию products_in_favourites, и делает это неправильно в части получения,

Вы не посылаете его в функцию как slug, вы посылаете его как data с post reqeust, и поэтому вы должны получить его таким же образом:

@login_required
def products_in_favourites(request):
    #print all data to see what is coming to this view
    print(request.POST)
    slug = request.POST['product_slug']
    product = get_object_or_404(Product, slug=slug)

Также лучше передавать pk (первичный ключ) вместо slug, первичный ключ по умолчанию имеет индексы в базе данных, поэтому ваш запрос будет намного быстрее, если вы используете pk.

Вернуться на верх