@ponyorm

Страница 12 из 75
Luckydonald
17.12.2016
22:18:30
Cuz I made a (for me) non-trivial DB change so I wanted to ask.

The difference is that I moved sticker into a subclass, and added anotherone with a stickerpack attribute

Alexey
17.12.2016
22:21:22
an example of to_dict and json.dumps

Luckydonald
17.12.2016
22:21:28
The difference is that I moved sticker into a subclass, and added anotherone with a stickerpack attribute
What I understood, Pony does that in one big table, distinguising it with a special row, telling it to be a specific class.

Google
Alexey
17.12.2016
22:22:35
def account_page(): user = get_current_user() projects = Project.select(lambda p: p.user == user).order_by(desc(Project.updated_at)) account = user.to_dict(exclude=['id', 'password', 'balance']) return json.dumps({ 'account': account, 'projects': [dict(p.to_dict(exclude=['id', 'user', 'data'])) for p in projects] }, default=json_handler)

def json_handler(obj): if hasattr(obj, 'isoformat'): return obj.isoformat() elif isinstance(obj, UUID): return str(obj) else: raise TypeError("Unserializable object {} of type {}".format(obj, type(obj)))

Luckydonald
17.12.2016
22:23:10
What I understood, Pony does that in one big table, distinguising it with a special row, telling it to be a specific class.
So, I'd need to add a row for that? If I remember correctly thats type "text" and contains a string of the class name? In that migration I would need to fill in "StickerTag", right? (I still have the sticker attribute) And add another pack field?

Alexander
17.12.2016
22:26:01
I think that first version of migration tool will not support such a changes which move attributes between subclasses. But this migration is actually simple. The first change is adding classtype system column which Pony uses to distinguish between subclasses. The second one is adding pack column for PackTag.pack relation. So the SQL for migration looks like (I assume PostgreSQL is used): alter table "tag" add column "classtype" text; update "tag" set "classtype" = "StickerTag"; --for previous objects alter table "tag" add column "pack" int references "stickerpack" ("id");

Alexander
17.12.2016
22:29:00
Yes, I think if you add default value it should work with previous code without problems

Luckydonald
17.12.2016
22:29:45
Cool, because I have seperated everything between Dev and Production, well except the database :/ The DB is shared.

Alexander
17.12.2016
22:30:28
Maybe it is better to have two different database copies for Dev and Prod

That way you may be sure that you non-tested dev code does not delete all objects from the database

Luckydonald
17.12.2016
22:33:38
Yes, definitly. Probably I'll learn that as soon as I fry up the DB. Couldn't find a way to easily export/import all the data, so I instead make periodically backups of the postgres folder... ... .. . and hope nothing bad happens... (Yeah that is terrible, I know)

Alexander
17.12.2016
22:35:04
Maybe we need some dump/load functionality in Pony

Luckydonald
17.12.2016
22:39:16
Not sure if that should be part of pony (or pony core at least)

Google
Luckydonald
17.12.2016
22:39:31
But It could indeed make switching Databases easy

Alexander
17.12.2016
22:41:27
I think making backup of entire database is outside of Pony scope. But maybe we should have a method to save content of a known entities into a big JSON file and then to load data from that file

That way it may be easier to populate a dev & test databases

Alexander
17.12.2016
22:55:37
Federico I know that many developers try to separate modules and apply @db_session only to modules which directly perform queries to the database. In my opinion, this is a mistake. The goal of PonyORM is to provide a common way to represent business data, and @db_session should wrap entire scope where PonyORM objects are used. For example, if we have a function which processes HTTP request, it may contain two sub-function. The first one retrieves objects from the database, and the second one uses retrieved objects to render HTML template using Jinja2. In my opinion @db_session should wrap the main function, which processes entire HTTP request.

This way the development of the application becomes much less painful

Luckydonald
17.12.2016
22:59:01
Just wrap both?

Alexander
17.12.2016
22:59:16
Yes, it is also possible

Federico
17.12.2016
22:59:56
wrapping both would mean it queries twice right? because the cache is cleared on exit?

Alexander
17.12.2016
23:00:18
No, the inner db_session is ignored

Federico
17.12.2016
23:00:23
yeah I see your point, I should probably make inner functions and wrap the external function

Alexander
17.12.2016
23:00:47
In my experience it works much better this way

