I need to update fields for a whole users table. It is stated in the docs that I shouldn't iterate through all table records. But to calculate a new field value I need to perform calculations using loops, user's relations and other complex logic relied on a concrete model.
I tried to include this calculations in the model's property, but I got:
peewee.InterfaceError: Error binding parameter 0 - probably unsupported type.
Atomic update:
query = User.update(balance=(User.balance + User.partners_reward))\
.where(User.deposit >= 3)
Model:
class User(peewee.Model):
deposit = peewee.DecimalField(default=0)
balance = peewee.DecimalField(default=0)
@property
def partners(self):
query = (
User.select(User, Partnership)
.join(Partnership, JOIN.INNER, on=Partnership.invited)
.where(Partnership.referral == self.id)
)
partners = query.execute()
return partners
@property
def partners_reward(self):
partners = self.partners
sum_reward = 0
partner_reward = 0.02
for partner in partners:
reward = partner.deposit * partner_reward
sum_reward += reward
return sum_reward
Prop description:
Each user has partners (other users invited by him) and depending on them he gets bonuses. So to accomplish the update I need to collect user partners using relations and then calculate the actual bonus using loops.
Changing property to a method solves this, but I don't know how I can get access to a concrete user instance.
So how can some complex logic be implemented in atomic updates or should I do it using loop as not recommended?
You can use a subquery. If I understand your query example correctly, it's just the sum of each partner deposit * .02?
subq = (Partnership
.select(fn.COALESCE(fn.SUM(Partnership.deposit * .02)))
.where(Partnership.referral == User.id))
res = (User
.update(reward=subq)
.execute())
What the above query does is, for each user, it selects all the partnership rows associated with the user, and sums the partnership deposit * .02 and stores the result in the user's "reward" column (assuming such a column existed). The "COALESCE()" bit is to handle the case where a user has no partner, so as to return 0 instead of null.
If you wished to increment the user's balance instead:
subq = (Partnership
.select(fn.COALESCE(fn.SUM(Partnership.deposit * .02)))
.where(Partnership.referral == User.id))
res = (User
.update(balance=User.balance + subq)
.execute())