Defining virtual fields in peewee

Suppose I have a peewee model that looks more or less like this:

class MyModel(peewee.Model): a = peewee.IntegerField() b = peewee.IntegerField() 

And I want to add a property to this model as follows:

  @property def diff(self): return self.a - self.b 

It is useful sometimes; now if Object is an instance of MyModel , I can easily check its diff for Object.diff .

What I cannot do is the following:

 objects = list(MyModel.select().where(MyModel.diff < 17)) 

And this is because MyModel.diff is a simple property and probably always greater than 17. This is not Expression , like MyModel.a < 17 .

It would be nice to set diff as if it were a field; therefore, the user of this API will not need to know if a particular implementation a and b real fields and diff as virtual fields, or rather, a and diff as real fields and b as virtual.

Of course, my real intention is to use properties that in some cases include much more complex calculations presented on diff ; example:

 @property def complicated_property(self): if 17 <= self.a <= 173: return a_complicated_math_function(self.a + self.b) return another_complicated_math_function(self.a * self.b ** 2) 

On the other hand, it can be a very simple property, such as

 @property def seven(self): return 7 

This means that it cannot be converted to SQL at all, but must filter the results after they are received from the database.

Is it possible?

Update

I just opened the peewee playhouse hybrid methods / properties. They provide a partial solution to my question.

For example, my diff method could become hybrid_property and work as expected. My complicated_property cannot become one or at least looks like it; the if condition at the beginning will return either True or False continuously and will not act as a function.

Peewee probably has some more magic tricks; I will continue to search and report on my findings.

+5
source share
1 answer

It looks like hybrid_property will be what you are looking for. Here is the documentation on hybrid methods

As for your update, if you just read a little further in the docs ...

 @hybrid_property def radius(self): return abs(self.length) / 2 @radius.expression def radius(cls): return fn.ABS(cls.length) / 2 

So you see two functions for the same property, radius . The first function will be called when the model instance is called. The second when called in the request.

You can write:

 @hybrid_property def complicated_property(self): if 17 <= self.a <= 173: return a_complicated_math_function(self.a + self.b) return another_complicated_math_function(self.a * self.b ** 2) @complicated_property.expression def complicated_property(cls): # Here you will need to use a CASE statement most likely. # If you want to turn it into SQL, you obviously need to know # what SQL you want to turn it into... return case( None, (cls.a.between(17, 173), fn.math(fn.more_math(cls.a, 1.23))), default=fn.another_complicated_math(cls.a)) 
+4
source

Source: https://habr.com/ru/post/1235472/


All Articles