I think, one counter-argument may be, "I don't want to allow the ORM to make queries inside template rendering function, because it will lead to N+1 query problem". Indeed, if you use Django or some other usual ORM, it will. But Pony prevents "N+1 query problem" automatically, so this argument is not applicable for PonyORM

With Pony there are nothing wrong if you lazy load some attributes in template redering function or in any other place outside of the function which makes the initial query

Luckydonald
17.12.2016
23:15:41
Is there a article about lazy loading? When does it make sense, when not?

Alexander
17.12.2016
23:16:56
I'm not sure about the article. I think, default behavior in Pony should be good enough for most cases

Luckydonald
18.12.2016
19:41:00
Is there a helper function to get the classtype of an db.Entity subclass?

Alexander
18.12.2016
19:42:01
You mean for specific instance?

Luckydonald
18.12.2016
19:42:57
Cuz, with my tags from before, I want do query Tags, StickerTags or PackTags based on a given variable.

depending on type variable I want to select one of the Tag classes

Google
Alexander
18.12.2016
19:45:52
if type == 'pack': tag_class = 'PackTag' elif type == 'sticker': tag_class = StickerTag else: tag_class = Tag tags = select(t for t in tag_class if ...)

Or, if you pass class name as a parameter, you can do: tags = select(t for t in Tag if t.classname == param and ...)

Luckydonald
18.12.2016
19:47:58
Alexander
18.12.2016
19:48:44
This is StickerTag._discriminator_

Alexey
19.12.2016
05:39:17
Thanks for reporting @luckydonald !

Luckydonald
19.12.2016
05:39:55
Your welcome :D

do_tags = Optional(bool, default=None) Is that possible? What is the default default of an optinal bool?

Thanks for reporting @luckydonald !
Note: I wrote "None" there before. Not that that is mistaken for the bug

Alexey
19.12.2016
05:44:16
do_tags = Optional(bool, default=None) Is that possible? What is the default default of an optinal bool?
Default for Optional is None, so you don't need to write 'default=None'

stsouko
19.12.2016
08:26:05
Hello! why then i do: Emails.get(post_parent=meeting.meeting, post_type=EmailPost.MEETING_REGISTRATION.value) pony translate it to SELECT "id", "post_type", "author", "title", "body", "date", "banner", "slug", "post_parent", "special", "classtype" FROM "Posts" WHERE "classtype" IN ('Emails') AND "post_type" = ? AND "post_parent" = ? LIMIT 2 [12, 1] why limit 2?

Alexander
19.12.2016
09:04:17
The get method assumes that no more than one object satisfies specified criteria. Pony attempts to retrieve more than one object in order to throw exception if multiple objects were found. Sometimes the query condition is wrong and a very big number of objects satisfy the criteria. Pony adds LIMIT 2 in order not to load all that objects to memory.

stsouko
19.12.2016
09:11:36
Thank you!

Alexander
19.12.2016
17:48:57
In order to not throw an exception?

Luckydonald
19.12.2016
17:49:37
Yes.

Alexander
19.12.2016
17:49:37
To do that you can use first instead of get

Luckydonald
19.12.2016
17:49:48
Awesome

Better then .select( ... )

Alexander
19.12.2016
17:51:01
The first is a method of Query, you can use select(...).first() or SomeEntity.select(...).first()

Google
Vsevolod
19.12.2016
17:52:52
Hi, everyone. I felt tired of ugly raw SQL queries in my Python code, so I decided to find a database ORM tool with elegant syntax. Found pony! Do you guys like this thing? ☺️

Luckydonald
19.12.2016
17:53:09
Thats why were here.

Vsevolod
19.12.2016
17:53:23
?

Luckydonald
19.12.2016
17:53:36
Useing it to write https://getstickers.me/

Vsevolod
19.12.2016
17:54:38
Impressing!

Luckydonald
19.12.2016
17:54:57
If someone uses that and sees bugs, please tell me

Vsevolod
19.12.2016
17:55:13
Are you working on this for fun?

Or are you somehow earning money?

Just interested

Luckydonald
19.12.2016
17:56:28
And because I thought such tool was missing.

If any of you can help me test by breaking stuff, I'd appreaciate it.

Vsevolod
19.12.2016
17:58:14
I like your website. It looks 100% fancy

