FieldError:不能为 Post 模型表单指定“已创建”,因为它是不可编辑的字段

Posted

技术标签:

【中文标题】FieldError:不能为 Post 模型表单指定“已创建”,因为它是不可编辑的字段【英文标题】:FieldError: 'created' cannot be specified for Post model form as it is a non-editable field 【发布时间】:2020-10-22 23:24:16 【问题描述】:

Django 3.0.8

admin.py

class PostAdmin(admin.ModelAdmin):
    list_display = ("id", "title", 'category',)

    def get_fields(self, request, obj=None):
        fields = [a_field.name for a_field in self.model._meta.fields]
        return fields

    def get_readonly_fields(self, request, obj):
        readonly_fields = self.readonly_fields
        if obj:
            if obj.already_published and (not request.user.has_perm('posts.change_already_puclished')):
                readonly_fields = READONLY_FIELDS_AFTER_PUBLISHING

        return readonly_fields

追溯

Exception Type: FieldError
Exception Value:    
'created' cannot be specified for Post model form as it is a non-editable field. Check fields/fieldsets/exclude attributes of class PostAdmin.

本地变量

Variable    Value
change  
False
defaults    
'exclude': None,
 'fields': ['id',
            'comment',
            'title',
            'slug',
            'description',
            'body',
            'draft',
            'already_published',
            'featured_image',
            'category',
            'excerpt',
            'h1',
            'author',
            'created',
            'updated',
            'sidebar',
            'keywords',
            'lsi',
            'google_indexed',
            'google_first_indexed',
            'yandex_indexed',
            'yandex_first_indexed'],
 'form': <class 'django.forms.widgets.ModelForm'>,
 'formfield_callback': functools.partial(<bound method BaseModelAdmin.formfield_for_dbfield of <posts.admin.PostAdmin object at 0x7f1d596e3820>>, request=<WSGIRequest: GET '/admin/posts/post/add/'>)
exclude 
None
excluded    
None
fields  
['id',
 'comment',
 'title',
 'slug',
 'description',
 'body',
 'draft',
 'already_published',
 'featured_image',
 'category',
 'excerpt',
 'h1',
 'author',
 'created',
 'updated',
 'sidebar',
 'keywords',
 'lsi',
 'google_indexed',
 'google_first_indexed',
 'yandex_indexed',
 'yandex_first_indexed']
form    
<class 'django.forms.widgets.ModelForm'>
kwargs  

new_attrs   
'declared_fields': 
obj 
None
readonly_fields 
()
request 
<WSGIRequest: GET '/admin/posts/post/add/'>
self    
<posts.admin.PostAdmin object at 0x7f1d596e3820>

同图:

我使用超级用户和没有 change_already_pucliished 权限的用户尝试此代码。

    超级用户:尝试添加或更改帖子时,出现错误。 普通用户:添加帖子正常,没有错误。但添加新姿势会导致此错误。

编辑

class Post(DraftMixin,
       TitleMixin,
       TagMixin,
       SlugMixin,
       DescriptionMixin,
       CommentMixin,
       FeaturedImageMixin,
       BodyMixin,
       models.Model):
category = models.ForeignKey(Category,
                             on_delete=models.PROTECT,
                             verbose_name="Категория")

excerpt = models.TextField(default=True,
                           blank=True,
                           verbose_name="Выдержка") # A text associated to a Post. Most of the time, it is used as the Post summary.
h1 = models.CharField(max_length=500,
                      blank=True,
                      default="",
                      verbose_name="H1")
author = models.ForeignKey(Author,
                           blank=True,
                           null=True,
                           on_delete=models.PROTECT,
                           related_name='blog_posts',
                           verbose_name="Автор")

created = models.DateField(auto_now_add=True,
                           verbose_name="Дата создания")
updated = models.DateField(auto_now=True,
                           verbose_name="Дата обновления")

sidebar = models.ForeignKey(Sidebar,
                            null=True,
                            blank=True,
                            on_delete=models.PROTECT,
                            verbose_name="Сайдбар")

keywords = models.TextField(blank=True, default="", verbose_name="Ключевые слова")
lsi = models.TextField(blank=True, default="", verbose_name="LSI")

google_indexed = models.BooleanField(verbose_name="Индексировано Google",
                                     default=False)
google_first_indexed = models.DateField(blank=True,
                                        null=True,
                                        verbose_name="Дата первой индексации Google")

yandex_indexed = models.BooleanField(verbose_name="Индексировано Яндекс",
                                     default=False)
yandex_first_indexed = models.DateField(blank=True,
                                        null=True,
                                        verbose_name="Дата первой индексации Яндексом")

class Meta:
    ordering = ('-created',)
    verbose_name = "Статья"
    verbose_name_plural = "Статьи"
    permissions = [
        ("change_already_puclished", 'Может менять статус "Уже опубликовано"'),
    ]

【问题讨论】:

您能否提供您的 Post 模型的代码 【参考方案1】:

问题是由这个定义引起的:

created = models.DateField(auto_now_add=True,
                           verbose_name="Дата создания")

auto_now_add 使 Django 无法编辑它。所以不能将其指定为可编辑的表单域。

您需要将其指定为只读字段。见:Django admin: How to display a field that is marked as editable=False' in the model?

【讨论】:

【参考方案2】:

如果您将auto_now_add 设置为True,则默认情况下该字段将变为不可编辑(editable=False),Django 将自动处理该字段。此外,auto_now=True 将导致对任何更改的覆盖,因为当您在实例上调用 save() 时,它将更新该字段。

您可以通过将这些字段添加到readonly_fields 来添加要在表单中显示的字段,但您不能添加/编辑它们。现在你要么必须删除 auto_now_addauto_now 并为它们提供你的价值,要么你应该让 Django 为你做这件事。

Django 文档:DateField.auto_now_add

【讨论】:

以上是关于FieldError:不能为 Post 模型表单指定“已创建”,因为它是不可编辑的字段的主要内容,如果未能解决你的问题,请参考以下文章

在 Django 1.5 自定义用户模型中使用电子邮件作为用户名字段导致 FieldError

如何将 django 表单输入转换为 python 数据?

来自模型的输入未包含在表单 POST 数据中

Asp.net Mvc post表单提交多个实体模型

Django POST 不调用视图

form表单提交file文件传输失败