Не работает ссылка “Смотреть на сайте” в Django (решение)

В своё время, когда я изучал Джанго, сломал много копий на этом простом моменте. Решений находил множество, но все они в конкретно моём случае не подходили. Итак. Если вы получили ошибку типа:

NoReverseMatch at /admin/r/7/1/

Reverse for 'f_view_bog' not found. 'f_view_bog' is not a valid view function or pattern name...

То возможная причина в том, что вы неправильно используете функцию reverse() в get_absolute_url. На многих сайтах первый аргумент, который должен являться view-функцией оборачивают в кавычки. Однако, это сработает лучше, если вы не будете так делать, а вместо этого просто импортируете view-функцию вначале файла models.py

Reverse for 'f_view_bog' not found

Чтобы было ещё чуточку понятнее, я приведу небольшоё демо-пример. У нас имеется приложение Blog, файлы которого выглядят следующем образом:

urls.py:

from django.urls import path
from . import views
from .views import f_view_bog

# pattern for the index page, all products and each product
urlpatterns = [
    path('post/<int:post_id>/', f_view_bog, name="post_url"),
]

views.py:

from django.http import HttpResponse
from django.shortcuts import render


# Create your views here.
def f_view_bog(request, post_id):
    return HttpResponse(f"<h1>Текст статьи</h1>{post_id}</p>")

models.py:

from django.db import models
from django.urls import reverse
from blog.views import f_view_bog

# Create your models here.
class Blog(models.Model):
    name = models.CharField(max_length=255, unique=True, verbose_name='Название поста')
    slug = models.SlugField(max_length=200, unique=True, verbose_name='Постоянная ссылка')
    content = models.TextField(blank=True, verbose_name='Текст')

    def get_absolute_url(self):
        return reverse(f_view_bog, kwargs={'post_id': self.pk})

    def __str__(self):
        return self.name

    class Meta:
        verbose_name = 'Запись'
        verbose_name_plural = 'Записи'

Обратите внимание на строки 3 и 12 кода выше. В третей строке мы импортируем вьюху, а в 12-й ссылаемся на неё, но не через return reverse('f_view_bog', kwargs={'post_id': self.pk}), а через return reverse(f_view_bog, kwargs={'post_id': self.pk})

Если данный вариант не подошел

Однако, приведённый выше пример не идеален и имеет свои недостатки. По этой причине предлагаю вам ещё один вариант:

urls.py:

from django.urls import path

from .views import show_post_view, show_category_view

# pattern for the index page, all products and each product
urlpatterns = [
    path('post/<slug:post_slug>/', show_post_view, name="post_url"),
    path('category/<slug:cat_slug>/', show_category_view, name="category_url")
]

views.py:

from django.http import HttpResponse
from django.shortcuts import render, get_object_or_404, redirect

from .models import *


# Create your views here.
def show_post_view(request, post_slug):
    post = get_object_or_404(PostModel, slug=post_slug)
    # в post помещаем все данные о текущей записи в блоге. в дальнейшем в шаблоне будем вызывать так: post.name
    # где name - название одного из полей записи из созданной нами модели в models.py
    context = {
        'post': post
    }

    return render(request, 'blog-single-page.html', context=context)


def show_category_view(request, cat_slug):
    category = get_object_or_404(CategoryModel, slug=cat_slug)
    # в category помещаем все данные о текущей категории. в дальнейшем в шаблоне будем вызывать так: product.name
    # где name - название одного из полей категории из созданной нами модели в models.py
    context = {
        'category': category
    }

    return render(request, 'blog-single-category.html', context=context)

admin.py:

from django.contrib import admin
from mptt.admin import MPTTModelAdmin
from .models import *


# Register your models here.
class BlogAdmin(admin.ModelAdmin):
    prepopulated_fields = {'slug': ('name',)}  # автозаполнение слага из названия

    class Meta:
        verbose_name = 'Запись'
        verbose_name_plural = 'Записи'


class BlogCategoryAdmin(MPTTModelAdmin):
    prepopulated_fields = {'slug': ('name',)}  # автозаполнение слага из названия


admin.site.register(PostModel, BlogAdmin)  # PostModel - имя класса из модели
admin.site.register(CategoryModel, BlogCategoryAdmin)  # CategoryModel - имя класса из модели

models.py:

from django.db import models
from django.urls import reverse
from mptt.fields import TreeForeignKey
from mptt.models import MPTTModel


# Create your models here.
class CategoryModel(MPTTModel):
    name = models.CharField(max_length=50, unique=True, verbose_name='Название категории')
    slug = models.SlugField(max_length=150, verbose_name='slug', null=False, unique=True)
    parent = TreeForeignKey('self', on_delete=models.PROTECT, null=True, blank=True, related_name='children',
                            db_index=True, verbose_name='Родительская категория')

    class MPTTMeta:
        order_insertion_by = ['name']

    def get_absolute_url(self):
        return reverse('category_url', kwargs={'cat_slug': self.slug})

    def __str__(self):
        return self.name

    class Meta:
        verbose_name = 'Категория'
        verbose_name_plural = 'Категории'


class PostModel(models.Model):
    name = models.CharField(max_length=255, unique=True, verbose_name='Название поста')
    slug = models.SlugField(max_length=200, unique=True, verbose_name='Постоянная ссылка')
    category = TreeForeignKey(CategoryModel, on_delete=models.PROTECT, null=False, verbose_name='Категория')
    content = models.TextField(blank=True, verbose_name='Текст')

    def __str__(self):
        return self.name

    def get_absolute_url(self):
        return reverse('post_url', kwargs={'post_slug': self.slug})

    class Meta:
        verbose_name = 'Запись'
        verbose_name_plural = 'Записи'

В данном примере мы заключаем в одинарные кавычки первый аргумент функции reverse. Значение этого аргумента соответствует значению name функции path из файла urls.py

Рейтинг: 5

2023-10-24 / / 0 комментариев / Про кодинг и сервер / ,