danielrvt
danielrvt

Reputation: 10916

Django - Filter objects older than X days

I need to filter objects older than X number of days. I realize this question exists here: django filter older than day(s)?

However, I not trying to do exactly that, since the number of days, in my case lives inside the model:

class Post(models.Model):
    title = models.CharField(max_length=200)
    description = models.CharField(max_length=500)
    createdAt = models.DateTimeField(default=datetime.now, blank=True)
    plan = models.ForeignKey(Plan) # This model has the number of days

This is the query I have so far:

EDIT: I changed the days.plan part for the_post.plan.days Meaning that the number of days that I'm using to compare is in each post's plan field.

    Post.objects.filter(createdAt__lte=datetime.now() - timedelta(days=the_post.plan.days))

Note the plan.days part of the query. How can I reference the_post.plan.days for this query? Is it possible?

Upvotes: 4

Views: 2480

Answers (3)

jatinderjit
jatinderjit

Reputation: 1399

Assuming Postgres database:

table_post = Post._meta.db_table
table_plan = Plan._meta.db_table

old_posts = Post.objects.select_related('plan')\
            .extra(where=["%s.created_at <= NOW() - INTERVAL '1 day' * %s.days"
                          % (table_post, table_plan)])

Upvotes: 1

lucasnadalutti
lucasnadalutti

Reputation: 5948

With a small tweak in your Plan model, it is indeed possible to do what you want.

First of all, you'll need to change your Plan days field, which is probably an IntegerField, to DurationField.

Now the catch is that we have to use ExpressionWrapper to achieve the exact same result inside Postgres as the result you'd achieve in Python if you were to get the plan in a separate query.

Finally, your query should be something like:

from django.db.models import F, ExpressionWrapper, DateTimeField
from django.utils import timezone

Post.objects.annotate(target_date=ExpressionWrapper(timezone.now() - F('plan__days'), output_field=DateTimeField())).filter(createdAt__lte=F('target_date'))

Upvotes: 2

user2693928
user2693928

Reputation:

For me you must first grab the plan object.

plan = Plan.objects.filter(...)

and then reference the days

 Post.objects.filter(createdAt__lte=datetime.now() - timedelta(days=plan.days))

Upvotes: 0

Related Questions