代码之家  ›  专栏  ›  技术社区  ›  Dagg Nabbit

如何在django admin中表示位标志int字段?

  •  15
  • Dagg Nabbit  · 技术社区  · 14 年前

    我有一个数据模型,其中的位域定义如下:

    alter table MemberFlags add column title varchar(50) not null default '';
    alter table MemberFlags add column value integer( 3) not null default 0;
    
    insert into MemberFlags (title, value) values
        ("Blacklisted",             1),
        ("Special Guest",           2),
        ("Attend Ad-hoc Sessions",  4),
        ("Attend VIP Sessions",     8),
        ("Access Facility A",      16),
        ("Access Facility B",      32)
    

    像这样使用:

    alter table Membership add column title varchar(50) not null default '';
    alter table Membership add column flags integer( 3) not null default 0;
    
    insert into Membership (title, flags) values
        ("Guest Pass",          4+2 ),
        ("Silver Plan",    16+  4   ),
        ("Gold Plan",   32+16+  4+2 ),
        ("VIP Pass",    32+16+8+4+2 )
    

    我的问题是:

    a)在管理站点中将不同的位标志表示为单独的项目最简单的方法是什么?我应该重写模板,还是对表单做些什么?

    b)搜索列表如何?我可以在模型中创建表示每一位的函数,但是如何进行搜索和排序呢?

    我刚认识姜戈。

    4 回复  |  直到 9 年前
        1
  •  5
  •   rz.    13 年前

    根据安德鲁答案中的一小段内容,您需要做以下更改:

    from django.db import models
    from django import forms
    
    class BitFlagFormField(forms.MultipleChoiceField):
        widget = forms.CheckboxSelectMultiple
    
        def __init__(self, *args, **kwargs):
            super(BitFlagFormField, self).__init__(*args, **kwargs)
    
    class BitFlagField(models.Field):
        __metaclass__ = models.SubfieldBase
    
        def get_internal_type(self):
            return "Integer"
    
        def get_choices_default(self):
            return self.get_choices(include_blank=False)
    
        def _get_FIELD_display(self, field):
            value = getattr(self, field.attname)
            choicedict = dict(field.choices)
    
        def formfield(self, **kwargs):
            # do not call super, as that overrides default widget if it has choices
            defaults = {'required': not self.blank, 'label': capfirst(self.verbose_name), 
                        'help_text': self.help_text, 'choices':self.choices}
            if self.has_default():
                defaults['initial'] = self.get_default()
            defaults.update(kwargs)
            return BitFlagFormField(**defaults)
    
        def get_db_prep_value(self, value):
            if isinstance(value, int):
                return value
            elif isinstance(value, list):
                return sum(value)
    
        def to_python(self, value):
            result = []
            n = 1
            while value > 0:
                if (value % 2) > 0:
                    result.append(n)
                n *= 2
                value /= 2
            return sorted(result)
    
    
        def contribute_to_class(self, cls, name):
            super(BitFlagField, self).contribute_to_class(cls, name)
            if self.choices:
                func = lambda self, fieldname = name, choicedict = dict(self.choices):" and ".join([choicedict.get(value,value) for value in getattr(self,fieldname)])
                setattr(cls, 'get_%s_display' % self.name, func)
    
        2
  •  5
  •   Sar009    9 年前

    我认为这里最好的解决方案是通过子类化创建一个新的字段类型 models.Field . 你可以利用 choices 指定有效位标志及其含义的参数。这将有助于保持模型声明的整洁和可读性,最终结果如下:

    class BitFlagField(models.Field):
    
        ...
    
    class MyModel(models.Model):
    
        ...
    
        FLAG_CHOICES = (
            (1, 'Blacklisted'),
            (2, 'Special Guest'),
            (4, 'Attend Ad-hoc Sessions'),
            (8, 'Attend VIP Sessions'),
            (16, 'Access Facility A'),
            (32, 'Access Facility B'),
        )
        flags = BitFlagField(choices=FLAG_CHOICES)
    
       ...
    

    Django文档中有一篇关于如何对模型进行子类化的深入文章。field:

    Writing Custom Model Fields
    它似乎涵盖了你需要做的一切,包括:

    如果要查找子类字段的示例, this snippet 可能有用。它的目标是相似的(作为模型字段有多个选项),但是它在数据库中存储它们的方式不同(它使用的是csv文本字段而不是位标志)。

        3
  •  3
  •   fixmycode    11 年前

    一个很好的测试解决方案,即使它不适合您的模型,将使用 django-bitfield

        4
  •  1
  •   Wayne Werner    14 年前

    这是我将如何在用户类中使用标志:

    FLAGS = {
        1:"Blacklisted",
        2:"SpecialGuest",
        4:"AttendAd-hocSessions",
        8:"AttendVIPSessions",
        16:"AccessFacilityA",
        32:"AccessFacilityB",
    }
    
    class User(object):
        def __init__(self, name="John Doe", groups=0):
            self.name = name
            self.groups = groups
        def memberof(self):
            ''' Display string representation of the groups. '''
            for flag in sorted(FLAGS):
                if (flag & self.groups) == flag:
                    print FLAGS[flag]
    

    当然,您可以创建一个逗号分隔的字符串来显示在管理视图中,或者您想要的任何内容,而不是打印标志。

    对于管理员,只需使用 boolean 对于每个组值。

    推荐文章