Anonymous
like this
Alexander
class MyEntity(db.Entity): _table_ = 'real_table_name'
Anonymous
thank you very mucjh
Anonymous
ForeignKeyField(column_name='user_id_id') can I do smth like this
Anonymous
And If I write foreign key . Is it mandatory to write optional in another table ?
Alexander
class Message(db.Entity): id = PrimaryKey(int, auto=True) text = Required(str) user = Required("User", column='user_id') # <- this class User(db.Entity): id = PrimaryKey(int, auto=True) name = Required(str) messages = Set("Message") Message.user and User.messages are two attributes which form a relationship. Message.user is attribute which is based on foreign key column, and on the other side usually there is a Set attribute (because one user can be related to multiple messages)
Anonymous
Does it matter Set("Message") and Set(Message)
Alexander
Without quotes, Message should be defined earlier
Anonymous
column='user_id' this column name should be written due to model that made with Pony or my column name in server ?
Alexander
Pony right now use the same name for column as for attribute (that is, user in this case). In future releases we plan to change it to user_<name_of_User_pk> by default So if you want to connect to existing table you need to name column user_id explicitly
Anonymous
Thanks, You are creator of Pony ?
Alexander
yes
Anonymous
It is really fast.That's why we chose this.
Anonymous
class UsersUser(db.Entity): date_joined = Required(datetime) email = Required(str,unique=True) is_active = Required(int) is_staff = Required(int) is_superuser = Required(int) last_login = Optional(datetime) name = Optional(str) password = Required(str) score_card_id=Set('ScorecardScorecard') _table_ = 'users_user' class ScorecardScorecard(db.Entity): add_date = Required(datetime) delete_date = Optional(datetime) deleted = Required(int) description = Required(str) max_score = Required(Decimal) min_score = Required(Decimal) name = Required(str) update_date = Required(datetime) user_id= Required("UsersUser",column='user_id_id')
Anonymous
is something wrong here ?
Alexander
- duplicate identifiers looks weird (UsersUser, ScorecardScorecard, user_id_id) - score_card_id, according to its name, is definitely not Set (should be Required or Optional)
Jacob
Pony expects that concurrent requests are processed in transactions, each parallel transaction decorated with db_session, and have separate connection to the database. Pony handles connection under the hood, each connection associated with current thread (or current process if the application is single-threaded). In async framework all coroutines use the same thread, so the approach that connections are tied to specific threads does not work. It may lead to situation that different coroutines use the same connection, which may break transaction boundaries. Also, async code can lead to enormous amount of concurrent coroutines with parallel transactions, which are very long comparing with transactions in a usual application. Database server does not work well in situation, when there are thousands of concurent long-living transactions. But it seems that many people who choose to use async approach does not understand what does it mean from the database point of view. The just say, "hey, async code should definitely be better, because it async", and don't think about transactions and all that database stuff. For async application it is better to have separate database access layer which communicates with the rest part of application using queues, but such architecture is much more complex than the usual synchronous approach.
Do you know of a good article or resource that explains this queued db access architecture? I want to understand it better so that if an async project warrants the complexity, I'll have that pattern available to use.
Anonymous
Hello,
Anonymous
(ScorecardScorecard.select() .join(ScorecardCategoryAppScorecardCategory) .join(ScorecardCriteriaAppScorecardCriteria) .join(ScorecardAttributeAppScorecardAttribute) .switch(ScorecardCriteriaAppScorecardCriteria) .join(ScorecardCriteriaTypeAppScorecardCriteriaType))
Anonymous
this kind of join is not exisiting in your orm ?
Alexander
Pony does joins automatically when you traverse relationship attributes, like query1 = select(p for p in Person for car in p.cars if car.manufacturer.name == "Toyota") you can also use filter method to build query incrementally, it will do joins too if necessary query2 = query1.filter(lambda person: person.spouse.country.name == "USA")
Anonymous
I need to join 3-4 tables
Alexander
You can join as many tables as you wish
Alexander
Actually, joining tables is probably not your final goal. You join tables to do something useful with joined data, probably write some condition. Try to express this condition, and Pony join necessary tables automatically
Anonymous
query1 = select(p for p in Person for car in p.cars if car.manufacturer.name == "Toyota") here two tables joined on car ?
Alexander
If person-car relationship is one-to-many, it joins Person and Car. If it is many-to-many, it joins intermediate table as well
Anonymous
query1 = select(p for p in Person for car in p.cars for x in car.rel ) for 3 table it will be like this
Anonymous
?
Alexander
yes, if rel is a Set attribute. If it is a Required or Optional attribute, then you just wrote query1 = select(p for p in Person for car in p.cars if car.rel.foo == 'bar')
Alexander
Imagine that all that data sits in memory, and each Set attribute is a collection, as well as entity class itself, and think how you'd write generator expression to filter necessary objects
Young
Any ER diagram for a bank system or similar ?
Alexey
Can you provide more details on what are you looking for? @YoungNastyman
Young
Can you provide more details on what are you looking for? @YoungNastyman
something to simulate withdrawals and deposits from a bank account, user management etc.
Young
Is it going to be an app?
yes, just for simulate and practicing, nothing serious
Young
i want to speed it up the process haha
Anonymous
Hi, is it possible to dynamically assign a table name to an entity? I usually can change it with class Meta, but I have the idea to use one class for three different tables. Or is it easier to create a base class and inherit 3 subclasses and only change the table name there?
Alexander
Pony implements simgle-table inheritance, when all subclasses share the same table If you really need three different tables (but no more) it is easier to define thee different classes
Anonymous
Ok, thanks. Creating a base class wouldn't help since generate_mapping would create that base class as well. :)
Nikolay
I was under impression that using rollback within a db_session may cause further selects to throw an error along the lines of "You are trying to use an object from a transaction that's already over", but now i can't reproduce it. Is there an error like that in pony? Not a different session, but a different transaction within a session
Alexander
Yes, after rollback() session cache is invalidated and all previous objects are unaccessible >>> from pony.orm.examples.university1 import * >>> with db_session: ... s = Student[1] ... rollback() ... print(s.group.dept.name) ... Traceback (most recent call last): ... pony.orm.core.DatabaseSessionIsOver: Cannot load attribute Group[101].dept: the database session is over
Alexander
Direct properties which already loaded are available, so you can access s.name after rollback, but not properties which require additional selects, like s.group.dept.name
Nikolay
this also works
Nikolay
that's why i wasn't able to reproduce it
Alexander
because child.parent is already loaded, as well as parent.value
Nikolay
This makes rollbacks rather unpredictable
Nikolay
Well I don't mind not using rollbacks but that's the only way to get-or-create I know of which doesn't require raw sql
Nikolay
Right now i have an ugly hack that involves setting is_fully_loaded of parent.children to False.
Alexander
I just added support of volatile Set attributes, you can check it on GitHub https://github.com/ponyorm/pony/commit/54b0a97fa5602980ef1dd368336a08ad89da4748
Alexander
Re-fetching objects which were created in previous db_session may be an interesting idea, but it is tricky to implement correctly. We need not only to fetch attributes, but also to add this object to current db_session. It is possible that current db_session already has an instance which represents Student[1], and in Python we cannot merge two different instances into a single one. Maybe in that case Student[1] from previous db_session should become something like a transparent proxy for Student[1] from the current db_session. It is possible, but may be a bit tricky to implement
Alexander
Actually, we really need to add native support for upserts, this would make most of this problems obsolete
Alexander
Currently there is no much difference in db_session cache handling between with db_session: aaa rollback() bbb and with db_session: aaa rollback() with db_session: bbb And even inside a single db_session it is possible to have s situation like with db_session: s = Student[123] rollback() # fresh session cache ss = Student[123] # new object print(s.group.dept.name) # old object with the same id
Alexander
Also, rollback() inside of db_session currently commonly used as a way to forget and garbage collect previously loaded objects, at least ones which does not have direct references from user code, so we don't want to keep full identity map of objects which are loaded before rollback()
Lucky
Pony expects that concurrent requests are processed in transactions, each parallel transaction decorated with db_session, and have separate connection to the database. Pony handles connection under the hood, each connection associated with current thread (or current process if the application is single-threaded). In async framework all coroutines use the same thread, so the approach that connections are tied to specific threads does not work. It may lead to situation that different coroutines use the same connection, which may break transaction boundaries. Also, async code can lead to enormous amount of concurrent coroutines with parallel transactions, which are very long comparing with transactions in a usual application. Database server does not work well in situation, when there are thousands of concurent long-living transactions. But it seems that many people who choose to use async approach does not understand what does it mean from the database point of view. The just say, "hey, async code should definitely be better, because it async", and don't think about transactions and all that database stuff. For async application it is better to have separate database access layer which communicates with the rest part of application using queues, but such architecture is much more complex than the usual synchronous approach.
Which is a bummer really, as something as fast as [asyncpg](https://github.com/MagicStack/asyncpg) could be used which claims to be 3x faster than psycopg2…
Lucky
In hindsight it is really sad that table building, query building and actually running the code aren't more modular. Otherwise I could use Pony to write a pythonic query but let asyncpg execute it.
Nikolay
I just added support of volatile Set attributes, you can check it on GitHub https://github.com/ponyorm/pony/commit/54b0a97fa5602980ef1dd368336a08ad89da4748
Of course making the whole relation volatile feels like an overkill but it's much better than messing with _values_. Thanks.
Nikolay
In hindsight it is really sad that table building, query building and actually running the code aren't more modular. Otherwise I could use Pony to write a pythonic query but let asyncpg execute it.
There's a method to get sql from a query, There's also generate_create_script or smth like that for creating tables. You still have to bind and generate_mapping to use those though
Nikolay
Actually, we really need to add native support for upserts, this would make most of this problems obsolete
I'd like to note that ON CONFLICT DO NOTHING is probably used as much as ON CONFLICT DO UPDATE. In case of pony DO UPDATE would probably cause the other session to fail with "object was modified outside of db session" while with DO NOTHING i expect to be able to fetch, try insert and commit if fetched nothing, fetch again if inserted nothing
Nikolay
Is there a separate name for ON CONFLICT DO NOTHING? I'm actually not sure. edit: doesn't look so
Alexander
Cache wipe is ok and probably even required but having to manually refetch stuff makes rollback pretty much unusable for a user. At least not usable in "inner" functions.
Rollback is not something you can do in normal situation. Usually after rollback a function raises exception and exits. Rollback lead to transaction termination. After rollback a new transaction is started, and in-between these transactions database tables could be modified by concurrent transactions, so we cannot keep old query results and use them in new transaction. And inner functions is definitely not a place to do rollback, if the inner function does not have corresponding raise for some exception. Some databases (PostgreSQL including) have a concept of nested transactions, so theoretically it would be possible to start sub-transaction in inner function and then rollback this sub-transaction only and continue execution of the main transaction. But it may be hard to support from an ORM, because on encountering rollback of sub-transaction, the ORM needs to rollback its in-memory cache of loaded objects as well to the moment where the sub-transaction started, and it is hard to do that rollback(clear_cache=False) is possible to implement, but I'm not sure all users who will try to use it will understand consequences on isolation: it is possible that objects were changed in database by concurrent transaction. On the other side, Pony support of optimistic checks can make this problem a bit less critical, as object state will be checked during the UPDATE execution But I think that proper support of ON CONFLICT would solve most of these problems
Nikolay
Rollback is not something you can do in normal situation. Usually after rollback a function raises exception and exits. Rollback lead to transaction termination. After rollback a new transaction is started, and in-between these transactions database tables could be modified by concurrent transactions, so we cannot keep old query results and use them in new transaction. And inner functions is definitely not a place to do rollback, if the inner function does not have corresponding raise for some exception. Some databases (PostgreSQL including) have a concept of nested transactions, so theoretically it would be possible to start sub-transaction in inner function and then rollback this sub-transaction only and continue execution of the main transaction. But it may be hard to support from an ORM, because on encountering rollback of sub-transaction, the ORM needs to rollback its in-memory cache of loaded objects as well to the moment where the sub-transaction started, and it is hard to do that rollback(clear_cache=False) is possible to implement, but I'm not sure all users who will try to use it will understand consequences on isolation: it is possible that objects were changed in database by concurrent transaction. On the other side, Pony support of optimistic checks can make this problem a bit less critical, as object state will be checked during the UPDATE execution But I think that proper support of ON CONFLICT would solve most of these problems
> in-between these transactions database tables could be modified by concurrent transactions I was under impression that can happen anyway because pony uses optimistic concurrency control
Nikolay
But i do agree that rollbacks are not something you would normally do and rollback(clear_cache=False) has unclear implications
Nikolay
I did some googling on support of ON CONFLICT DO NOTHING by various dbs: PostgreSQL has ON CONFLICT since 9.5 which also happens to be oldest supported version. MySQL has INSERT IGNORE and INSERT … ON DUPLICATE KEY UPDATE since apparently forever. Oracle has MERGE statement since around 9.0 and also IGNORE_ROW_ON_DUPKEY_INDEX hint since 11.2. Oldest supported version is 12.2. CockroachDB has ON CONFLICT with apparently some limitations in stable version and with some bugs in older versions. SQLite has ON CONFLICT since 3.24.0 (2018-06-04) which is rather new and will probably not be available to all users. Documenting it as such is probably enough.
Nikolay
I imagine CockroachDB "limitation" applies not only to CockroachDB and is insignificant
Nikolay
I just added support of volatile Set attributes, you can check it on GitHub https://github.com/ponyorm/pony/commit/54b0a97fa5602980ef1dd368336a08ad89da4748
Now that I think about it I never understood how exactly volatile=True is different from optimistic=False on an attribute. If this causes pony to constantly refetch the children list then it's a bit more of an overkill that I thought, especially since in my case the single extra child created by raw sql is immediately fetched manually. But it doesn't look like this makes pony do more queries than it already does. But then again I also don't know if it's supposed to and how to trigger that behavior.
Anonymous
hi, how could i create a ‘updated_at’ field in db.Entity which will be reset once a recrod is updated?
Anonymous
Anonymous
compared to other orms, i can set on_update function here.
Jim
https://docs.ponyorm.org/api_reference.html#entity-hooks
Alexander
class MyEntity(db.Entity): x = Required(int) updated_at = Required(datetime, default=datetime.utcnow) def before_update(self): self.updated_at = datetime.now()
Anonymous
👍 thanks. give it a try
Anonymous
I wrote like this. But after executing create_tables. I found student table does’t have created_at and updated_at fields.
Anonymous
I got confused.