Alexander
You defined __init__ in your mixin and not call base __init__
Lucky
I will rewrite it as one big class.
Alexander
In my test all works as expected: from pony.orm import * class PersonMixin(object): def hello(self): print('My name is ' + self.name) class Person(PersonMixin): def __init__(self, name): self.name = name db = Database('sqlite', ':memory:') class DBPerson(PersonMixin, db.Entity): name = Required(str) sql_debug(True) db.generate_mapping(create_tables=True) with db_session: p1 = Person(name='John') p1.hello() p2 = DBPerson(name='Mike') p2.hello() with db_session: p3 = select(p for p in DBPerson).first() p3.hello()
Lucky
Let me explain my project a bit, maybe that will help understanding my problem. I have a script (called node) which sends (broadcasts) messages and receives brodcasted messages. Thats basically all it does. Receiving messages and doing a bit of calulation what to send next. And I am writing another script (called db_proxy) which also reveives the broadcasted messages. This script should decode the stuff from the socket, like the node, but put it in a database. So I want to use the same code for receiving the Messages. But in second program i want to dump it into a database, instead of answering with more messages. The mixin, while perfectly working, is not as readable, because the functionality is split into 2 classes. I think I will write seperate DBMessage class which has functions to set it's own values according to a given Message instance. with db_session: p3 = select(p for p in DBPerson).first() p = p3.from_db() # eventually calls Person(foo=self.foo, bar=self.bar) p.foo.do_stuff() With that I don't have to modify the original classes ( Message or in your example Person)
Lucky
Because If you take the DB part away, the Mixin classes alone are very confusing.
Alexander
I think this approach is valid. This way the code may be easier to understand
Lucky
Hey guys
Alexey
hey
Lucky
SELECT DISTINCT ON (m.type) * FROM ( SELECT * FROM DBMessage ORDER BY date DESC ) as m ORDER BY m.type, m.date DESC This selects the newest (m.date) DBMessage of each m.type in postgres.
Lucky
SELECT * FROM DBmessage ORDER BY date DESC
Lucky
SELECT DISTINCT ON (m.type) * FROM ( SELECT * FROM DBmessage ORDER BY date DESC ) as m ORDER BY m.type, m.date DESC
Lucky
I can't find how to do DISTINCT on pony
Alexey
Is this what you need? https://docs.ponyorm.com/api_reference.html?highlight=distinct#distinct
Lucky
I couldn't find it as I searched :( Probalby, yes. Thanks
Alexey
there is Quick search field here https://docs.ponyorm.com/toc.html
Alexey
np
Alexander
I think this is not the same thing. As I understand, "DISTINCT ON" is a special PostgreSQL construction which is not equivalent to DISTINCT
Lucky
yeah, DESTINCT and DESTINCT ON ({column}) are different. https://www.postgresql.org/docs/9.0/static/sql-select.html#SQL-DISTINCT
Alexander
You want to select latest message for each message type
Lucky
DESTINCT removes duplicate rows, DESTINCT ON keeps only the first row with the same value of a column
Lucky
Actually I did the wrong thing, here is my correct SQL: SELECT DISTINCT ON (m.node) * FROM ( SELECT * FROM DBmessage WHERE type = 1 ) as m ORDER BY m.node, m.date DESC But lets stay by the above example :D
Alexander
Can you use max id instead of a latest date to find the latest message? I think it will be a bit easier to write
Lucky
Can you use max id instead of a latest date to find the latest message? I think it will be a bit easier to write
hm, probably later the max_id might not be the newest one, if a client is to slow to dump it in real time
Alexander
ok, with dates you can try the following: select(m for m in DBMessage if (m.type, m.date) in select((m.type, max(m.date)) for m in DBMessage)) But if two messages of the same type may have indentical date (up to microseconds), you will get both messages
Alexander
Another way is to use raw SQL query: DBMessage.select_by_sql(""" SELECT DISTINCT ON (m.node) * FROM ( SELECT * FROM DBmessage WHERE type = 1 ) as m ORDER BY m.node, m.date DESC """)
Lucky
Hm, probably a db.select("sql") is better
Lucky
That's cool!
Lucky
Btw, how can I apply .show() on the resulting list?
Alexander
Note that inside raw SQL you can use Python expression, which are converted to query parameters: message_type = 1 DBMessage.select_by_sql(""" SELECT DISTINCT ON (m.node) * FROM ( SELECT * FROM DBmessage WHERE type = $message_type ) as m ORDER BY m.node, m.date DESC """)
Alexander
show is the method of QueryResult. select_by_sql returns list of entities, which don't have show method.
Alexander
Maybe we can add it later
Lucky
Okey, was just to visualize it to myself
Lucky
How would I do m.date >= NOW() - '1 minute'::INTERVAL? latest_vote = orm.select(m for m in DBVoteMessage).order_by(orm.desc(DBVoteMessage.date)).first()
Lucky
I want to only get messages from the last past hour. Best would be to use the server NOW()
Alexander
You can write from datetime import datetime, timedelta select(m for m in DBVoteMessage if m.date >= detetime.now() - timedelta(hours=1)) But Pony will think that expression datetime.now() - timedelta(hours=1) can be evaluated in Python and replaced with a single query parameter. In order to use server NOW() you can use raw SQL fragment: select(m for m in DBVoteMessage if m.date >= raw_sql("NOW() - '1 minute'::INTERVAL"))
Alexander
Thanks, we'll fix it
Lucky
But raw_sql is very neat. Is that executed in the same query?
Alexander
yes
Lucky
perfect
Lucky
Alexander
Alexander
oops )
Lucky
:D
Alexey
😄👍
Mikki
Welcome!
HM
Alexey
Hey guys I have a problem with the display of the ORM online editor. I found no good place to file an issue, so I went for the doc repo: https://github.com/ponyorm/pony-doc/issues/1
Thank you for reporting, it should be fixed now. Please use the issue tracker in this project https://github.com/ponyorm/editor for any issues related to the Editor.
Lucky
You are the 6th Alexander in this group oO
Rozen
only 6th?
Lucky
I think thats an awful lot 😅
Mikki
Welcome!
Michael
Hey! Thanks :)
Lucky
5
Mikki
Welcome!
stsouko
Hello!
stsouko
from enum import Enum from pony.orm.dbapiprovider import IntConverter class EnumConverter(IntConverter): def validate(self, val): if not isinstance(val, Enum): raise ValueError('Must be an Enum. Got {}'.format(type(val))) return val def py2sql(self, val): return val.value def sql2py(self, val): return self.py_type(val) db.provider.converter_classes.append((Enum, EnumConverter)) class Models(db.Entity): id = PrimaryKey(int, auto=True) model_type = Required(ModelType, default=ModelType.PREPARING) class ModelType(Enum): PREPARER = 0
stsouko
Hello!
stsouko
I tryed to use custom converter.
stsouko
its work if i do smth as: Models[1].model_type
Rozen
use ` to make the code less ugly in the chat
stsouko
but not in queries: select(x.model_type for x in Models)
Rozen
print ('hello wurld')
stsouko
ok
stsouko
`class EnumConverter(IntConverter): def validate(self, val): if not isinstance(val, Enum): raise ValueError('Must be an Enum. Got {}'.format(type(val))) return val def py2sql(self, val): return val.value def sql2py(self, val): return self.py_type(val) db.provider.converter_classes.append((Enum, EnumConverter))`
stsouko
` class EnumConverter(IntConverter): def validate(self, val): if not isinstance(val, Enum): raise ValueError('Must be an Enum. Got {}'.format(type(val))) return val def py2sql(self, val): return val.value def sql2py(self, val): return self.py_type(val) db.provider.converter_classes.append((Enum, EnumConverter)) `
stsouko
oh sheee
stsouko
http://pastebin.com/yidQy0X6
stsouko
is it possible?
Alexander
Multiline examples are wrapped with three backquotes. What error do you get when using select?
stsouko
TypeError: Unsupported type 'ModelType'
stsouko
select(x.id for x in Models if x.model_type == ModelType.PREPARER)
stsouko
I tryed this and got TypeError: Expression ModelType.PREPARER has unsupported type 'ModelType'
stsouko
если можно на русском, то: я предположил что маппер автоматом раскрывает Енам в число и выполняет запрос. вот и решил сделать так.
Rozen
D:
Alexander
We plan to add support of enums, I think it is a bit more complex than in your example. Right now the simplest you can do is to manualy convert enum items to values inside query: select(x.id for x in Models if x.model_type == ModelType.PREPARER.value)
stsouko
Thank You for quick response!