在Django Managers中进行非外键连接

时间:2014-04-03 14:43:33

标签: django left-join

我有两个Django模型:

class Person(CommonModel):
    """ Person """
    person_type = models.ForeignKey(PersonType)
    ciam_id = models.PositiveIntegerField()  # ForeignKey('ciam.person_id')
    first_name = models.CharField(max_length=50)
    last_name = models.CharField(max_length=50)
    middle_name = models.CharField(max_length=50)
    empl_id = models.CharField(max_length=8)
    pcn = models.CharField(max_length=50)
    ...

class PositionHierarchy(CommonModel):
    """ Position Hierarchy  """
    pcn = models.CharField(max_length=50)
    title = models.CharField(max_length=100)
    level = models.CharField(max_length=25)
    reports_to_pcn = models.CharField(max_length=50, db_index=True)  # FK?

不幸的是,由于我无法控制的原因(并且超出理由),判断一个人是否是经理的唯一方法是查看Person.pcn,使用它通过pcn查找他们的PositionHierarchy,然后查看他们在PositionHierarchy中的级别。同样,找出他们的经理名字(我需要很多)的唯一方法是使用他们的Person.pcn,通过pcn查找他们的PositionHierarchy,通过reports_to_pcn查找他们的经理的PositionHierarchy,然后使用该pcn查找经理的人事记录。并且这些PCN中的任何一个都不允许被PositionHeirarchy模型的外键替换。多么令人费解的混乱,对吗?

所以我需要能够快速查找一个人,并查看他们的级别和经理姓名。

1 个答案:

答案 0 :(得分:0)

该解决方案是基于this blog post的自定义管理器:

class PersonWithManagerManager(CommonManager):
    """ Manager to get a query that adds the level and manager name
    to the person record """
    def get_query_set(self):
        qs = super(PersonWithManagerManager, self).get_query_set()
        cp_tab = qs.query.get_initial_alias()
        # Join to the PCN table to find the position
        pcn_tab = qs.query.join(
            (
                cp_tab,
                PositionHierarchy._meta.db_table,
                'pcn',
                'pcn'
            ), promote=True)
        # Find the manager's PCN
        man_pcn_tab = qs.query.join(
            (
                pcn_tab,
                PositionHierarchy._meta.db_table,
                'reports_to_pcn',
                'pcn'
            ), promote=True)
        # Find the manager's person record
        man_per_tab = qs.query.join(
            (
                man_pcn_tab,
                'cart_person',
                'pcn',
                'pcn'
            ), promote=True)
        return qs.extra(
            select={
                'level': '%s.level' % pcn_tab,
                'manager_last_name': '%s.last_name' % man_per_tab,
                'manager_first_name': '%s.first_name' % man_per_tab,
            }
        )

现在我可以print Person.extra_objects.filter(last_name='Tomblin').manager_last_name获取经理的姓氏。我还做不到的一件事是过滤它们。