Breaking stuff? ?

Colin
19.12.2016
17:58:49
And the online editor is very nice done

Luckydonald
19.12.2016
18:01:23
I like your website. It looks 100% fancy
It still needs some kind of search field. Still looking into how to do it (GUI I mean)

Oh never mind, I read it wrong.

Still for some reason query_text == st.sticker.file_id doen't seem to work. Maybe I am doing something wrong

Alexander
20.12.2016
10:35:51
I thought it should be query_text == st.sticker.emoji instead

Google
Luckydonald
20.12.2016
10:37:41
It also is in the line above

Alexander
20.12.2016
10:38:42
hmm. Give me a few minutes

Luckydonald
20.12.2016
10:47:58
If you want a SQL dump to play with, I can provide you such thing

pairs = orm.select( (st.sticker.file_id, max(st.date)) for st in StickerMessage for s_t in st.sticker.tags # for p_t in st.sticker.sticker_pack.tags if # (t.use_global or st.user.id == user_id or bot_id) and ( query_text.lower() in s_t.string.lower() or query_text.lower() in st.sticker.sticker_pack.url or query_text.lower() in st.sticker.sticker_pack.title or # query_text.lower() in p_t.string.lower() or query_text == st.sticker.emoji or query_text == st.sticker.file_id ) and not orm.exists(t for t in st.sticker.tags if t.string.lower() == "nsfw") and not orm.exists(t for t in st.sticker.sticker_pack.tags if t.string.lower() == "nsfw") ).order_by(orm.desc(2), 1).limit(50, offset=offset)

Or access to phppgadmin

Alexander
20.12.2016
10:49:27
I think that's enough for now

Luckydonald
20.12.2016
10:50:39
The for p_t in st.sticker.sticker_pack.tags part should actually be included, as well as the query_text.lower() in p_t.string.lower() or to check the Tags on a StickerPack too. `

Alexander
20.12.2016
11:03:13
Can you show me the the full text of the resulting SQL query?

Luckydonald
20.12.2016
11:26:22
Yes

SELECT DISTINCT "sticker"."file_id", MAX("st"."date") FROM "stickermessage" "st", "tag" "s_t", "sticker" "sticker", "stickerpack" "stickerpack" WHERE (lower("s_t"."string") LIKE ('%%' || replace(replace(replace(%(p1)s, '!', '!!'), '%%', '!%%'), '_', '!_') || '%%') ESCAPE '!' OR "sticker"."sticker_pack_url" LIKE ('%%' || replace(replace(replace(%(p1)s, '!', '!!'), '%%', '!%%'), '_', '!_') || '%%') ESCAPE '!' OR "stickerpack"."title" LIKE ('%%' || replace(replace(replace(%(p1)s, '!', '!!'), '%%', '!%%'), '_', '!_') || '%%') ESCAPE '!' OR %(p4)s = "sticker"."emoji" OR %(p4)s = "sticker"."file_id") AND NOT EXISTS ( SELECT 1 FROM "tag" "t-1" WHERE "st"."sticker_file_id" = "t-1"."sticker_file_id" AND "st"."sticker_emoji" = "t-1"."sticker_emoji" AND "t-1"."classtype" IN ('StickerTag') AND lower("t-1"."string") = 'nsfw' ) AND NOT EXISTS ( SELECT 1 FROM "sticker" "sticker-2", "tag" "t-2" WHERE "st"."sticker_file_id" = "sticker-2"."file_id" AND "st"."sticker_emoji" = "sticker-2"."emoji" AND lower("t-2"."string") = 'nsfw' AND ("sticker-2"."sticker_pack_url" = "t-2"."pack") ) AND "st"."sticker_file_id" = "s_t"."sticker_file_id" AND "st"."sticker_emoji" = "s_t"."sticker_emoji" AND "s_t"."classtype" IN ('StickerTag') AND "st"."sticker_file_id" = "sticker"."file_id" AND "st"."sticker_emoji" = "sticker"."emoji" AND "sticker"."sticker_pack_url" = "stickerpack"."url" GROUP BY "sticker"."file_id" ORDER BY 2 DESC, 1 LIMIT 50

I think I just wrote the query wrong or something

Alexander
20.12.2016
11:50:44
So, what in your opinion is wrong?

Страница 12 из 75