Am Samstag, 28. Juli 2012 14:04:29 UTC+2 schrieb akaariai: > > On 28 heinä, 12:20, sbrandt <s.brandt.ber...@googlemail.com> wrote: > > Hello, > > > > for the first time ever how to compile a query with the Django ORM :/ > > > > There are two Models: The second model has a foreign key to the first > model > > and a type, where the combination of "first model and second model's > type" > > is unique. Let's say type 1 are dogs, type 2 are cats and every model1 > can > > only have 0 or 1 dogs and cats. I know that it could have been > implemented > > as two seperate tables without types and one-to-ones, but I need to > query > > the whole model2 often and it's implemented in this way since years. > > > > This is not a problem for single model1 objects, since it's just a > second > > objects.get(...)-call as a lazy property in the model1. > > > > But now I need a query for *all* model1-objects with two additional > > columns: Has this model1 a cat, has this model1 a dog? > > > > Here's some code (Just pseudocode - doesn't work! My actual models would > be > > too complicated): > > > > class Model1(Model): > > name = CharField(...) > > > > m2types = (cats, dogs) > > > > class Model2(Model) > > m1 = ForeignKey(Model1) > > type = SmallIntegerField(..., choices=m2types) > > class Meta: > > unique_together = ('m1', 'type') > > > > In SQL I would do it with left outer joins: > > > > SELECT m1.id, m1.name, c.id, d.id > > FROM model1 AS m1 > > LEFT OUTER JOIN model2 AS c ON c.m1_id = m1.id AND c.type = 1 > > LEFT OUTER JOIN model2 AS d ON d.m1_id = m1.id AND d.type = 2; > > > > So, back to my questsion: Is this possible with the Django ORM without > > using raw SQL? > > > > Note: Speed is not important. Since it is a cronjob being done half a > year > > and my models are just hundrets, iterating over every model1 and using > the > > lazy property cat and dog would be okay, and also using raw SQL would be > > okay since I'm tied to PostgreSQL. I'm explicitly searching for an > elegant > > solution with the Django ORM. > > Hmmh, so you want to fetch every object, and "annotate" the > information about having a dog or a cat in the original model. I don't > think that can be done, although there might be some trick for this. > > What you could do is use the prefetch_related() method, and then do > the annotation in Python code. > > Something like this: > objs = Model1.objects.prefetch_related('model2_set') > > And in model1 you could have two properties, has_cat and has_dog > > class Model1: > ... > def _has_dog(self): > return any(obj for obj in self.model2_set if obj.type == DOG) > has_dog = property(_has_dog) > ... > > While this isn't elegant it gets the work done... If you need to > filter or do something else in the ORM with the has_dog information, > you will not be able to do this using the above idea. > > Django's ORM can be somewhat hard to use when working with reverse > foreign key data. There is room to improve the annotation mechanism of > Django. I hope the situation will improve... The prefetch_related > machinery has helped with many situations already. > > - Anssi >
Okay, so I'll take a closer look at prefetch_related. I didn't know one can prefetch the model_set. If I would have splitted up into one Dog and one Cat table using one-to-one to Model1, I could have just used select_related on the backwards relation. But I don't see any way to tell Django this is in fact a one-to-one relationship. -- You received this message because you are subscribed to the Google Groups "Django users" group. To view this discussion on the web visit https://groups.google.com/d/msg/django-users/-/KEAGQ2JQsSMJ. To post to this group, send email to django-users@googlegroups.com. To unsubscribe from this group, send email to django-users+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/django-users?hl=en.