16

次のようなビットフィールドが定義されたデータモデルがあります。

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) 検索リストはどうですか? モデル内に各ビットを表す関数を作成することはできますが、検索と並べ替えはどのように行うのでしょうか?

私はDjangoが初めてです。

4

4 に答える 4

6

ここでの最善の解決策は、サブクラス化して新しいフィールドタイプを作成することだと思いますmodels.Fieldchoicesパラメーターを使用して、有効なビットフラグとその意味を割り当てることができます。これにより、モデル宣言をクリーンで読みやすくし、次のような最終結果を得ることができます。

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のドキュメントには、モデルのサブクラス化を行う方法に関する詳細な記事があります。フィールド:

カスタムモデルフィールドの作成
これには、次のようなすべての作業が含まれているようです。

サブクラス化されたフィールドの例を探している場合は、このスニペットが役立つ可能性があります。その目標は似ていますが(モデルフィールドとして複数の選択肢があります)、データベースに保存する方法が異なります(ビットフラグの代わりにCSVテキストフィールドを使用しています)。

于 2010-08-16T05:09:40.797 に答える
6

モデルにすぐに適合しない場合でも、テスト済みの優れたソリューションは、django-bitfieldを使用することです。

于 2013-05-02T19:27:54.940 に答える
5

Andrew's answer のスニペットに取り組んで、行う必要がある変更は次のとおりです。

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)
于 2010-08-16T15:30:04.343 に答える
1

これは、User クラスでフラグを使用する方法です。

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]

もちろん、フラグを出力する代わりに、カンマ区切りの文字列を作成して管理ビューに表示することも、必要に応じて何でも行うこともできます。

管理者の場合は、各グループ値にブール値を使用してください。

于 2010-08-20T13:33:51.793 に答える