When you filter a queryset, you're AND-ing the keyword arguments together. Q objects allow Django developers to perform lookups with OR. Q objects can be combined together with &, representing AND, or |, representing OR.

Let's look at an example query.

today_and_yesterday_prices = TickerPrice.objects.filter(
    models.Q(close_date=today) | models.Q(close_date=yesterday)
)

In this query, we're fetching the ticker prices with close dates of today or yesterday. We wrap our close_date keyword arguments with a Q object and join them together with the OR operator, |.

We can also combine the OR and AND operators.

today_and_yesterday_greater_than_1000 = TickerPrice.objects.filter(
    models.Q(price__gt=1000),
    (models.Q(close_date=today) | models.Q(close_date=yesterday)),
)

For this query, we're getting all prices with a close date of today or yesterday with a price greater than 1000. By default, Q objects, similar to keyword arguments, are AND-ed together.

We can also use the ~ operator to negate Q objects.

today_and_yesterday_greater_than_1000_without_BRK = (
    TickerPrice.objects.filter(
        models.Q(price__gt=1000),
        ~models.Q(ticker__symbol__startswith="BRK"),
        (models.Q(close_date=today) | models.Q(close_date=yesterday)),
    )
)

In this query, we're fetching all ticker prices greater than 1000 that don't start with BKKwith close dates of either today or yesterday. We added the condition that the ticker's symbol does not start with BRK (Berkshire Hathaway), which will exclude those from the query.