Django 管理员预填充字段和字段集

发布于 2025-01-19 17:13:54 字数 1154 浏览 5 评论 0原文

我正在使用 Django 3.2

我有以下模型:

class Foo(models.Model):
    title = models.CharField()
    slug = models.SlugField()
    # remaining fields listed below

在管理管理器中,我有模型:

class FooAdmin(admin.ModelAdmin):
    fieldsets = [
        ('General', {
            'fields': [
                        'title',
                        'description',
                        'information',
                        'cover_photo',
                        'gallery', 
            ]

        }),
        ('Details', {
            'fields' : [
            'is_cancelled',
            'start',
            'finish',
            'video_url',
            ]

        }),
    ]
    
    prepopulated_fields = {'slug': ('title',), }


admin.site.register(Foo, FooAdmin)

当我尝试在管理管理器中创建新的 Foo 时,出现错误:

KeyError:“在“FooForm”中找不到键“slug”。选项包括:cover_photo、description、finish、gallery、information、is_cancelled、start、title、video_url。”

当我将 slug 字段添加到字段集列表中时,它可以工作,但是随后 slug 字段显示在表单上(我不想要)。

我知道我可以通过重写 Foo.save() 来解决这个问题,但我希望管理员为我处理这个问题。

那么,如何使用带有不应出现在表单上的预填充字段的字段集?

I am using Django 3.2

I have the following model:

class Foo(models.Model):
    title = models.CharField()
    slug = models.SlugField()
    # remaining fields listed below

In Admin manager, I have the model:

class FooAdmin(admin.ModelAdmin):
    fieldsets = [
        ('General', {
            'fields': [
                        'title',
                        'description',
                        'information',
                        'cover_photo',
                        'gallery', 
            ]

        }),
        ('Details', {
            'fields' : [
            'is_cancelled',
            'start',
            'finish',
            'video_url',
            ]

        }),
    ]
    
    prepopulated_fields = {'slug': ('title',), }


admin.site.register(Foo, FooAdmin)

When I attempt to create a new Foo in the admin manager, I get the error:

KeyError: "Key 'slug' not found in 'FooForm'. Choices are: cover_photo, description, finish, gallery, information, is_cancelled, start, title, video_url."

When I add the slug field to the list of fieldsets, it works, but then the slug field is shown on the form (which I don't want).

I know that I can solve this by overriding Foo.save(), but I want the admin manager to handle this for me.

So, how do I use fieldsets with prepopulated fields that are not supposed to appear on the form?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

关于从前 2025-01-26 17:13:54

您不能从管理字段中排除 slug,因为您将其包含在 prepopulated_fields 中。但是,您可以重写模型的保存方法,如下所示,以生成唯一 slug。您可以使用此保存方法创建通用 BaseModel,并每次都使用 slug 字段扩展您的模型:

from django.utils.text import slugify


def generate_unique_slug(klass, field):
    """
    return unique slug if origin slug is exist.
    eg: `foo-bar` => `foo-bar-1`

    :param `klass` is Class model.
    :param `field` is specific field for title.
    """
    origin_slug = slugify(field)
    unique_slug = origin_slug
    numb = 1
    while klass.objects.filter(slug=unique_slug).exists():
        unique_slug = "%s-%d" % (origin_slug, numb)
        numb += 1
    return unique_slug


class BaseModel(models.Model):
    class Meta:
        abstact = True

    def save(self, *args, **kwargs):
        if hasattr(self, "slug") and hasattr(self, "title"):
            if self.slug:
                if slugify(self.title) != self.slug:
                    self.slug = generate_unique_slug(self.__class__, self.title)
            else:  # create
                self.slug = generate_unique_slug(self.__class__, self.title)

        super().save(*args, **kwargs)


class Foo(BaseModel):
    title = models.CharField()
    slug = models.SlugField()
    # remaining fields listed below


class AnotherModelWithSlug(BaseModel):
    title = models.CharField()
    slug = models.SlugField()

You cannot exclude slug from admin fields since you are including it in prepopulated_fields. However, you can override your model's save method like below to generate a unique slug. You can make general BaseModel with this save method and extend your models with slug fields everytime:

from django.utils.text import slugify


def generate_unique_slug(klass, field):
    """
    return unique slug if origin slug is exist.
    eg: `foo-bar` => `foo-bar-1`

    :param `klass` is Class model.
    :param `field` is specific field for title.
    """
    origin_slug = slugify(field)
    unique_slug = origin_slug
    numb = 1
    while klass.objects.filter(slug=unique_slug).exists():
        unique_slug = "%s-%d" % (origin_slug, numb)
        numb += 1
    return unique_slug


class BaseModel(models.Model):
    class Meta:
        abstact = True

    def save(self, *args, **kwargs):
        if hasattr(self, "slug") and hasattr(self, "title"):
            if self.slug:
                if slugify(self.title) != self.slug:
                    self.slug = generate_unique_slug(self.__class__, self.title)
            else:  # create
                self.slug = generate_unique_slug(self.__class__, self.title)

        super().save(*args, **kwargs)


class Foo(BaseModel):
    title = models.CharField()
    slug = models.SlugField()
    # remaining fields listed below


class AnotherModelWithSlug(BaseModel):
    title = models.CharField()
    slug = models.SlugField()
箜明 2025-01-26 17:13:54

您可以覆盖管理员的表单:

from django.utils.text import slugify  


class FooAdmin(admin.ModelAdmin):
    fieldsets = [
        ('General', {
            'fields': [
                        'title',
                        'description',
                        'information',
                        'cover_photo',
                        'gallery', 
            ]
        }),
        ('Details', {
            'fields' : [
            'is_cancelled',
            'start',
            'finish',
            'video_url',
            ]
        }),
    ]
   
    def get_form(self, request, obj=None, change=False, **kwargs):
       OriginalForm = super().get_form(request, obj, change, **kwargs)

       class Form(OriginalForm):
          def save(self, commit=True):
             instance = super().save(commit=False)
             instance.slug = slugify(instance.title)  # Here
             if commit:
                instance.save()
             return instance

       return Form

正如您所说,最好(也是最简单)的解决方案是覆盖模型的 save 方法。

You can override the form of the admin:

from django.utils.text import slugify  


class FooAdmin(admin.ModelAdmin):
    fieldsets = [
        ('General', {
            'fields': [
                        'title',
                        'description',
                        'information',
                        'cover_photo',
                        'gallery', 
            ]
        }),
        ('Details', {
            'fields' : [
            'is_cancelled',
            'start',
            'finish',
            'video_url',
            ]
        }),
    ]
   
    def get_form(self, request, obj=None, change=False, **kwargs):
       OriginalForm = super().get_form(request, obj, change, **kwargs)

       class Form(OriginalForm):
          def save(self, commit=True):
             instance = super().save(commit=False)
             instance.slug = slugify(instance.title)  # Here
             if commit:
                instance.save()
             return instance

       return Form

As you said the best (and simplest) solution would be to override the save method of the model.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文