开发者

Django query optimization: find a list of objects based on a many-to-one to a many-to-many

开发者 https://www.devze.com 2023-03-13 21:13 出处:网络
I have an ugly loop that is operating as a band-aid in Django that I\'d like to optimize into a join. I\'ve broken it down to the most basic structure to help simplify the problem. I\'m hoping someone

I have an ugly loop that is operating as a band-aid in Django that I'd like to optimize into a join. I've broken it down to the most basic structure to help simplify the problem. I'm hoping someone else has run into something 开发者_如何学Golike this before -- if not, I'll share the answer when I finally fix it.

To summarize

  • Object A has a non-symmetrical, many-to-many relationship with itself.
  • Object B has a many-to-one relationship with Object A.
  • Given an ObjectB, I need a set of other ObjectBs that are the children of the ObjectAs that are associated with our ObjectB's parent ObjectA.

I'm sure someone with more database experience could phrase that better (leave a comment if you have a better description of this association).

Here is a bare bones example of the structure I'm working with in Django, and the sort of loop that's running:

class ObjectA(models.Model):
    object_a_rules = models.ManyToManyField("self", symmetrical=False, through='ObjectARule')

class ObjectARule(models.Model):
    object_a_one = models.ForeignKey(ObjectA, related_name="object_a_before")
    object_a_two = models.ForeignKey(ObjectA, related_name="object_a_after")

class ObjectB(models.Model):
    object_a_association = models.ForeignKey(ObjectA)

    def that_annoying_loop_i_mentioned(self):
        object_a_rules_list = ObjectARule.objects.filter(object_a_one = self.object_a_association)
        #A list of all of the ObjectARules that have the ObjectA this ObjectB is associated with
        #as the first half of the many-to-many relationship.

        object_b_list = ObjectB.objects.all()
        #A list of all of the ObjectBs, may also be a filtered list

        for object_a_rule in object_a_rules_list:
            for object_b in object_b_list:
                if (object_a_rule.object_a_two == object_b.object_a_association):
                #if the second half of ObjectARule is the ObjectA of
                #the ObjectB in this list, then do something with that ObjectB.
                pass

How could Django get a list of ObjectBs through a join, so this painfully inefficient loop wouldn't have to run?


Given an ObjectB, I need a set of other ObjectBs that are the children of the ObjectAs that are associated with our ObjectB's parent ObjectA.

If objb is the ObjectB you are given, you could do this as follows:

objects = ObjectB.objects.filter(object_a_association__object_a_rules=objb.object_a_association)

or alternatively,

objects = ObjectB.objects.filter(object_a_association__object_a_rules__objectb_set=objb)

See also Lookups that span relationships

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号