3

私が構築しているシステムには、スマートグループがあります。スマートグループとは、次のルールに基づいて自動的に更新されるグループを意味します。

  1. 特定のクライアントに関連付けられているすべての人を含めます。
  2. 特定のクライアントに関連付けられ、これらの職業を持つすべての人を含めます。
  3. 特定の人を含める(つまり、IDで)

各スマートグループは、これらのルールをいくつでも組み合わせることができます。したがって、たとえば、特定のスマートリストには次の特定のルールがあります。

  1. クライアント1に関連付けられているすべての人を含める
  2. クライアント5に関連付けられているすべての人を含める
  3. 人6を含める
  4. クライアント10に関連し、職業2、6、および9を持っているすべての人を含めます

これらのルールはOR化されてグループを形成します。これらのルールをサポートするだけでなく、将来的にはそれほど苦労せずに他のルールを追加できるようにしたいと考えているので、これをデータベースに最適に保存する方法を考えています。

私が考えている解決策は、ルールタイプごとに個別のモデルを用意することです。モデルには、他のルールのクエリセットと組み合わせて最終的に人のリストを作成できるクエリセットを返すメソッドがあります。私が見ることができるこれの1つの欠点は、各ルールが独自のデータベーステーブルを持っていることです。私はこれについて心配する必要がありますか?おそらく、この情報を保存するためのより良い方法はありますか?

4

2 に答える 2

0

なぜQ オブジェクトを使用しないのですか?

rule1 = Q(client = 1)
rule2 = Q(client = 5)
rule3 = Q(id = 6)
rule4 = Q(client = 10) & (Q(occupation = 2) | Q(occupation = 6) | Q(occupation = 9))

people = Person.objects.filter(rule1 | rule2 | rule3 | rule4)

次に、ピクルス化された文字列をデータベースに保存します。

rule = rule1 | rule2 | rule3 | rule4
pickled_rule_string = pickle.dumps(rule)
Rule.objects.create(pickled_rule_string=pickled_rule_string)
于 2013-01-15T10:03:43.717 に答える
0

このシナリオに対処するために実装したモデルを次に示します。

class ConsortiumRule(OrganizationModel):
    BY_EMPLOYEE = 1
    BY_CLIENT = 2
    BY_OCCUPATION = 3
    BY_CLASSIFICATION = 4
    TYPES = (
        (BY_EMPLOYEE, 'Include a specific employee'),
        (BY_CLIENT, 'Include all employees of a specific client'),
        (BY_OCCUPATION, 'Include all employees of a speciified  client ' + \
            'that have the specified occupation'),
        (BY_CLASSIFICATION, 'Include all employees of a specified client ' + \
            'that have the specified classifications'))

    consortium = models.ForeignKey(Consortium, related_name='rules')
    type = models.PositiveIntegerField(choices=TYPES, default=BY_CLIENT)
    negate_rule = models.BooleanField(default=False,
        help_text='Exclude people who match this rule')


class ConsortiumRuleParameter(OrganizationModel):
    """ example usage: two of these objects one with "occupation=5" one
    with "occupation=6" - both FK linked to a single Rule
    """

    rule = models.ForeignKey(ConsortiumRule, related_name='parameters')
    key = models.CharField(max_length=100, blank=False)
    value = models.CharField(max_length=100, blank=False)

最初は、他のオブジェクトへの参照を CharField に格納するという考えが気に入らなかったので、この解決策には抵抗がありました (最も用途が広いため、CharField が選択されました。名は「じょう」で始まります)。ただし、この種のマッピングをリレーショナル データベースに格納するには、これが最適なソリューションだと思います。これが良いアプローチである理由の 1 つは、ぶら下がっている参照をきれいにするのが比較的簡単だからです。たとえば、会社が削除された場合、次のことを行うだけで済みます。

ConsortiumRuleParameter.objects.filter(key='company', value=str(pk)).delete()

パラメータがシリアル化されたオブジェクト (たとえば、コメントで提案されている Q オブジェクト) として格納されている場合、これははるかに困難で時間がかかります。

于 2013-01-16T19:05:15.803 に答える