Solution 1:

I used the F() and ExpressionWrapper, Am I doing a query on the database

sem_score = Enrollment.objects.all().update(
    sem_score=ExpressionWrapper(
        (F("prelim_score") + F("midterm_score") + F("final_score")) / 3,
        output_field=IntegerField(),
    )
)

Some important notes to consider with the above:

  1. Querysets are lazy, meaning they don't do anything until they are evaluated.
  2. F() expressions (and ExpressionWrapper) are for defining expressions that are executed by the database, rather than in-memory by Python. Django creates an expression as part of its query that is sent to the database; it is never evaluated by or even returned to Django.
  3. When you call .update on the queryset returned from .all(), it will immediately evaluate the queryset and perform the update. That's when the query (along with your expressions) are sent to the DB and the DB evaluates the expression on the database server.

So, to answer your question directly: no, calling F() or ExpressionWrapper(), alone, does not query the database. Once django does talk to the database, it sends along your expression to be evaluated by the DB. The expression evaluation takes place strictly on the database, not in Python.

Also, because your model fields referenced in the F() expressions are all of the same type, you do not need the ExpressionWrapper:

sem_score = Enrollment.objects.all().update(
    sem_score=(F("prelim_score") + F("midterm_score") + F("final_score")) / 3
)