Looking for best practices for Django queries in Python classes

Say I have a Django model Model1 and I have a python class Class1. Class1 has some properties that are derived from values in Model1. What is the best way to accomplish this? Gain access to Mode1 in the Class1 __init__ method, or access Model1 in the Class1 property? Not sure how to define "best way" - more pythonic, more efficient, etc?

A very contrived example of what I am asking:

class Model1(models.Model):
    model_id = models.AutoField(primary_key=True)
    field1 = models.CharField()
    field2 = models.CharField()

class Class1:
    def __init__(self, value1, value2):
        self.value1 = value1
        self.value2 = value2
        self._model1 = Model.objects.get(model_id=self.value1)

    @property
    def value3(self):
        return self._model1.field1 * 10

    @property
    def value4(self):
        field2 = Model.objects.get(model_id=self.value2).field2
        return field2 * 22

Which paradigm is "better" - the property for value4 or value3?

I am going to guess the the property for value4 is more efficient because the Model1 query set does not hang around in memory as it does when it is contained in the Class1 __init__.

Thanks!

It's not at all obvious why Class1 is necessary. For many (not all) purposes one would define methods/ properties on the Model1 class. (See also Django proxy models)

Otherwise, __init__ to get _model1 if this instance will always be used and if it should persist as long as the Class1 instance does. Obtain from the DB as needed in a Class1 property if that property or those properties won't always be used, or if up to date values from the DB are needed every time the property value is called for.

It's also possible to make _model into a property which queries the DB to obtain and cache, say, self._model_instance. This way you get the best of both of the above (but maybe harder to debug if the get fails).

@property
def _model1( self):
    if not hasattr( self, '_model1_instance'):
        self._model1_instance = Model.objects.get(model_id=self.value1)
    return self._model1_instance

Avoiding unnecessary DB accesses is normally a far more significant gain than any fine details of Python coding.

There's a smaller efficiency gain if you don't create an entire model instance but retrieve only the fields you are interested in from the DB. See Django queryset .values() and .values_list(). You can likewise cache the results of such a query.

Back to Top