Home > Mobile >  Django - add to favourites button in ListView
Django - add to favourites button in ListView

Time:08-18

I want to create add to favourites feature in ListView but I am struggling with passing product slug in each item.

I have a table with the product name and Action (Add/Remove buttons). I want to allow users to add a specific product to favourites or remove it from there. 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 >

<table >
  <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" >
  {% 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'),

]

CodePudding user response:

You are sending your slug not in a ListView you are sending it

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

to products_in_favourites function, and doing it wrong at recieving part,

You are not sending it to a function as slug, you are sending it as data with post reqeust, and so you should recieve it same way:

@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)

Also it is better to pass pk (primary key) instead of slug, primary key has indexes by default in database, so your query will be much much faster if you use pk.

  • Related