views:

260

answers:

2

I have the following 2 models:

class Job(models.Model):
    title = models.CharField(_('title'), max_length=50)
    description = models.TextField(_('description'))
    category = models.ForeignKey(JobCategory, related_name='jobs')
    created_date = models.DateTimeField(auto_now_add=True)

class JobCategory(models.Model):
    title = models.CharField(_('title'), max_length=50)
    slug = models.SlugField(_('slug'))

Here is where I am at with the query thus far:

def job_categories():
    categories = JobCategory.objects.annotate(num_postings=Count('jobs'))
    return {'categories': categories}

The problem is that I only want to count jobs that were created in the past 30 days. I want to return all categories however, not only those categories that have qualifying jobs.

+3  A: 

Just a guess... but would this work?

def job_categories():
    thritydaysago = datetime.datetime.now - datetime.timedelta(days=30)
    categories = JobCategory.objects.filter(job__created_date__gte=thritydaysago).annotate(num_postings=Count('jobs'))
    return {'categories': categories}

See"lookups-that-span-relationships" for more details on spanning queries. Hmmm... probably need another query in there to get all categories...

monkut
This will return only the categories that have jobs created within the last 30 days. I'm also trying to avoid returning multiple querysets, as that defies the purpose of using annotations. This function actually exists as a templatetag, and I was hoping, at the template layer, to include the counts with each of the categories (even if the count is 0). Thank you though.
gsiegman
Yeah, I think your just going to have to perform two queries.
monkut
A: 

I decided to approach this differently and chose not to use annotations at all. I added a manager to the Job model that returned only active (30 days or less old) jobs, and created a property on the JobCategory model that queried for the instance's job count. My templatetag simply returned all categories. Here is the relevant code.

class JobCategory(models.Model):
    title = models.CharField(_('title'), max_length=50, help_text=_("Max 50 chars. Required."))
    slug = models.SlugField(_('slug'), help_text=_("Only letters, numbers, or hyphens. Required."))

    class Meta:
        verbose_name = _('job category')
        verbose_name_plural = _('job categories')

    def __unicode__(self):
        return self.title

    def get_absolute_url(self):
        return reverse('djobs_category_jobs', args=[self.slug])

    @property
    def active_job_count(self):
        return len(Job.active.filter(category=self))

class ActiveJobManager(models.Manager):
    def get_query_set(self):
        return super(ActiveJobManager, self).get_query_set().filter(created_date__gte=datetime.datetime.now() - datetime.timedelta(days=30))

class Job(models.Model):
    title = models.CharField(_('title'), max_length=50, help_text=_("Max 50 chars. Required."))
    description = models.TextField(_('description'), help_text=_("Required."))
    category = models.ForeignKey(JobCategory, related_name='jobs')
    employment_type = models.CharField(_('employment type'), max_length=5, choices=EMPLOYMENT_TYPE_CHOICES, help_text=_("Required."))
    employment_level = models.CharField(_('employment level'), max_length=5, choices=EMPLOYMENT_LEVEL_CHOICES, help_text=_("Required."))
    employer = models.ForeignKey(Employer)
    location = models.ForeignKey(Location)
    contact = models.ForeignKey(Contact)
    allow_applications = models.BooleanField(_('allow applications'))
    created_date = models.DateTimeField(auto_now_add=True)

    objects = models.Manager()
    active = ActiveJobManager()

    class Meta:
        verbose_name = _('job')
        verbose_name_plural = _('jobs')

    def __unicode__(self):
        return '%s at %s' % (self.title, self.employer.name)

and the tag...

def job_categories():
    categories = JobCategory.objects.all()
    return {'categories': categories}
gsiegman