Извлекайте несколько объектов из нескольких категорий (многие ко многим из них) более djangoish способом - PullRequest
2 голосов
/ 15 января 2012

Я занимаюсь разработкой системы рассылки новостей. В этой системе есть Newslettercategories и Newsletterabos (говорят подписки), которые имеют отношение многих ко многим. Рассмотрим эти две модели:

class NewsletterCategory(models.Model):
    title = models.CharField(max_length=255, unique=True)
    slug = models.SlugField(max_length=255, unique=True)
    is_active = models.BooleanField(default=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        ordering=['title']

    def __unicode__(self):
        return self.title


class NewsletterAbo(models.Model):
    abo_id = models.CharField(max_length=255, unique=True)
    first_name = models.CharField(max_length=255, unique=False)
    last_name = models.CharField(max_length=255, unique=False)
    email = models.EmailField(max_length=75, unique=False)
    is_active = models.BooleanField(default=False)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    categories = models.ManyToManyField(NewsletterCategory, blank=True)

    class Meta:
        ordering=['last_name']

    def __unicode__(self):
        return (self.last_name + ', ' +self.first_name)

Теперь представьте, что я хочу разослать новостной бюллетень нескольким категориям новостных рассылок, при этом новостные рассылки не отправляются на один адрес электронной почты несколько раз. Это может произойти, если один NewsletterAbo находится в нескольких категориях Newsletter. До сих пор я собираю Abos, я хочу отправлять письма подобным этому (избегая дубликатов):

# get all NewsletterCategories that are active, 
categories = NewsletterCategory.objects.filter(is_active=True)
# initialize empty list for storing NewsletterAbos
abolist = []
# loop through retrieved NewsLetterCategories
for cat in categories:
    # get NewsletterAbos that are related to a NewsletterCategory
    abos = cat.newsletterabo_set.filter(is_active=True)
    # add retrieved NewsletterAbos to list
    abolist += abos
# removing duplicate entries
abolist = set(abolist)

# ... do something else then like sending out newsletter to abolist subscriptions

Abolist - это теперь список предметов без дубликатов. У меня такой вопрос: есть ли более «django-ish» способ сделать это, используя ORM.

Любая помощь приветствуется.

UPDATE: С помощью ответа lazerscience я нашел следующий код, который соответствует моим потребностям:

qs=NewsletterAbo.objects.filter(categories__is_active=True, 
                                categories__id__in=[1,2,3,4], 
                                is_active=True).distinct()

Эта строка кода возвращает все информационные бюллетени, которые мне нужны. Новый qs хранит этот список (если честно, это набор запросов) из тех предметов, которые я ранее хранил в abolist.

Спасибо:)!

1 Ответ

1 голос
/ 15 января 2012

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

qs = NewsletterAbo.objects.filter(categories_set__is_active=True)
qs = qs.values_list('email', flat=True).distinct()

Это даст вам полный список уникальных адресов электронной почты при обращении к базе данных только один раз.Посмотрите документацию на django для получения дополнительной информации о distinct() и values() / values_list().

...