django.urls.exceptions.NoReverseMatch: Reverse for 'like_post' with arguments '('',)' not found

26 Views Asked by At

There is full error: Reverse for 'like_post' with arguments '('',)' not found. 1 pattern(s) tried: ['recipe/like/(?P[0-9]+)\Z']

I suspect there is some issue with post_if but I'm unable to point out exactly whats wrong. i really dont know what to do, i think i tried everything(.

views.py:

def LikeView(request, pk):
  post = get_object_or_404(models.Recipe, id=request.POST.get('post_id'))
  liked = False
  if post.likes.filter(id=request.user.id).exists():
      post.likes.remove(request.user)
      liked = False
  else:
      post.likes.add(request.user)
      liked = True

  return HttpResponseRedirect(reverse('recipe-detail', args=[str(pk)]))

templates:

{% block content %}
  <form action="{% url 'like_post' post.pk %}"
        method = "POST">
          {% csrf_token %}
          <form action="{% url 'like_post' post.pk %}" method="POST">
            {% csrf_token %}
          
          {% if user.is_authenticated %}
            {% if liked %}
              <button type="submit", name="post_id", value="{{ post.id }}", class="btn btn-danger btn-sm">Unlike</button> 
            {% else %}  
              <button type="submit", name="post_id", value="{{ post.id }}", class="btn btn-primary btn-sm">Like</button> 
        
            {% endif %}
          {% else %}
            <small><a href="{% url 'login' %}">Login</a> to like</small>
          {% endif %}
          
            - {{ total_likes }} Likes
          
          </form>

models.py:

class Recipe(models.Model):
  title = models.CharField(max_length=100)
  description = models.TextField()
  author = models.ForeignKey(User, on_delete=models.CASCADE)
  created_at = models.DateTimeField(auto_now_add=True)
  updated_at = models.DateTimeField(auto_now=True)
  ingredients = models.ManyToManyField(Ingredient)
  likes = models.ManyToManyField(User, related_name='blog_posts')

  def get_absolute_url(self):
    return reverse("recipes-detail", kwargs={"pk": self.pk})
  
  def total_likes(self):
    return self.likes.count()

  def __str__(self):
    return self.title
1

There are 1 best solutions below

0
willeM_ Van Onsem On

Based on the error, very likely, there is no variable named post in the template. It is probably recipe.

But the template is quite strange: you encode the primary key both in the url, and in the POST parameters, and furthermore you make two forms with one nested in the other.

{% block content %}
<form action="{% url 'like_post' recipe.pk %}" method = "POST">
{% csrf_token %}
{% if user.is_authenticated %}
  {% if liked %}
    <button type="submit" class="btn btn-danger btn-sm">Unlike</button> 
  {% else %}  
    <button type="submit" class="btn btn-primary btn-sm">Like</button>   
  {% endif %}
{% else %}
  <small><a href="{% url 'login' %}">Login</a> to like</small>
{% endif %}         
- {{ total_likes }} Likes          
</form>

We can also boost the view a bit with:

from django.contrib.auth.decorators import login_required
from django.shortcuts import redirect


@login_required
def like(request, pk):
    liked = False
    removed, __ = models.Recipe.likes.through.filter(
        recipe_id=pk, user_id=request.user.id
    ).delete()
    if not removed:
        models.Recipe.likes.through.create(recipe_id=pk, user_id=request.user.id)
    return redirect('recipe-detail', pk)

We here don't have to fetch the Recipe item first, but immediately try to delete a like with that recipe_id and user_id. If no record is removed, we continue by creating one.


Note: You can limit views to a view to authenticated users with the @login_required decorator [Django-doc].


Note: Functions are normally written in snake_case, not PascalCase, therefore it is advisable to rename your function to like, not LikeView.


Note: You can make use of redirect(…) [Django-doc] instead of first calling reverse(…) [Django] and then wrap it in a HttpResponseRedirect object [Django-doc]. The redirect(…) function does not only offer a more convenient signature to do this, it also for example will use the .get_absolute_url() method [Django-doc] if you pass it a model object.