A
Okay no worries, thanks anyway!
A
Do you want me to raise an issue on Github for this?
Alexander
It will be part of migrations, probably not necessary to have a separate issue for that
A
👍
B
Hello. Is there a convenient way to specify a default value in Declaring Entity Class by Python function with Context? For example, in SQLAlchemy: def mydefault(context): return context.get_current_parameters()['counter'] + 12 t = Table('mytable', metadata_obj, Column('counter', Integer), Column('counter_plus_twelve', Integer, default=mydefault, onupdate=mydefault) ) Thank you.
Alexander
Hi! You can specify default for attribute, but default with context is not supported: def my_function(): return randint(0, 100) class MyEntity(db.Entity): my_attr = Required(int, default=my_function) onupdate for attribute is not supported, you can try to use hooks for this: https://docs.ponyorm.org/api_reference.html#entity-hooks class MyEntity(db.Entity): my_attr = Optional(int) before_insert(self): if self.my_attr is None: self.my_attr = ... before_update(self): self.my_attr = ... Context-Sensitive Default Functions look like an interesting idea, maybe Pony should have something like that
B
Let's suppose that I want to use table2 simply as a list of valid non-repeating values for some column in table1, and NOT NULL, so that the database does not allow adding an arbitrary value. But I do not need a one-to-one relationship, otherwise there will be too many records in table2. I've tried it in different ways, but the pony requires "specify both ends of a relationship" and binds a row to a row. For example: class Table1(db.Entity): id = PrimaryKey(int, auto=True) name = Required(str, unique=True) source = Required('Table2') class Table2(db.Entity): name = PrimaryKey(str, 10) table1 = Optional(Table1) Doesn't work like that: pony.orm.core.ConstraintError: Cannot unlink Users[1] from previous Auth_Sources['google'] object, because Users.source attribute is required
Alexander
Instead of table1 = Optional(Table1) it should be table1 = Set(Table1) because one source name can be used in multiple Table1 records
Solution
Solution
Am having issue with db_session is required when working with database
Solution
I used the example from the doc
Alexander
When you do something with Pony objects, you need to do it inside db_session. Like: with db_session: p1 = Person(name="John", age=20) db_session opens a connection to the database and handles transactions
Solution
Still throwing the same error
Solution
Wil9
Solution
Copy the code I paste down here
Alexander
probably you aren't wrap ALL lines when you work with objects with the db_session
Solution
from pony.orm import * from pony.py23compat import PY37 db = Database() class Person(db.Entity): name = Required(str) age = Required(int) cars = Set('Car') class Car(db.Entity): brand = Required(str) model = Required(str) owner = Required(Person) db.bind(provider='mysql', host='localhost', user='sqluser', passwd='Bayo4real', db='ponydb') db.generate_mapping(create_tables=True) set_sql_debug(True) p1 = Person(name='John', age=20) p2 = Person(name='Mary', age=30) p3 = Person(name='Mike', age=40) c1 = Car(brand='Ford', model='Focus', owner=p1) c2 = Car(brand='Audi', model='A4', owner=p2) c3 = Car(brand='BMW', model='X5', owner=p3) with db_session: p = Person(name='John', age=20) Car(make='Audi', model='A4', owner=p1) # commit() will be done automatically # database session cache will be cleared automatically # database connection will be returned to the pool
Alexander
with db_session should wrap ALL lines starting from p1 = Person(...)
Solution
👍
Solution
Got it
Solution
How can I use pony to map CSV file into database?
Alexander
Pony does not work with csv files, you need to use csv standard library to read csv file first, and then you can create Pony object for each csv row https://docs.python.org/3/library/csv.html
Solution
T hanks the first time in my history of coding I see a great community
B
I agree with great community!
Karsten
Hi community, I use pony in my application. There are often multiple instances of the application. Is there some way to notify all instances when a record has been inserted? Karsten
Alexander
No, pony does not have such notifications. You need to implement it yourself with something like Redis
B
I'm about using PonyORM with aiohttp. The StackOverflow site has an answer: https://stackoverflow.com/questions/64844557/what-s-the-right-way-to-use-ponyorm-with-fastapi "To be sure everything will be okay you should use db_session as the context manager and be sure that you don't have async calls inside this block of code." But, in PonyORM documentation I find this: https://docs.ponyorm.org/transactions.html#using-db-session-with-generator-functions-or-coroutines "If inside such a generator function or coroutine you’ll try to use the db_session context manager, it will not work properly, because in Python context managers cannot intercept generator suspension. Instead, you need to wrap you generator function or coroutine with the @db_session decorator." I'm really confused! I found the following solution: https://snorfalorpagus.net/blog/2020/05/10/threaded-workers-with-aiohttp/ Is it a good idea to wrap a function with a db_session as context manager to run_in_executor, like this? executor = ThreadPoolExecutor() def add_user(): with db_session: ... async def run(executor): loop = asyncio.get_event_loop() result = await loop.run_in_executor(executor, add_user) ... Maybe there is a better solution?
Alexander
I'm about using PonyORM with aiohttp. The StackOverflow site has an answer: https://stackoverflow.com/questions/64844557/what-s-the-right-way-to-use-ponyorm-with-fastapi "To be sure everything will be okay you should use db_session as the context manager and be sure that you don't have async calls inside this block of code." But, in PonyORM documentation I find this: https://docs.ponyorm.org/transactions.html#using-db-session-with-generator-functions-or-coroutines "If inside such a generator function or coroutine you’ll try to use the db_session context manager, it will not work properly, because in Python context managers cannot intercept generator suspension. Instead, you need to wrap you generator function or coroutine with the @db_session decorator." I'm really confused! I found the following solution: https://snorfalorpagus.net/blog/2020/05/10/threaded-workers-with-aiohttp/ Is it a good idea to wrap a function with a db_session as context manager to run_in_executor, like this? executor = ThreadPoolExecutor() def add_user(): with db_session: ... async def run(executor): loop = asyncio.get_event_loop() result = await loop.run_in_executor(executor, add_user) ... Maybe there is a better solution?
Pony support of db_session decorator for async functions is currently broken, you should not rely on it. You can use synchronous with db_session in async code if you never call await some_function inside it. Currently, Pony support of async frameworks is limited
Alexander
The same way as you created Person objects, but for your own entity class
Solution
>>> import csv >>> with open('names.csv', newline='') as csvfile: ... reader = csv.DictReader(csvfile) ... for row in reader: ... print(row['first_name'], row['last_name']) ... Eric Idle John Cleese >>> print(row) {'first_name': 'John', 'last_name': 'Cleese'}
Solution
alright thanks
B
Should I disconnect() db or others methods at the close of my program?
Alexander
It is not strictly necessary, I think. But if you use threads, you need to do db.disconnect() in thread before it finishes
B
Clearly, Thanks!
I do.
When will pony support async queries?
Alexander
When will pony support async queries?
Not soon, it requires massive refactoring of Pony internals
I do.
Ah ok, thanks.
Bob
hey all, I have a query issue I'm hoping to be able to figure out
Bob
I am trying to call db.select(blah blah blah) without making use of any entity classes
Bob
I have a constant PEOPLE which is a list of multiple names I would like my adapted tsql to look something like 'select * from txs where person in PEOPLE'
Bob
Why?
because entities and everything else in the db are defined in another repo that I'm not allowed to use for this use case
Volbil
Well, in that case you have to use raw SQL queries
Volbil
Pony require entity definitions in order to make queries
Bob
so I've tried db.select('select * from txs where person in $(PEOPLE)) but that tries to pass the list as an ARRAY rather than a list
Bob
Pony require entity definitions in order to make queries
this isn't always the case tho, is it? I've successfully done db.select(random query) without needing to use the entity classes before
Bob
maybe easiest solution is to copy pasta entity definition from the other repo. But that could cause future complications if the entity definition changes remotely
Volbil
You can make package containing entity definitions and use it on both projects
Bob
well ty for your help sir, Ill play around with this some more tonight
Bob
ooh good idea, I like that
Alexander
It is a bit tricky to create a list of parameters for a raw SQL query if you have a list of names names = ["John", "Mike"] It is not usually a good idea to directly inject names into a query SELECT * FROM txs WHERE person.name in ('John', 'Mike') because it can lead to SQL injection vulnerability. But you can create a query that looks like this: SELECT * FROM txs WHERE person.name in ($names[0], $names[1]) And it will be protected from SQL injections. To create such a query, you can do something like name_params = ', '.join('$name[%d]' % i for i in range(names)) sql_query = """ SELECT * FROM txs WHERE person.name in (%s) """ % name_params db.execute(sql_query) Also, note that if your function receives db object from another module, where entities are defined, you can access entity classes as attributes of db object. The import of entity classes is not necessary: select(p for p in db.Person if p.name in names)
Mattia
Hello exploring Pony I'm trying to add a column to the db proposed in the test example:
Mattia
class Person(db.Entity): name = orm.Required(str) age = orm.Required(int) cars = orm.Set('Car') test = orm.Optional(int) class Car(db.Entity): make = orm.Required(str) model = orm.Required(str) owner = orm.Required(Person)
Mattia
specifically I would like to add the test attribute to Person
Mattia
But when I launch db.generate_mapping() I would have expected to add the column to the db, while I get this error back: pony.orm.dbapiprovider.OperationalError: no such column: Person.test
Mattia
You would know which is the correct method for achieve this goal?
Volbil
You would know which is the correct method for achieve this goal?
You should manually update db schema via sql query
Mattia
Here because! Thanks so much 👍👍👍
Ben
Is there any reason doing orm.sum(x.amount for x in y) is significantly slower (by about 10x) than doing orm.select(x.amount for x in y).sum()
Ben
I'm very confused, is there a recommended way?
Alexander
It should produce the same query. If you perform these queries one after the another, the table rows and indexes will be cached in memory, and the second query execution should be significantly faster
Ben
hmm
Ben
that's probably why then, thanks!
Radim
Hey, any updates on Python3.10 support?
Alexander
It's almost done. Our checklist is now - one (known) bug - coverage check - make release text - publish it ETA before 9th Jan
Radim
sounds great! keep up the good work, thanks
Christian
Hi. I'm getting an error here in the last line, because self.user comes back as Multiset: TypeError: unsupported operand type(s) for +=: 'Multiset' and 'decimal.Decimal'. I'm being a little stupid - how can I get the connected user object, so I can work with it here?
Christian
class LoanEntry(db.Entity): user = Set(lambda: User) created = Required(datetime, default=datetime.utcnow) loan = Required(Decimal, precision=9, scale=2) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.update_total(self.loan) def update_total(self, loan): self.user.loan_total += loan
Christian
I'm trying to do the following: Every time a user adds a new loan, it creates a new LoanEntry and also adds the new loan to the total amount of money the user has loaned so far.