Manuel Santi
Manuel Santi

Reputation: 1132

Add a django model method result as a field in an ORM query

I create a djngo model with two methods for do some stuff like thisone:

class Scaling(models.Model):
    id = models.AutoField(primary_key=True)
    description = models.TextField(default='', verbose_name="Description", null=True, blank=True)
    input_low = models.FloatField()
    input_high = models.FloatField()
    output_low = models.FloatField()
    output_high = models.FloatField()
    limit_input = models.BooleanField()

    def __str__(self):
        if self.description:
            return self.description
        else:
            return str(self.id) + '_[' + str(self.input_low) + ':' + \
                   str(self.input_high) + '] -> [' + str(self.output_low) + ':' \
                   + str(self.output_low) + ']'

    def scale_value(self, input_value):
        input_value = float(input_value)
        if self.limit_input:
            input_value = max(min(input_value, self.input_high), self.input_low)
        norm_value = (input_value - self.input_low) / (self.input_high - self.input_low)
        return norm_value * (self.output_high - self.output_low) + self.output_low

    def scale_output_value(self, input_value):
        input_value = float(input_value)
        norm_value = (input_value - self.output_low) / (self.output_high - self.output_low)
        return norm_value * (self.input_high - self.input_low) + self.input_low

Ok so now i would use my instance methods calculation in a complex django query as normal field as, for example:

 var_results = VarsResults.objects.filter(
    id_res__read_date__range=(start_d, end_d),
    id_res__proj_code=pr_code,
    var_id__is_quarterly=False
).select_related(
    "id_res",
    "var_id",
    "scaling_id"
).values(
    "id_res__read_date",
    "id_res__unit_id",
    "id_res__device_id",
    "id_res__proj_code",
    "var_val",
    <scale_output_value(scaling instance_id)>
)

how can i use model method return value as a column in a queryset?

So many thanks in advance Manuel

Upvotes: 0

Views: 725

Answers (1)

Carlos Carvalheira
Carlos Carvalheira

Reputation: 146

I have some ideas to solve this problem.

One is using a @property decorator. The scale_output_value in this case will be function only as a property of the model. The downside of this is the value of scale_output_value will be NOT stored on the database(on the model table). But can be accessed by calling the model instances or in Serializers fields.

@property
def scale_output_value(self, input_value):
        input_value = float(input_value)
        norm_value = (input_value - self.output_low) / (self.output_high - self.output_low)
        return norm_value * (self.input_high - self.input_low) + self.input_low

Other way is Overriding the save method from a model. Will declare normally the fields.

scale_value = models.FloatField()

def save(self, *args, **kwargs):
    #.... do your math here
    #.... self.scale_value....
    super(Scaling, self).save(*args, **kwargs)

Upvotes: 1

Related Questions