简体   繁体   English

如何在关系数据库中存储智能列表规则

[英]How to store smart-list rules in a relational database

The system I'm building has smart groups. 我正在建立的系统有智能组。 By smart groups, I mean groups that update automatically based on these rules: 智能组是指基于以下规则自动更新的组:

  1. Include all people that are associated with a given client. 包括与给定客户关联的所有人员。
  2. Include all people that are associated with a given client and have these occupations. 包括与给定客户关联并具有这些职业的所有人员。
  3. Include a specific person (ie, by ID) 包括特定的人(即通过ID)

Each smart groups can combine any number of these rules. 每个智能组可以组合任意数量的这些规则。 So, for example, a specific smart list might have these specific rules: 因此,例如,特定的智能列表可能具有以下特定规则:

  1. Include all people that are associated with client 1 包括与客户端1关联的所有人员
  2. Include all people that are associated with client 5 包括与客户5关联的所有人员
  3. Include person 6 包括人6
  4. Include all people associated with client 10, and who have occupations 2, 6, and 9 包括与客户10关联的所有人员,以及具有职业2,6和9的人员

These rules are OR'ed together to form the group. 这些规则被组合在一起形成组。 I'm trying to think about how to best store this in the database given that, in addition to supporting these rules, I'd like to be able to add other rules in the future without too much pain. 我正在考虑如何在数据库中最好地存储它,因为除了支持这些规则之外,我希望将来能够添加其他规则而不会有太多痛苦。

The solution I have in mind is to have a separate model for each rule type. 我想到的解决方案是为每种规则类型设置一个单独的模型。 The model would have a method on it that returns a queryset that can be combined with other rules' querysets to, ultimately, come up with a list of people. 该模型将有一个方法,它返回一个查询集,可以与其他规则的查询集结合,最终得出一个人的列表。 The one downside of this that I can see is that each rule would have its own database table. 我可以看到的一个缺点是每个规则都有自己的数据库表。 Should I be concerned about this? 我应该关注这件事吗? Is there, perhaps, a better way to store this information? 是否有更好的方法来存储这些信息?

Why not use Q objects ? 为什么不使用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)

and then store their pickled strings into the database. 然后将他们的pickle字符串存储到数据库中。

rule = rule1 | rule2 | rule3 | rule4
pickled_rule_string = pickle.dumps(rule)
Rule.objects.create(pickled_rule_string=pickled_rule_string)

Here are the models we implemented to deal with this scenario. 以下是我们为处理此方案而实施的模型。

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)

At first I was resistant to this solution as I didn't like the idea of storing references to other objects in a CharField (CharField was selected, because it is the most versatile. Later on, we might have a rule that matches any person whose first name starts with 'Jo'). 起初我对这个解决方案有抵触,因为我不喜欢在CharField中存储对其他对象的引用的想法(CharField被选中,因为它是最通用的。后来,我们可能有一个规则匹配任何人的名字以'Jo'开头)。 However, I think this is the best solution for storing this kind of mapping in a relational database. 但是,我认为这是在关系数据库中存储此类映射的最佳解决方案。 One reason this is a good approach is that it's relatively easy to clean hanging references. 这是一个很好的方法的一个原因是清理悬挂引用相对容易。 For example, if a company is deleted, we only have to do: 例如,如果公司被删除,我们只需要:

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

If the parameters were stored as serialized objects (eg, Q objects as suggested in a comment), this would be a lot more difficult and time consuming. 如果参数存储为序列化对象(例如,评论中建议的Q对象),则这将更加困难且耗时。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM