I made a simple django migration that adds two field to our Invoices model : first_payment
and first_paying_month
.
first_payment
is obvious : is this the user's first payment, first_paying_month
answers to the question: Was this payment made in the same month as the first payment, I'd love a more obvious name for this field.
The values for these fields used to be computed dynamically but now we need them all the time for performance reasons.
The schema part of the migration in handled by Django so there's not much to show. But I'd like inputs on this script, I'm mostly looking for performance optimizations but I'm really open to any feedback :)
from django.db.models import Count
from wallet.models import Invoice
from account.models import User
def set_first_payment_flags(): # We don't use a RunPython for out-of-scope reasons
users_by_invoice_count = User.objects.annotate(Count("invoice"))
users_with_one_invoice = users_by_invoice_count.filter(
invoice__count=1
).values_list("id", flat=True)
users_with_many_invoice = users_by_invoice_count.filter(
invoice__count__gt=1
)
Invoice.objects.filter(user__id__in=users_with_one_invoice).update(
first_payment=True, first_paying_month=True
)
invoices_to_save = []
for user in users_with_many_invoices:
# This part has a lot of queries and I'd like to reduce them but I could'nt find anything.
# I don't see how to reference the first field of a relation in an F expression.
first_invoice = user.invoice_set.order_by("date_created").first()
first_invoice.first_payment = True
invoices_to_save.append(first_invoice)
user.invoice_set.filter(
date_created__month=first_invoice.date_created.month
).update(first_paying_month=True)
Invoice.objects.bulk_update(invoices_to_save, fields=["first_payment"])