djangodjango-modelsdjango-viewsslugslugify

Slug returns Reverse for '' with arguments '('',)' not found. 1 pattern(s)


I am trying to make it so when I view a blog from any particular link on my website, the url displays www.example.com/view-blog/slug. I have got it working for my images and image title. But I cannot get it to work with blog titles.

It keeps returning the error:

Reverse for 'viewblog' with arguments '('',)' not found. 1 pattern(s) tried: ['view\-blog/(?P[-a-zA-Z0-9_]+)/\Z'].

Models.py

class BlogPost(models.Model):
    blog_title = models.CharField(max_length=100, null=False, blank=False, default="")
    slug = models.SlugField()
    blog_article = RichTextUploadingField(null=True, blank=True, default="ici")
    blog_image = models.ImageField(null=True, blank=True, upload_to="images", default="default.png")
    blog_date = models.DateField(auto_now_add=True)
    blog_published = models.BooleanField(default=False)
    blog_featured = models.BooleanField(default=False)
        
    def save(self, *args, **kwargs):
        self.slug = self.slug or slugify(self.blog_title)
        super().save(*args, **kwargs)

    def __str__(self):
        return self.blog_title

Views.py EDIT: ADDED ALL VIEWS.

    def blogPage(request):
    posts = BlogPost.objects.filter(blog_date__lte=timezone.now()).order_by('-blog_date')[:4]
    context = {'posts': posts}
    
    return render(request, 'blog.html', context)

def blogsPage(request):
    posts = BlogPost.objects.filter(blog_date__lte=timezone.now()).order_by('-blog_date')
    context = {'posts': posts}

    return render(request, 'blogs.html', context)

def searchBlogs(request):
    if request.method == "POST":
        searched = request.POST.get('searched', False);
        searched_blogs = BlogPost.objects.filter(blog_title__icontains=searched)
        
        return render(request, 'search-blogs.html', {'searched': searched, 'searched_blogs': searched_blogs})

def viewBlog(request, slug):
    try:
        blog = BlogPost.objects.get(slug=slug)
    except BlogPost.DoesNotExist:
        print("ViewBlog with this slug does not exist")
        blog = None
    return render(request, 'view-blog.html', {'blog': blog, 'slug': slug})

Urls.py

urlpatterns = [
    path('', views.galleryPage, name='gallery'),
    path('gallery/', views.galleryPage, name='gallery'),
    path('contact/', views.contactPage, name='contact'),
    path('blog/', views.blogPage, name='blog'),
    path('blogs/', views.blogsPage, name='blogs'),
    path('search-blogs/', views.searchBlogs, name='searchblogs'),
    path('view-image/<slug:slug>/', views.viewImage, name='viewimage'),
    path('view-blog/<slug:slug>/', views.viewBlog, name='viewblog'),
    path('thank-you/', views.thankyouPage, name='thankyou'),
    path('about-me/', views.aboutmePage, name='aboutme'),
]

**One of my templates I wish to link to viewblog page from ** ( I have tried to replace .id on my urls with .slug but this is what gives me the error.

<body>
<header>{% include 'navbardesktop.html' %}</header>
  <div class="blog-container">
    <h1 class="all-blog-title" id="all-blog-title" style="text-align: center;">All Blogs</h1>
    <br>
      <div class="search">
        <form class="d-flex" method="POST" action="{% url 'searchblogs' %}">
          {% csrf_token %}
          <i class="fa fa-search"></i>
          <input type="text" class="form-control" placeholder="Search keyword" name="searched">
          <button id="search-btn" class="btn btn-secondary">Search</button>
        </form>
      </div>
      <br> 
    <hr id="blog-hr" style="width:50%; margin-left:25% !important; margin-right:25% !important;" />
    <div class="blog-post-container">
      <div class="dropdown">
        <button class="btn btn-secondary dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">
          Blog List
        </button>
        <ul class="dropdown-menu" style="background-color: #d6d6d6 ;">
          {% for post in posts %} {% if post.blog_published is True %}
          <li><a class="dropdown-item" href="{% url 'viewblog' post.id %}">{{post.blog_title}}</a></li>
          {% endif %}
          {% endfor %}
        </ul>
        <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-kenU1KFdBIe4zVF0s0G1M5b4hcpxyD9F7jL+jjXkk+Q2h455rYXK/7HAuoJl+0I4" crossorigin="anonymous"></script>
      </div>
      <div class="row">
        {% for post in posts %} {% if post.blog_published is True %}
          <div class="col-md-4" id="blog-col">
              <div class="blog-post">
                <div class="blog-content">
                      <img class="blog-img"src="{{post.blog_image.url}}"alt="My image"/>
                      <h2 class="blog-title">{{post.blog_title}}</h2>
                      <hr id="blog-hr" style="width: 90%" />
                      <article class="blog-article">
                        <p>{{post.blog_article|truncatechars_html:265|safe}}</p>
                      </article>
                      <a href="{% url 'viewblog' post.slug %}"class="btn btn-secondary"type="button"class="blog-button">Read More...</a>
                      <p class="blog-date">Posted on: {{post.blog_date}}</p>
                    </div>
                </div>
              </div>
              {% endif %} {% empty %}
              <h3>No Blog Uploads</h3>
              {% endfor %}
          </div>
      </div>
    </div>
  </div>  
 

Solution

  • the error message

    Reverse for 'viewblog' with arguments '('',)' not found.
    

    Remark: what is '('',)' ??

    it is simply the print of a python list () with one empty argument ('',). The comma just indicates it is a list. This is placed in '' to structure the error message text '('',)'

    so this is the list of arguments that is extracted from your {% url .... %} statement for the error message

    always means you have and url tag pointing to "viewblog" that requires an argument (because definded like that in urlpatterns in urls.py ) but actually one of them is null or "" (which is not accepted to reverse a valid url):

    urlpatterns = [
        ...
        path('view-blog/<slug:slug>/', views.viewBlog, name='viewblog'),
        ...
    ]
    
    ---------------------------------
    
    href="{% url 'viewblog' post.id %}"
    
    

    Now in your case you had originally post.id as parameter (I understood you changed that to post.slug). That means one of the post database entries has a post.slug that is null or ""

    to debug just print the value of post.slug into the html page and you will see what is wrong. the "xxx" and "yyy" are there to mark on the output clearly where some content shoult appear (because without it is more difficult to see if there is an empty output).

    {% for post in posts %} 
    
    xxx {{ post.slug }} xxx <br>
    yyy {{ post.blog_title }} xxx <br>
    
    {% endfor %}
    

    Another way of checking post.slug is to go to the admin page ouf your app and inspect the database entries directly

    And a third one would be to print the query result for posts in the view:

    def blogsPage(request):
        posts = BlogPost.objects.filter(blog_date__lte=timezone.now()).order_by('-blog_date')
        context = {'posts': posts}
    
        for post in posts:
           print(post)
    
        return render(request, 'blogs.html', context)
    

    which will show the content of posts in the console