2👍
As per the OP’s invitation, here’s an answer.
The core question is how to define an efficient permission check based on a highly relational data model.
The first variant involves building a Python list from evaluating a Django query set. The suspicion must certainly be that it imposes unnecessary computations on the Python interpreter. Although it’s not clear whether that’s tolerable if at the same time it allows for a less complex database query (a tradeoff which is hard to assess), the underlying DB query is not exactly simple.
The second approach involves fetching additional 1:1 data through relational lookups and then checking if there is any record fulfilling access criteria in a different, 1:n relation.
Let’s have a look at them.
bt_id = user.realtor.billing_tier.id
: This is required to get the hook for the following 1:n query. It is indeed highly inefficient in itself. It can be optimized in two ways.- As per Django: Access Foreign Keys Directly, it can be written as
bt_id = user.realtor.billing_tier_id
because theid
is of course present inbilling_tier
and needs not be found via a relational operation. - Assuming that the page in itself would only load a
user
object, Django can be told to fetch and cache relational data along with that viaselect_related
. So if the page does not only fetch theuser
object but the requiredbilling_tier_id
as well, we have saved one additional DB hit.
- As per Django: Access Foreign Keys Directly, it can be written as
BillingTier.objects.filter(id = bt_id).filter(plans__automatic_feedback=True).distinct()
can be optimized using Django’s exists because that will redurce efforts both in the database and regarding data traffic between the database and Python.- Maybe even Django’s
prefetch_related
can be used to combine the 1:1 and 1:n queries into a single query, but it’s much more difficult to judge whether that pays. Could be worth a try.
In any case, it’s worth installing a gem called Django Debug Toolbar which will allow you to analyze how much time your implementation spends on database queries.