简体   繁体   中英

Django prefetch_related multiple queries

I'm using prefetch_related to join three tables. Products, ProductPrices and ProductMeta . But besides I'm following the documentation, the debugger says that I'm using three queries instead of one (with joins)

Also this creates a second problem. Some products doesn't have prices in some countries because they are not avaliable there. But using this code, the product appears but with an empty price.

So, I'd like to exclude the products that doesn't have prices or meta . I'm doing something wrong?

This is my code:

prefetch_prices = Prefetch(
    'product_prices',
    queryset=ProductPrices.objects.filter(country=country_obj),
    to_attr='price_info'
)

prefetch = Prefetch(
    'product_meta',
    queryset=ProductMeta.objects.filter(language=lang),
    to_attr='meta_info'
)

products = Product.objects.prefetch_related(prefetch, prefetch_prices).all()

That produces these SQL Queries:

{   'sql': 'SELECT DISTINCT `products`.`id`, `products`.`image`, '
               '`products`.`wholesale_price`, `products`.`reference`, '
               '`products`.`ean13`, `products`.`rating`, `products`.`sales`, '
               '`products`.`active`, `products`.`active_in`, '
               '`products`.`encilleria`, `products`.`delivery`, '
               '`products`.`stock`, `products`.`ingredients`, ' 
               'FROM `products` WHERE `products`.`active` = 1 ',
        'time': '0.098'},
    {   'sql': 'SELECT `products_meta`.`id`, `products_meta`.`product_id`, '
               '`products_meta`.`name`, `products_meta`.`slug`, '
               '`products_meta`.`tagline`, `products_meta`.`key_ingredients`, '
               '`products_meta`.`ideal_for`, `products_meta`.`description`, '
               '`products_meta`.`advice`, `products_meta`.`summary`, '
               '`products_meta`.`language` FROM `products_meta` WHERE '
               "(`products_meta`.`language` = 'en' AND "
               '`products_meta`.`product_id` IN (52001, 51972, 52038, 52039, '
               '52040, 52041, 51947, 51948, 51949, 51950, 51951, 51953, 51954, '
               '51832))',
        'time': '0.096'},
    {   'sql': 'SELECT `products_prices`.`id`, `products_prices`.`product_id`, '
               '`products_prices`.`country_id`, `products_prices`.`price` FROM '
               '`products_prices` WHERE (`products_prices`.`country_id` = 1 '
               'AND `products_prices`.`product_id` IN (52001, 51972, 52038, '
               '52039, 52040, 52041, 51947, 51948, 51949, 51950, 51951, 51953, '
               '51954, 51832))',
        'time': '0.046'}

Thanks

From prefetch_related documentation

Returns a QuerySet that will automatically retrieve, in a single batch, related objects for each of the specified lookups.

As you can see from following explanation

prefetch_related , on the other hand, does a separate lookup for each relationship, and does the 'joining' in Python.

prefetch_related will do queries for each of tables and merge them in python

Additionally if you are having Foreign keys and not Many to Many you could use select_related instead

As @iklinac said, prefetch_related will do multiple queries and marge the results.

But if you want to "exclude the empty rows" or a functionality like INNER JOIN, you can do this:

You could do something like this:

a = ProductPrices.objects.filter(country=country_obj)
prefetch1 = Prefetch(
    'product_prices',
    queryset=a,
    to_attr='price_info'
)

b = ProductMeta.objects.filter(language=lang)
prefetch2 = Prefetch(
    'product_meta',
    queryset=b,
    to_attr='meta_info'
)

products = products.prefetch_related(prefetch1, prefetch2)
products = products.filter(id__in=a.values_list('product_id'))
products = products.filter(id__in=b.values_list('product_id'))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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