Sqlalchemy AttributeError: 'property' object has no attribute 'translate'

Clash Royale CLAN TAG#URR8PPP
Sqlalchemy AttributeError: 'property' object has no attribute 'translate'
Situation
Users make purchases, which are stored as transactions in 3 different tables (depending on the type). I need to calculate total amount of transactions/purchases of female and male users, so I need to look into all 3 tables.
For this I created a @property in the User table:
@property
@property
def count_credits_purchases(self):
trans = object_session(self).query(Transaction_1).filter(Transaction_1.type == "credits").with_parent(self).count()
trans_vk = object_session(self).query(Transaction_2).filter(Transaction_2.type == "credits").with_parent(self).count()
trans_stripe = object_session(self).query(Transaction_3).filter(Transaction_3.type == "credits").with_parent(self).count()
value = trans + trans_vk + trans_stripe
return int(value)
I am trying to calculate the total amount of purchases by using sqlalchemy func.sum():
func.sum()
total_purchases_males_credits = db_session.query(func.sum(Users.count_credits_purchases))
.filter(Users.date_added >= start_date, Users.date_added <= end_date, Users.gender == "1")
.scalar()
Problem
AttributeError: 'property' object has no attribute 'translate'
The translate method is a string method, what is happening here? I definitely return an integer in count_credits_purchases.
count_credits_purchases
I made a test and checking the value per user is always correct:
all_users = db_session.query(Users).limit(200)
for user in all_users:
print (user.count_credits_purchases) # gives correct result
I could make a variable and calculate it in the loop, but it is super unefficient and would need probably 1 hour if there are 50k users. I need to understand how to work with the @property attribute
@property
hybrid_property
@vishes_shell I am currently experimenting with column_property, next will be hybrid_property
– Roman
Aug 10 at 9:16
2 Answers
2
As the docs Using Descriptors and Hybrids says you should be using hybrid_property to be able to use them in your queries.
hybrid_property
Take a look at example in docs:
class EmailAddress(Base):
__tablename__ = 'email_address'
id = Column(Integer, primary_key=True)
# name the attribute with an underscore,
# different from the column name
_email = Column("email", String)
# then create an ".email" attribute
# to get/set "._email"
@property
def email(self):
return self._email
While our EmailAddress object will shuttle the value through the email descriptor and into the _email mapped attribute, the class level EmailAddress.email attribute does not have the usual expression semantics usable with Query. To provide these, we instead use the hybrid extension
EmailAddress
EmailAddress.email
hybrid
Thanks for the reply. Already two people telling me to try @hybrid_property. I was currently trying to use column_property but I switch to hybrid now. It doesn't work right of the bat:
sqlalchemy.orm.exc.UnmappedInstanceError: Class 'sqlalchemy.ext.declarative.api.DeclarativeMeta' is not mapped; was a class (stats_models.Users) supplied where an instance was required? But I try to figure it out, thanks– Roman
Aug 10 at 9:24
sqlalchemy.orm.exc.UnmappedInstanceError: Class 'sqlalchemy.ext.declarative.api.DeclarativeMeta' is not mapped; was a class (stats_models.Users) supplied where an instance was required?
If you have the time, check my answer please. Is the normal method a viable solution here? I have problems to make hybrid_method work.
– Roman
Aug 10 at 10:08
The best solution here is probably using @hybrid_property but I had problems to make it work.
@hybrid_property
I came up with a completely different solution, using a classical method. This was super fast and so far I dont see any downsides:
# Normal method to calculate | Best case would probably be @hybrid_method
def count_credits_purchases(self, start_date, end_date, gender):
trans = db_session.query(Transaction_1).filter(Transaction_1.type == "credits", Transaction_1.user_id == Users.id).filter(Users.date_added >= start_date, Users.date_added <= end_date, Users.gender == gender).count()
trans_vk = db_session.query(Transaction_2).filter(Transaction_2.type == "credits", Transaction_2.user_id == Users.id).filter(Users.date_added >= start_date, Users.date_added <= end_date, Users.gender == gender).count()
trans_stripe = db_session.query(Transaction_3).filter(Transaction_3.type == "credits", Transaction_3.user_id == Users.id).filter(Users.date_added >= start_date, Users.date_added <= end_date, Users.gender == gender).count()
value = trans + trans_vk + trans_stripe
return value
Call in python:
total_purchases_males_credits = Users().count_credits_purchases(start_date, end_date, "1")
I would still like to know how good ths approach is compared to hybrid_property?
EDIT:
Its also possible to use @hybrid_method:
@hybrid_method
@hybrid_method
def count_credits_purchases(self, start_date, end_date, gender):
trans = db_session.query(Transaction_1).filter(Transaction_1.type == "credits", Transaction_1.user_id == Users.id).filter(Users.date_added >= start_date, Users.date_added <= end_date, Users.gender == gender).count()
trans_vk = db_session.query(Transaction_2).filter(Transaction_2.type == "credits", Transaction_2.user_id == Users.id).filter(Users.date_added >= start_date, Users.date_added <= end_date, Users.gender == gender).count()
trans_stripe = db_session.query(Transaction_3).filter(Transaction_3.type == "credits", Transaction_3.user_id == Users.id).filter(Users.date_added >= start_date, Users.date_added <= end_date, Users.gender == gender).count()
value = trans + trans_vk + trans_stripe
return value
And use it:
total_purchases_males_credits = db_session.query(func.sum(Users.count_credits_purchases(start_date, end_date, "1"))).scalar()
The problem is pretty much specific (so i cannot dive in it completely), and as well it works for you, and is fast enough, then it is a problem solver. Good work!
– vishes_shell
Aug 11 at 18:24
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
Shouldn't you be using
hybrid_property?– vishes_shell
Aug 10 at 9:12