Реверс для 'edit_blog_post' с аргументами '('',)' не найден

Я пытаюсь создать способ редактирования отдельных постов блога из их индивидуального html. Вот соответствующие файлы и трассировка. Я немного понимаю, что проблема в blog_post.id из-за того, что blog_post не был перенесен из цикла for в blog_posts.html. Я читал о других людях, столкнувшихся с этой проблемой, и все они структурировали свои страницы так, чтобы кнопка редактирования находилась внутри оригинального цикла for, что вполне логично с точки зрения ретроспективы. Но теперь, когда я столкнулся с этой проблемой, я намерен понять, как я могу решить ее, не возвращаясь назад и не перестраивая свои страницы, чтобы они соответствовали другим, которые я видел.

urls.py


from django.urls import path

from . import views

app_name = 'blogs'
urlpatterns = [
    # Home page
    path('', views.index, name='index'),
    path('blog_posts/', views.blog_posts, name='blog_posts'),
    path('blog_posts/<int:blog_post_id>/', views.blog_post, name='blog_post'),
    path('new_blog_post/', views.new_blog_post, name='new_blog_post'),
    path('edit_blog_post/<int:blog_post_id>/', views.edit_blog_post, name='edit_blog_post'),

]

views.py


from .models import BlogPost
from .forms import BlogPostForm

def index(request):
    """Home page for Blog."""
    return render(request, 'blogs/index.html')

def blog_posts(request):
    """Show all Blog Posts."""
    blog_posts = BlogPost.objects.order_by('date_added')
    context = {'blog_posts': blog_posts}
    return render(request, 'blogs/blog_posts.html', context)

def blog_post(request, blog_post_id):
    """Show details of an individual blog post."""
    blog_post = BlogPost.objects.get(id=blog_post_id)
    title = blog_post.title
    id = blog_post_id
    date = blog_post.date_added
    text = blog_post.text
    context = {'title': title, 'text': text, 'date': date}
    return render(request, 'blogs/blog_post.html', context)

def new_blog_post(request):
    """Add a new blog post"""
    if request.method != 'POST':
        # No data submitted, create a blank form.
        form = BlogPostForm()
    else:
        # POST data submitted, process data.
        form = BlogPostForm(data=request.POST)
        if form.is_valid():
            form.save()
            return redirect('blogs:blog_posts')
    # Display a blank or invalid form.
    context = {'form': form}
    return render(request, 'blogs/new_blog_post.html', context)

def edit_blog_post(request, blog_post_id):
    """Edit an existing blog post's title or text."""
    blog_post = BlogPost.objects.get(id=blog_post_id)
    if request.method != 'POST':
        # Initial request, prefill with the current data.
        form = BlogPostForm(instance=blog_post)
    else:
        # POST data submitted; process new data.
        form = BlogPostForm(instance=blog_post, data=request.POST)
        if form.is_valid():
            form.save()
            return redirect('blogs:blog_post', blog_post_id=blog_post.id)
    context = {'blog_post': blog_post, 'form': form}
    return render(request, 'blogs/edit_blog_post.html',  context)

models.py

from django.db import models

class BlogPost(models.Model):
    """A post the user is posting on their blog."""
    title = models.CharField(max_length=200)
    text = models.TextField()
    date_added = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        """Return a string representation of the model"""
        return f"{self.title.title()}"

blog_posts.html

{% extends 'blogs/base.html' %}

{% block content %}

<p>Blog Posts</p>

<ul>
    {% for blog_post in blog_posts %}
    <li>
        <a href="{% url 'blogs:blog_post' blog_post.id %}">{{ blog_post }}</a>
    </li>
    {% empty %}
    <li>No posts have been made yet.</li>
    {% endfor %}
</ul>

<a href="{% url 'blogs:new_blog_post' %}">Add a new blog post</a>

{% endblock content %}

blog_post.html

{% extends 'blogs/base.html' %}

{% block content %}

<p>Blog Post: {{ title }}</p>

<p>Entry:</p>

