【问题标题】:Django admin choice fieldDjango 管理员选择字段
【发布时间】:2012-09-19 12:31:20
【问题描述】:

我有一个具有 CharField 的模型,我想在管理员中为小部件添加选择。原因是我使用的是代理模型,并且有很多模型共享这个 CharField,但它们每个都有不同的选择。

class MyModel(MyBaseModel):
    stuff = models.CharField('Stuff', max_length=255, default=None)

    class Meta:
        proxy = True

class MyModelAdmin(admin.ModelAdmin):
    fields = ('stuff',)
    list_display = ('stuff',)
admin.site.register(MyModel, MyModelAdmin)

对于这个模型,我想在MyModelAdmin 中使用MY_CHOICES

我是否覆盖小部件?我需要覆盖整个表单吗?

【问题讨论】:

    标签: django django-admin


    【解决方案1】:
    from django.contrib import admin
    from django import forms
    
    class MyModel(MyBaseModel):
        stuff = models.CharField('Stuff', max_length=255, default=None)
    
        class Meta:
            proxy = True
    
    class MyModelForm(forms.ModelForm):
        MY_CHOICES = (
            ('A', 'Choice A'),
            ('B', 'Choice B'),
        )
    
        stuff = forms.ChoiceField(choices=MY_CHOICES)
    
    class MyModelAdmin(admin.ModelAdmin):
        fields = ('stuff',)
        list_display = ('stuff',)
        form = MyModelForm
    
    admin.site.register(MyModel, MyModelAdmin)
    

    见:https://docs.djangoproject.com/en/dev/ref/forms/fields/#choicefield

    【讨论】:

    • 非常感谢,我正在浏览文档并错过了这个:S 没有办法避免创建 ModelForm 吗?
    • 只是检查一下,我认为可能有一个选项可以将其传递给字符域或作为元选项或其他东西。
    【解决方案2】:

    您可以覆盖formfield_for_choice_field(),这样您就无需创建新表单。

    class MyModelAdmin(admin.ModelAdmin):
        def formfield_for_choice_field(self, db_field, request, **kwargs):
            if db_field.name == 'status':
                kwargs['choices'] = (
                    ('accepted', 'Accepted'),
                    ('denied', 'Denied'),
                )
                if request.user.is_superuser:
                    kwargs['choices'] += (('ready', 'Ready for deployment'),)
            return super().formfield_for_choice_field(db_field, request, **kwargs)
    

    formfield_for_choice_field

    【讨论】:

      【解决方案3】:

      您不需要自定义表单。

      这是您需要的最低要求:

      # models.py
      from __future__ import unicode_literals
      
      from django.db import models
      
      class Photo(models.Model):
          CHOICES = (
              ('hero', 'Hero'),
              ('story', 'Our Story'),
          )
      
          name = models.CharField(max_length=250, null=False, choices=CHOICES)
      
      # admin.py
      from django.contrib import admin
      from .models import Photo
      
      
      class PhotoAdmin(admin.ModelAdmin):
          list_display = ('name',)
      
      
      admin.site.register(Photo, PhotoAdmin)
      

      【讨论】:

        【解决方案4】:

        您需要覆盖ModelAdmin 将使用的表单:

        class MyForm(forms.ModelForm):
            stuff = forms.CharField('Stuff', max_length=255, choices=MY_CHOICES, default=None)
        
            class Meta:
                model = MyModel
                fields = ('stuff', 'other_field', 'another_field')
        
        
        class MyModelAdmin(admin.ModelAdmin):
            fields = ('stuff',)
            list_display = ('stuff',)
            form = MyForm
        

        如果您需要动态选择,也许您可​​以执行以下操作:

        class MyForm(forms.ModelForm):
            stuff = forms.CharField('Stuff', max_length=255, choices=MY_CHOICES, default=None)
        
            def __init__(self, stuff_choices=(), *args, **kwargs):
                # receive a tupple/list for custom choices
                super(MyForm, self).__init__(*args, **kwargs)
                self.fields['stuff'].choices = stuff_choices
        

        并在您的ModelAdmin__init__ 中定义MY_CHOICES 将是什么并在那里分配表单实例:

        祝你好运! :)

        【讨论】:

        • 我认为 forms.CharField 就像 models.CharField 并且有选择选项。但我决定仔细检查,发现表单有 ChoiceField(见我的回答)。
        • 我要说:万分感谢!在任何地方都找不到根据表单的模型实例生成选择的解决方案。在这里,在 ModelForm 构造函数中,实例是可用的。
        【解决方案5】:

        Gerard's answer,如果你保留:

        def __init__(self, stuff_choices=(), *args, **kwargs):
        

        然后,当您尝试从管理员添加新模型时,您将始终得到“此字段为必填项”。所有必填字段。

        你应该从初始化中删除stuff_choices=()

        def __init__(self,*args, **kwargs):
        

        【讨论】:

          【解决方案6】:

          您需要考虑如何在数据库级别存储数据。 我建议这样做:

          1. 运行这个 pip 命令:pip install django-multiselectfield
          2. 在你的 models.py 文件中:

            from multiselectfield import MultiSelectField
            
            MY_CHOICES = (('item_key1', 'Item title 1.1'),
                      ('item_key2', 'Item title 1.2'),
                      ('item_key3', 'Item title 1.3'),
                      ('item_key4', 'Item title 1.4'),
                      ('item_key5', 'Item title 1.5'))
            
            class MyModel(models.Model):
                  my_field = MultiSelectField(choices=MY_CHOICES)
            
          3. 在你的 settings.py 中:

             INSTALLED_APPS = (
                  'django.contrib.auth',
                  'django.contrib.contenttypes',
                  'django.contrib.sessions',
                  'django.contrib.sites',
                  'django.contrib.admin',
            
                  #.....................#
            
                  'multiselectfield',
            )
            
          4. 观看魔法发生!

          来源:

          【讨论】:

            【解决方案7】:

            下面的解决方案可以立即与 Postgres 的特殊 ArrayField 一起工作:

            # models.py
            
            class MyModel(models.Model):
                class Meta:
                    app_label = 'appname'
            
                name = models.CharField(max_length=1000, blank=True)
              
                ROLE_1 = 'r1'
                ROLE_2 = 'r2'
                ROLE_3 = 'r3'
            
                ROLE_CHOICES = (
                    (ROLE_1, 'role 1 name'),
                    (ROLE_2, 'role 2 name'),
                    (ROLE_3, 'role 3 name'),
                )
            
                roles = ArrayField(
                    models.CharField(choices=ROLE_CHOICES, max_length=2, blank=True),
                    default=list
                )
            
            # admin.py
            
            class MyModelForm(ModelForm):
                roles = MultipleChoiceField(choices=MyModel.ROLE_CHOICES, widget=CheckboxSelectMultiple)
            
            
            @admin.register(MyModel)
            class MyModelAdmin(admin.ModelAdmin):
                form = MyModelForm
                list_display = ("pk", "name", "roles")
            

            (Django 2.2)

            【讨论】:

              猜你喜欢
              • 2015-06-17
              • 2023-02-19
              • 2014-11-26
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2021-03-03
              • 2012-01-12
              • 2019-05-31
              相关资源
              最近更新 更多