Как переопределить метод admin save_model

#python #django

#python #django

Вопрос:

Я использую slugify для создания слагов для URL-адресов сообщений моего блога. Чтобы принимать в пуле также неанглийские символы (греческие), я заменил метод save() Post model на метод, который включает параметр allow_unicode=True . Однако это не может работать в области администрирования. Всякий раз, когда я пытался установить греческий символ в области администрирования, либо установив новую запись с греческим названием, либо отредактировав английскую строку существующего сообщения, форма администратора не позволяла мне сохранять. Для этого, как я обнаружил в других потоках, я должен переопределить метод save_model() в admin.py досье. Я так и сделал, но я получаю сообщение об ошибке. Теперь ошибка, которую я получаю, указывает на то, что область администратора запросила сообщение, пуля которого изменится на старый URL (на основе идентификатора), вместо URL-адреса, который я установил в urls.py .

Ошибка, которую я получаю, это либо an AttribureError at /admin/blog/post/1 (когда я редактирую фрагмент существующего сообщения), либо an AttribureError at /admin/blog/post/add (когда я добавляю новое сообщение). И значение исключения в обоих случаях равно 'WSGIRequest' object has no attribute 'save'

Как мне настроить методы сохранения на стороне администратора для запроса URL-адресов с использованием URL-адресов slug? Заранее благодарю вас!

models.py:

 from django.db import models
from django.utils import timezone
from django.contrib.auth.models import User
from django.urls import reverse
from ckeditor.fields import RichTextField
from django.utils.text import slugify
from taggit.managers import TaggableManager

class Post(models.Model):
    title = models.CharField(max_length=100)
    content = RichTextField(blank=True, null=True)
    date_posted = models.DateTimeField(default=timezone.now)
    author = models.ForeignKey(User, on_delete=models.CASCADE)
    is_published = models.BooleanField(default=True)
    slug = models.SlugField(unique=True, max_length=100)
    tags = TaggableManager(blank=True)

    def __str__(self):
        return self.title

    def get_absolute_url(self):
        return reverse('post-detail', kwargs={'slug': self.slug})

    def save(self, *args, **kwargs):
        if not self.slug:
            self.slug = slugify(self.title, allow_unicode=True)
        super(Post, self).save(*args, **kwargs)
  

admin.py:

 from django.contrib import admin
from .models import Post
from django.utils.text import slugify

class PostAdmin(admin.ModelAdmin):
    prepopulated_fields = {'slug': ('title',)}
    list_display = ('title', 'slug', 'is_published', 'author', 'date_posted')
    list_editable = ('is_published',)

    def save_model(self, request, obj, form, change):
        if not obj.slug:
            obj.slug = slugify(obj.title, allow_unicode=True)
        super(PostAdmin, self).save_model(self, request, obj, form)

admin.site.register(Post, PostAdmin)
  

urls.py:

 from django.urls import path, register_converter, re_path
from .views import (
    PostListView,
    UserPostListView,
    PostDetailView,
    PostCreateView,
    PostUpdateView,
    PostDeleteView,
    TagIndexView
)
from django.urls.converters import SlugConverter

class CustomSlugConverter(SlugConverter): 
    regex = '[-w] '

register_converter(CustomSlugConverter, 'custom_slug')

urlpatterns = [
    path('front_page', PostListView.as_view(), name='blog-home'),
    path('user/<str:username>', UserPostListView.as_view(), name='user-posts'),
    re_path(r'post/(?P<slug>[w-] )/$', PostDetailView.as_view(), name='post-detail'),
    path('post/new/', PostCreateView.as_view(), name='post-create'),
    re_path(r'post/(?P<slug>[w-] )/update$', PostUpdateView.as_view(), name='post-update'),
    re_path(r'post/(?P<slug>[w-] )/delete$', PostDeleteView.as_view(), name='post-delete'),
    path('tag/<slug>', TagIndexView.as_view(), name='tag-posts'),
]
  

