Django管理员选择字段

时间:2012-09-27 16:41:08

标签: django django-admin

我有一个具有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)

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

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

7 个答案:

答案 0 :(得分:18)

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

答案 1 :(得分: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的{​​{1}}中定义__init__将会是什么,并在那里指定表单实例:

祝你好运! :)

答案 2 :(得分:3)

您可以以不需要创建新表单的方式覆盖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 :(得分:2)

您不需要自定义表单。

这是您的最低要求:

# 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 :(得分:0)

Gerard's answer,如果你保留:

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

然后当您尝试从管理员添加新模型时,您将始终获得“此字段是必需的”。对于所有必填字段。

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

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

答案 5 :(得分:0)

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

  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. 观看MAGIC的发生!

  5. 来源:

答案 6 :(得分:0)

下面的解决方案可立即与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)