Как использовать меньше просмотров базы данных во время фильтра? - PullRequest
0 голосов
/ 22 октября 2019

У меня есть фрагмент кода, который выполняет несколько вызовов в БД, и я пытаюсь его оптимизировать. Есть ли способ избавиться от:

username = users.models.User.objects.filter(groups__name=group)

или ..

user_obj = users.models.User.objects.get(username=user)

или объединить их так, чтобы во время этой транзакции я выполнял поиск только одной базы данных вместо двух?

        for group in groups:
            username = users.models.User.objects.filter(groups__name=group)
            for user in username:
                form.instance.unread.add(user)
                user_obj = users.models.User.objects.get(username=user)
                user_obj.send_sms('memo')
                user_obj.send_email('memo')

Это то, что меня излишне беспокоит?

Ответы [ 2 ]

1 голос
/ 22 октября 2019

Все группы, соответствующие списку, могут быть извлечены первыми в одном запросе с помощью __in lookup.

Затем можно запросить пользователей в наборе запросов соответствующей группы, просматривая итоговый набор запросов группы.

group_qs = users.models.Group.objects.filter(name__in=groups)
users_qs = users.models.User.objects.filter(groups__in=group_qs)

for user in users_qs:
    form.instance.unread.add(user.username)
    user.send_sms('memo')
    user.send_email('memo')

Вы можете связать поиски по цепочке:

users_qs = users.models.User.objects.filter(groups__name__in=groups)
1 голос
/ 22 октября 2019

Объединение (из примера кода вопроса) не очень хорошая идея, его поиск в БД еще больше:

 for group in groups:
        username = users.models.User.objects.filter(groups__name=group)
        for user in username:  # <-- Hitting DB 
            form.instance.unread.add(user)
            user_obj = users.models.User.objects.get(username=user) # <-- DB hit again
            user_obj.send_sms('memo')
            user_obj.send_email('memo')

Итак, минимальная оптимизация, которую вы можете сделать, это сначала оценить набор запросов,затем выполните итерации по циклу:

for group in groups:
    username = list(users.models.User.objects.filter(groups__name=group))
    for user in username:
        form.instance.unread.add(user)
        user.send_sms('memo')
        user.send_email('memo')

Более подробную информацию можно найти в документации относительно того, как оцениваются наборы запросов.

И ИМХО, наиболее оптимальное решение выглядит следующим образом (Я избавился от цикла for):

for group in groups:
    users = users.models.User.objects.filter(groups__name=group)
    form.instance.unread.add(*users) # unpacking the queryset and passing it through add (m2m) method. Reference: https://stackoverflow.com/a/4959580/2696165
    send_sms('memo', users.values_list('phone_number'))  # you need to convert this method so that it is not attached to user object and can accept a list of phone numbers
    send_email('memo', users.values_list('email')) # you need to convert this method so that it is not attached to user object and can accept a list of emails
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...