РЕДАКТИРОВАТЬ: вот трассировка ошибки:

 Traceback (most recent call last):
  File "/home/george/PythProj/myWebsite/myws_venv/lib/python3.7/site-packages/django/core/handlers/exception.py", line 47, in inner
    response = get_response(request)
  File "/home/george/PythProj/myWebsite/myws_venv/lib/python3.7/site-packages/django/core/handlers/base.py", line 179, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/home/george/PythProj/myWebsite/myws_venv/lib/python3.7/site-packages/django/contrib/admin/options.py", line 614, in wrapper
    return self.admin_site.admin_view(view)(*args, **kwargs)
  File "/home/george/PythProj/myWebsite/myws_venv/lib/python3.7/site-packages/django/utils/decorators.py", line 130, in _wrapped_view
    response = view_func(request, *args, **kwargs)
  File "/home/george/PythProj/myWebsite/myws_venv/lib/python3.7/site-packages/django/views/decorators/cache.py", line 44, in _wrapped_view_func
    response = view_func(request, *args, **kwargs)
  File "/home/george/PythProj/myWebsite/myws_venv/lib/python3.7/site-packages/django/contrib/admin/sites.py", line 233, in inner
    return view(request, *args, **kwargs)
  File "/home/george/PythProj/myWebsite/myws_venv/lib/python3.7/site-packages/django/contrib/admin/options.py", line 1656, in change_view
    return self.changeform_view(request, object_id, form_url, extra_context)
  File "/home/george/PythProj/myWebsite/myws_venv/lib/python3.7/site-packages/django/utils/decorators.py", line 43, in _wrapper
    return bound_method(*args, **kwargs)
  File "/home/george/PythProj/myWebsite/myws_venv/lib/python3.7/site-packages/django/utils/decorators.py", line 130, in _wrapped_view
    response = view_func(request, *args, **kwargs)
  File "/home/george/PythProj/myWebsite/myws_venv/lib/python3.7/site-packages/django/contrib/admin/options.py", line 1534, in changeform_view
    return self._changeform_view(request, object_id, form_url, extra_context)
  File "/home/george/PythProj/myWebsite/myws_venv/lib/python3.7/site-packages/django/contrib/admin/options.py", line 1580, in _changeform_view
    self.save_model(request, new_object, form, not add)
  File "/home/george/PythProj/myWebsite/blog/admin.py", line 15, in save_model
    super(PostAdmin, self).save_model(self, request, obj, form)
  File "/home/george/PythProj/myWebsite/myws_venv/lib/python3.7/site-packages/django/contrib/admin/options.py", line 1093, in save_model
    obj.save()

Exception Type: AttributeError at /admin/blog/post/1/change/
Exception Value: 'WSGIRequest' object has no attribute 'save'
  

EDIT2: Решением, позволяющим избежать ошибки, было, конечно, правильно написать мой метод super(). Однако это не дало моему коду той функциональности, которую я хотел. Итак, что, по-видимому, является решением моей проблемы, так это объявить slug в моей модели как CharField вместо SlugField. В этом случае я могу даже удалить свой метод save_model(), который был причиной публикации. Теперь я проверяю, будет ли какой-либо побочный эффект от удаления SlugField. Если нет, я должен найти поток, в котором я видел это решение, чтобы отдать должное, если есть побочные эффекты, я должен восстановить SlugField и найти способ переопределить его validate_slug класс. Вот и все, спасибо вам, ребята, за ваш ответ!

EDIT3: не заметил, что allow_unicode=True это может быть аргументом не только для slugify() , но и для models.SlugField() … Так что это было для меня окончательное решение…

Комментарии:

1. добавьте полную трассировку ошибок

Ответ №1:

когда вы вызываете super() метод, вы не должны передавать self его в качестве параметра. Итак, вместо вашего текущего кода:

 def save_model(self, request, obj, form, change):
    super(PostAdmin, self).save_model(self, request, obj, form)
  

вы должны вызвать параметр super() without self в качестве параметра и добавить отсутствующий change в конце:

 def save_model(self, request, obj, form, change):
    super(PostAdmin, self).save_model(request, obj, form, change)
  

Комментарии:

1. Ну, да, это было глупо с моей стороны. Однако мой код по-прежнему не обладает нужной мне функциональностью. Теперь нет никакой ошибки, но форма администратора по-прежнему не позволяет мне сохранять. Я даже прокомментировал prepopulated_fields = {'slug': ('title',)} , было ли это причиной, но я получаю приглашение Enter a valid “slug”... перед выполнением obj.slug = slugify(obj.title, allow_unicode=True) . Итак, кажется, что есть другой метод, который я должен переопределить, но я не знаю, какой.

2. да, так оно и есть — всегда есть еще одна проблема во время разработки. Однако объединение этих проблем в нерелевантные вопросы с помощью комментариев на самом деле не сработает, поэтому я бы посоветовал вам открыть это как новый вопрос.