<p>{{ text }}</p>
<p>{{ date }}</p>

<p>
    <a href="{% url 'blogs:edit_blog_post' blog_post.id %}">Edit Blog Post</a>
</p>

{% endblock content %}

edit_blog_post.html

{% extends "blogs/base.html" %}

{% block content %}

<p>
    <a href="{% 'blogs:blog_post' blog_post.id %}">{{ blog_post }}</a>
</p>
    <p>Edit Blog Post</p>

<form action="{% url 'blogs:edit_blog_post' blog_post.id %}" method='post'>
    {% csrf_token %}
    {{ form.as_p }}
    <button name="submit">Save Changes</button>
</form>

{% endblock content %}

Повтор для 'edit_blog_post' с аргументами '('',)' не найден. Попытка 1 шаблона(ов): ['edit_blog_post/(?P<blog_post_id>[0-9]+)/\Z']

3   {% block content %}
4   
5   <p>Blog Post: {{ title }}</p>
6   
7   <p>Entry:</p>
8   
9   <p>{{ text }}</p>
10  <p>{{ date }}</p>
11  
12  <p>
13      <a href="{% url 'blogs:edit_blog_post' blog_post.id %}">Edit Blog Post</a>
14  </p>
15  
16  {% endblock content %}

Если я правильно понял вопрос, вы получаете ошибку из-за того, что не указали необходимый ID в части построения URL в вашем шаблоне.

Вы отделяете элементы (дата, содержание и т.д.) для отправки в шаблон, но не передаете ID в то же время. Вы могли бы передавать ID в виде отдельной контекстной переменной, но это лишний набор текста без реальной награды.

Проще всего передавать пост сам через контекст и ссылаться на его атрибуты в шаблоне - мне кажется, так его легче читать. Таким образом, ID будет там, когда вам понадобится создать ссылку для редактирования, и если вы измените модель, чтобы иметь дополнительные поля, вам не нужно будет преобразовывать и добавлять в контекст, поскольку весь пост уже там.

views.py

def blog_post(request, blog_post_id):
    """Show details of an individual blog post."""
    blog_post = BlogPost.objects.get(id=blog_post_id) #this is all we need
    context = {"blog_post_context": blog_post}

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

blog_post.html

{% extends 'blogs/base.html' %}

{% block content %}

<p>Blog Post: {{ blog_post_context.title }}</p>

<p>Entry:</p>

<p>{{ blog_post_context.text }}</p>
<p>{{ blog_post_context.date }}</p>

<p>
    <a href="{% url 'blogs:edit_blog_post' blog_post_context.pk %}">Edit Blog Post</a>
</p>

{% endblock content %}

Если это все работает, рассмотрите возможность использования get_object_or_404 вместо Post.objects.get для дополнительной надежности.

Я предполагаю, что вы получили error при попытке посетить страницу blog_post.html. Если я прав, то вот подход, который вы могли бы использовать...

В вашем views.py

def blog_post(request, blog_post_id):
     """Show details of an individual blog post."""
     # blog_post = BlogPost.objects.get(id=blog_post_id)
     blog_post = get_object_or_404(id=blog_post_id)  # Recommended

     # Commented lines below are somewhat not necessary...
     
     # title = blog_post.title
     # id = blog_post_id
     # date = blog_post.date_added
     # text = blog_post.text

     context = {'blog_post': blog_post}

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

edit_blog_post.html ожидает, что object с именем blog_post сможет получить доступ к blog_post.id для {% url 'blogs:edit_blog_post' blog_post.id %}.

Теперь внутри edit_blog_post.html файла.

{% block content %}
     <p>Blog Post: {{ blog_post.title }}</p>

     <p>Entry:</p>
     <p>{{ blog_post.text }}</p>
     <p>{{ blog_post.date_added }}</p>

     <p>
          <a href="{% url 'blogs:edit_blog_post' blog_post.id %}">Edit Blog Post</a>
     </p>
{% endblock content %}
Вернуться на верх