bmispelon,
@bmispelon@mastodon.social avatar

New article on my blog: a #Django ORM technique I found for combining JSONObject and Subquery to build model instances: https://blog.bmispelon.rocks/articles/2024/2024-05-09-django-getting-a-full-model-instance-from-a-subquery.html

hvdklauw,
@hvdklauw@mastodon.social avatar

@bmispelon created a pr to fix relationships, ignore the baby writing a book in the tests ;-)

bmispelon,
@bmispelon@mastodon.social avatar

@hvdklauw Amazing! I knew that my usage of _meta.get_fields() was a bit optimistic, thanks for getting your hands dirty and doing the legwork on relational fields. Much appreciated ✨

(I'll take a closer look at the code in the next few days)

treyhunner,
@treyhunner@mastodon.social avatar

@bmispelon This is so clever! 🎉And a great write up! 👏

I appreciate your "attempt 1", "attempt 2", style write ups in general. It makes me feel like I'm suffering through searching for the solution along with you. 😆

josh,
@josh@joshthomas.dev avatar

@bmispelon 👑 This is great!

As someone who has also spent his time in the mines translating raw SQL to ORM this would have come in handy so much in the past! Totally yanking this pattern if I ever have the need to do it again.

bmispelon,
@bmispelon@mastodon.social avatar

@josh Thanks, I've put the code on github and decided to try model-bakery for the tests 😁

https://github.com/bmispelon/django-model-subquery

hvdklauw,
@hvdklauw@mastodon.social avatar

@bmispelon oh, this is awesome, for years one of the things I do is write a forum and try to optimize the hell out of getting the related information. Django has gotten better and better but this trick might be the final bit needed to do things in a single query without weird triggers/signals to update related tables when needed.

webology,
@webology@mastodon.social avatar

@bmispelon Nice.

(If you are open to typos, "Suquery" stuck out which might be a good band name.)

bmispelon,
@bmispelon@mastodon.social avatar

@webology Fixed, thanks 👍

webology,
@webology@mastodon.social avatar

@bmispelon 🤘

CodenameTim,
@CodenameTim@fosstodon.org avatar

@bmispelon 🤩 this functionality is something that belongs in the ORM ideally. I think a third party library is a good starting point, but I'd vote for it to go straight to main. People frequently want to fetch a list of discussion threads and the latest post of each thread. Your idea is perfect for that scenario!

bmispelon,
@bmispelon@mastodon.social avatar

@CodenameTim Yes, this technique should work well for the "latest comment in thread" scenario. That might even have been a better example to use 😅

To be honest I was surprised how far I was able to get, I kept thinking I would hit some fundamental limitation of the ORM at some point, but I never did.

CodenameTim,
@CodenameTim@fosstodon.org avatar

@bmispelon I don't know enough about the ORM if this bootstrapping approach has some unseen performance penalty. @lilyf maybe you have some insight?

lilyf,
@lilyf@fosstodon.org avatar

@CodenameTim @bmispelon That's really cool!

I don't have any particular insight into the performance implications I'm afraid - we'd need to do some profiling.

I'd love it if we could find a way to avoid needing the JSONObject intermediary though! I never worked on the SubQuery code, so I don't know what's possible there.

carlton,
@carlton@fosstodon.org avatar

@lilyf @CodenameTim @bmispelon I wonder if using ArrayAgg, rather than JSONObject, would let you select the raw values without the conversion 🤔

Awesome post! 🎩

https://docs.djangoproject.com/en/5.0/ref/contrib/postgres/aggregates/#arrayagg

bmispelon,
@bmispelon@mastodon.social avatar

@carlton @lilyf @CodenameTim Possibly, but then you'd lose the ability to defer missing fields.

carlton,
@carlton@fosstodon.org avatar

@bmispelon @lilyf @CodenameTim OK, missing what you mean there. I need to play, since I don't have all that in RAM 🤔

Thought was exactly as you have it in the post, but with ArrayAgg at the JSONObject step. PG can return an array of fields, as native values, for a single output field. (Like a composite type, but here from a subquery)

Is your test project cloneable?

bmispelon,
@bmispelon@mastodon.social avatar

@carlton @lilyf @CodenameTim It's not yet on github, I'm going to do that later today.

I mention the deferring bit at the end of the post. Basically the idea is that if the jsonobject doesn't contain all the model fields, you can still instanciate the model and the missing fields will be deferred (same as if you'd used Django's .defer()/.only()).

carlton, (edited )
@carlton@fosstodon.org avatar

@bmispelon @lilyf @CodenameTim Ah, yes, you'd want a DictAgg (or such) so you'd know what fields to pass.

🤔

Nice.

You could probably do something with a namedtuple, so the ordered subfields in an array mapped back to names.

🤔

Nice.

🤔

bmispelon,
@bmispelon@mastodon.social avatar
carlton,
@carlton@fosstodon.org avatar

@bmispelon @lilyf @CodenameTim Super thanks!

(Not sure my ArrayAgg idea will work… « types… varying cannot be matched » 😔)

bmispelon,
@bmispelon@mastodon.social avatar

@carlton Ah right, I guess arrays need to be homogenous don't they? It might work by casting everything to a string first, then using the same Field.to_python() trick that I use? https://github.com/bmispelon/django-model-subquery/blob/main/src/modelsubquery/functions.py#L46

carlton,
@carlton@fosstodon.org avatar

@bmispelon maybe 🤔 I shall potter on the project. (Much easier than me half hacking it together myself.) There must be some incantation to get PG to return it like an ad hoc composite type.

bmispelon,
@bmispelon@mastodon.social avatar

@carlton Best of luck!

I didn't dare going deep into the psycopg depths, but I'm sure there's some cool stuff in there too.

I'm happy to hear back if you find anything (here or via a PR on the project)

bmispelon,
@bmispelon@mastodon.social avatar

@carlton Also I tried flit for making the package, after your recommendation from last week 😁

It was rather pleasant as far as python packaging go

carlton,
@carlton@fosstodon.org avatar

@bmispelon welcome aboard! ⛵️

Every day there are more of us 🥳

  • All
  • Subscribed
  • Moderated
  • Favorites
  • django
  • rosin
  • Youngstown
  • khanakhh
  • ngwrru68w68
  • slotface
  • ethstaker
  • mdbf
  • everett
  • kavyap
  • DreamBathrooms
  • thenastyranch
  • cisconetworking
  • magazineikmin
  • Durango
  • megavids
  • GTA5RPClips
  • Leos
  • tester
  • tacticalgear
  • InstantRegret
  • normalnudes
  • osvaldo12
  • cubers
  • anitta
  • modclub
  • provamag3
  • JUstTest
  • lostlight
  • All magazines