I'm wondering what's the best way to reduce the number of queries for looking up FK's?
As suggested by the docs, I'm not using Full=True.
However, that me, I currently need to make a separate query for each FK field in my model.
For example, say I have a resource, "Application", which links to several other tables - "Collocation", "Host", "Binary", etc. (there's quite a few others which are domain-specific).
If I look up a list of applications - say 20 of them - I then need to look up the separate collocations, hosts, binaries, and other tables associated with them - resulting in several hundred queries.
Hi Victor I learnt how to do this recently (also from this group) You just set queryset = select_related You can then use full=True with no additional DB hits too - very nice!
An example:
class PurchaseOptionResource(ModelResource): product_type = fields.ForeignKey('core.api.ProductTypeResource', 'product_type', full=True) class Meta: queryset = PurchaseOption.objects.select_related('product_type').all()
Results in one query with a join as you would expect from Django. You might already guess - you can also use prefetch_related in this way for non-FK relationships. Nice eh!
On Monday, 12 November 2012 12:15:40 UTC+11, Victor Hooi wrote:
> Hi,
> I'm wondering what's the best way to reduce the number of queries for > looking up FK's?
> As suggested by the docs, I'm not using Full=True.
> However, that me, I currently need to make a separate query for each FK > field in my model.
> For example, say I have a resource, "Application", which links to several > other tables - "Collocation", "Host", "Binary", etc. (there's quite a few > others which are domain-specific).
> If I look up a list of applications - say 20 of them - I then need to look > up the separate collocations, hosts, binaries, and other tables associated > with them - resulting in several hundred queries.
Nick - Thanks for the pointer. That's a neat trick.
However, I wonder if there's any way to do this without using full=True? Or are you required to use that if you want to use the select_related/prefetch_related behaviour?
I thought part of the point of Tasty-Pie is to make everything accessible via Resource URIs - I'm wondering if there's a way to pre-pull all of the related objects down so they're ready without needing to hit the database, but still have them accessible at the URIs.
On Friday, 16 November 2012 16:40:16 UTC+11, Nick Doyle wrote:
> Hi Victor > I learnt how to do this recently (also from this group) > You just set queryset = select_related > You can then use full=True with no additional DB hits too - very nice!
> An example:
> class PurchaseOptionResource(ModelResource): > product_type = fields.ForeignKey('core.api.ProductTypeResource', > 'product_type', full=True) > class Meta: > queryset = > PurchaseOption.objects.select_related('product_type').all()
> Results in one query with a join as you would expect from Django. > You might already guess - you can also use prefetch_related in this way > for non-FK relationships. > Nice eh!
> On Monday, 12 November 2012 12:15:40 UTC+11, Victor Hooi wrote:
>> Hi,
>> I'm wondering what's the best way to reduce the number of queries for >> looking up FK's?
>> As suggested by the docs, I'm not using Full=True.
>> However, that me, I currently need to make a separate query for each FK >> field in my model.
>> For example, say I have a resource, "Application", which links to several >> other tables - "Collocation", "Host", "Binary", etc. (there's quite a few >> others which are domain-specific).
>> If I look up a list of applications - say 20 of them - I then need to >> look up the separate collocations, hosts, binaries, and other tables >> associated with them - resulting in several hundred queries.
I am also currently optimizing DB queries. On top of the
select_related/prefetch_related for full=True stuff, I have this for ToOne
full=False, something similar could probably be done for ToMany
FakeModel = collections.namedtuple("FakeModel", "pk")
class YPToOneField(fields.ToOneField):
def dehydrate(self, bundle):
""" Patched to not load the related model when we only want a URI
note: this breaks support for callables and __ for non inlined
resources.
"""
if not self.full:
pk = getattr(bundle.obj, self.attribute + "_id", None)
if pk is not None:
foreign_obj = FakeModel(pk)
else:
foreign_obj = None
if not foreign_obj:
if not self.null:
raise ApiFieldError("The model '%r' has an empty
attribute '%s' and doesn't allow a null value." % (previous_obj, attr))
On Fri, Nov 16, 2012 at 7:28 AM, Victor Hooi <victorh...@gmail.com> wrote:
> Hi,
> Nick - Thanks for the pointer. That's a neat trick.
> However, I wonder if there's any way to do this without using full=True?
> Or are you required to use that if you want to use the
> select_related/prefetch_related behaviour?
> I thought part of the point of Tasty-Pie is to make everything accessible
> via Resource URIs - I'm wondering if there's a way to pre-pull all of the
> related objects down so they're ready without needing to hit the database,
> but still have them accessible at the URIs.
> Cheers,
> Victor
> On Friday, 16 November 2012 16:40:16 UTC+11, Nick Doyle wrote:
>> Hi Victor
>> I learnt how to do this recently (also from this group)
>> You just set queryset = select_related
>> You can then use full=True with no additional DB hits too - very nice!
>> An example:
>> class PurchaseOptionResource(**ModelResource):
>> product_type = fields.ForeignKey('core.api.**ProductTypeResource',
>> 'product_type', full=True)
>> class Meta:
>> queryset = PurchaseOption.objects.select_**
>> related('product_type').all()
>> Results in one query with a join as you would expect from Django.
>> You might already guess - you can also use prefetch_related in this way
>> for non-FK relationships.
>> Nice eh!
>> On Monday, 12 November 2012 12:15:40 UTC+11, Victor Hooi wrote:
>>> Hi,
>>> I'm wondering what's the best way to reduce the number of queries for
>>> looking up FK's?
>>> As suggested by the docs, I'm not using Full=True.
>>> However, that me, I currently need to make a separate query for each FK
>>> field in my model.
>>> For example, say I have a resource, "Application", which links to
>>> several other tables - "Collocation", "Host", "Binary", etc. (there's quite
>>> a few others which are domain-specific).
>>> If I look up a list of applications - say 20 of them - I then need to
>>> look up the separate collocations, hosts, binaries, and other tables
>>> associated with them - resulting in several hundred queries.
Also, there is a downside to the prefetch/related thing, tastypie uses the
same queryset when it needs the object for a modification, either on the
object or an object that has it as a ToOne field, so all that prefetch and
related stuff happens then as well, I haven't found a way around that yet.
On Fri, Nov 16, 2012 at 9:39 AM, Gordon Wrigley <gordon.wrig...@gmail.com>wrote:
> I am also currently optimizing DB queries. On top of the
> select_related/prefetch_related for full=True stuff, I have this for
> ToOne full=False, something similar could probably be done for ToMany
> FakeModel = collections.namedtuple("FakeModel", "pk")
> class YPToOneField(fields.ToOneField):
> def dehydrate(self, bundle):
> """ Patched to not load the related model when we only want a URI
> note: this breaks support for callables and __ for non inlined
> resources.
> """
> if not self.full:
> pk = getattr(bundle.obj, self.attribute + "_id", None)
> if pk is not None:
> foreign_obj = FakeModel(pk)
> else:
> foreign_obj = None
> if not foreign_obj:
> if not self.null:
> raise ApiFieldError("The model '%r' has an empty
> attribute '%s' and doesn't allow a null value." % (previous_obj, attr))
> On Fri, Nov 16, 2012 at 7:28 AM, Victor Hooi <victorh...@gmail.com> wrote:
>> Hi,
>> Nick - Thanks for the pointer. That's a neat trick.
>> However, I wonder if there's any way to do this without using full=True?
>> Or are you required to use that if you want to use the
>> select_related/prefetch_related behaviour?
>> I thought part of the point of Tasty-Pie is to make everything accessible
>> via Resource URIs - I'm wondering if there's a way to pre-pull all of the
>> related objects down so they're ready without needing to hit the database,
>> but still have them accessible at the URIs.
>> Cheers,
>> Victor
>> On Friday, 16 November 2012 16:40:16 UTC+11, Nick Doyle wrote:
>>> Hi Victor
>>> I learnt how to do this recently (also from this group)
>>> You just set queryset = select_related
>>> You can then use full=True with no additional DB hits too - very nice!
>>> An example:
>>> class PurchaseOptionResource(**ModelResource):
>>> product_type = fields.ForeignKey('core.api.**ProductTypeResource',
>>> 'product_type', full=True)
>>> class Meta:
>>> queryset = PurchaseOption.objects.select_**
>>> related('product_type').all()
>>> Results in one query with a join as you would expect from Django.
>>> You might already guess - you can also use prefetch_related in this way
>>> for non-FK relationships.
>>> Nice eh!
>>> On Monday, 12 November 2012 12:15:40 UTC+11, Victor Hooi wrote:
>>>> Hi,
>>>> I'm wondering what's the best way to reduce the number of queries for
>>>> looking up FK's?
>>>> As suggested by the docs, I'm not using Full=True.
>>>> However, that me, I currently need to make a separate query for each FK
>>>> field in my model.
>>>> For example, say I have a resource, "Application", which links to
>>>> several other tables - "Collocation", "Host", "Binary", etc. (there's quite
>>>> a few others which are domain-specific).
>>>> If I look up a list of applications - say 20 of them - I then need to
>>>> look up the separate collocations, hosts, binaries, and other tables
>>>> associated with them - resulting in several hundred queries.