Фильтрация и группировка в объектах модели Python после запроса к базе данных - PullRequest
0 голосов
/ 01 сентября 2018

У меня есть следующая модель:

class Item(models.Model):
    user = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True, null=True, related_name='item',on_delete=models.SET_NULL)
    email = models.BooleanField(blank=True, null=True)
    ..... 

Мне нужно отправить электронное письмо на адрес user, где атрибут Item email равен False.

У меня следующий запрос:

 items = Item.objects.filter(email=False)

Я хочу отфильтровать / сгруппировать элемент по пользователю. Я хочу сделать это python, потому что я хочу отправлять электронные письма с задержкой, а не перегружать базу данных сразу многими запросами.

Для каждого использования я хочу создать context словарь, который я могу отправить на электронную почту Django.

Псевдокод / ​​логика:

  user_context { 
      'subject' : 'some subject'}

 for item in items:
   if user is the same:
    user_context['content] = append item

    if finished same_user items:
      send_email(user_context)
      context = {} # reset context

1 Ответ

0 голосов
/ 01 сентября 2018

Вы можете использовать itertools.groupby, чтобы сгруппировать итерируемое в итерируемое из 2-х кортежей. Однако для эффективной обработки важно выполнить некоторую предварительную выборку (связанных) User объектов, например:

from operator import itemgetter
from itertools import groupby

qs = Item.objects.filter(email=False).order_by('user_id').prefetch_related('user')

result = [
    (k, list(vs))
    for k, v in groupby(qs, key=attrgetter('user'))
]

Теперь result представляет собой список из двух кортежей: первый элемент каждого кортежа содержит связанный объект User, второй элемент кортежа - список соответствующих объектов Itememail=False). User s без таких Item s будет не будет в списке.

Так что, если вы хотите отправить электронное письмо, вы можете перебрать список из двух кортежей, например:

for user, items in result:
    user_context { 
        'subject' : 'some subject'
    }
    user_context['content] = items
    send_email(user_context)

Если вы, однако, только вставлены в User s, где существует Item с email=False, то вам нужно только запросить:

User.objects.filter(<b>item__email=False</b>)
...