{ "info": { "author": "Matt Westcott", "author_email": "matt@west.co.tt", "bugtrack_url": null, "classifiers": [ "Development Status :: 4 - Beta", "Environment :: Web Environment", "Framework :: Django", "Intended Audience :: Developers", "License :: OSI Approved :: BSD License", "Operating System :: OS Independent", "Programming Language :: Python", "Topic :: Software Development :: Libraries :: Python Modules" ], "description": "django-unjoinify\n\nA library for efficiently retrieving deeply-nested data sets\n(for people who aren't afraid of a bit of SQL)\n\nThe problem\n-----------\nSuppose you have a website about film festivals. Each festival has many awards,\nand each award has many nominations. A nomination belongs to a movie, and a\nmovie can have several directors (in a many-to-many relation). You want to have\na page listing the full roster of nominated movies at a festival, including\ntheir directors.\n\nIf you do this the naive way (looping over awards, then nominations / movies,\nthen directors), you'll end up making lots and lots of little queries. This is\nbad.\n\nselect_related won't help you here - it can't follow one-to-many and\nmany-to-many relations. (See Django tickets #2238 and #6432.)\n\nThe traditional answer is to bite the bullet and drop down to raw SQL at this\npoint:\n\nSELECT\n\ttinseltown_award.id,\n\ttinseltown_award.name,\n\ttinseltown_nomination.id AS nomination__id,\n\ttinseltown_nomination.ranking AS nomination__ranking,\n\ttinseltown_movie.id AS nomination__movie__id,\n\ttinseltown_movie.title AS nomination__movie__title,\n\ttinseltown_person.id AS nomination__movie__directors__id,\n\ttinseltown_person.first_name AS nomination__movie__directors__first_name\n\ttinseltown_person.surname AS nomination__movie__directors__surname\nFROM\n\ttinseltown_award\n\tLEFT JOIN tinseltown_nomination ON (tinseltown_award.id = tinseltown_nomination.award_id)\n\tLEFT JOIN tinseltown_movie ON (tinseltown_nomination.movie_id = tinseltown_movie.id)\n\tLEFT JOIN tinseltown_movie_directors ON (tinseltown_movie.id = tinseltown_movie_directors.movie_id)\n\tLEFT JOIN tinseltown_person ON (tinseltown_movie_directors.person_id = tinseltown_person.id)\nWHERE\n\ttinseltown_award.festival_id = ?\nORDER BY\n\ttinseltown_award.name,\n\ttinseltown_nomination.ranking\n\nThis captures all the data you need for the page in a single query, but there's\na downside: all you get back is a plain SQL result table, with no access to\nyour model objects and their lovingly-crafted methods (think get_absolute_url).\n\nunjoinify to the rescue\n-----------------------\nProvided you've used the double-underscore notation above for your column\nnames, and made them match up with your relation names, unjoinify will take\nyour query, and through some cunning ORM introspection, reconstruct an object\ntree:\n\nawards = unjoinify(Award, \"SELECT tinseltown_award.id...\", (festival_id,))\n\n(Here Award is the base class that all the joins are hanging off, and\nfestival_id is a parameter to the query.)\n\nWell... almost. Due to limitations of Django's ORM, we can't return a proper\nobject tree with the ability to refer to award.nominations and so on. Instead,\nwhat you get back is an array of (award, nominations) tuples, where nominations\nis itself an array of (nomination, movie, directors) tuples, and directors is\nan array of person objects. This is good enough for iterating through in a\ntemplate, though:\n\n{% for award, nominations in awards %}\n\t

{{ award.name }}

\n\t\n{% endfor %}\n\nunjoinify will even handle cartesian joins - for example, if a movie had\nmultiple studios as well as multiple directors, you could join on both\nrelations and have it successfully unpack to a tuple of\n(nomination, movie, directors, studios). You're advised to use this sparingly,\nthough - this will result in count(directors) * count(studios) rows being\nreturned for each movie, which, depending on your particular use-case, could\nend up being far worse than running separate queries...\n\nExplicit column names\n---------------------\nUnfortunately, database engines are liable to have a fairly low limit on column\nname length (63 characters, in the case of Postgres), and it's easy to run into\nthis limit when working with deeply-nested relations. To work around this, you\ncan pass the list of column names as an additional parameter (in the same order\nthat they appear in the query):\n\nawards = unjoinify(Award, sql, (festival_id,),\n\tcolumns = ['id', 'name', 'nomination__id', 'nomination__ranking', 'nomination__movie__id', 'nomination__movie__title'])\n\nAuthor\n------\nMatt Westcott \nhttp://matt.west.co.tt/ - @westdotcodottt", "description_content_type": null, "docs_url": null, "download_url": "UNKNOWN", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/gasman/django-unjoinify", "keywords": null, "license": "BSD", "maintainer": null, "maintainer_email": null, "name": "django-unjoinify", "package_url": "https://pypi.org/project/django-unjoinify/", "platform": "UNKNOWN", "project_url": "https://pypi.org/project/django-unjoinify/", "project_urls": { "Download": "UNKNOWN", "Homepage": "https://github.com/gasman/django-unjoinify" }, "release_url": "https://pypi.org/project/django-unjoinify/0.1.0/", "requires_dist": null, "requires_python": null, "summary": "A helper for efficiently retrieving deeply-nested data sets", "version": "0.1.0" }, "last_serial": 790933, "releases": { "0.1.0": [ { "comment_text": "", "digests": { "md5": "c16bf6e6c881e721d1c68c752a34bff7", "sha256": "63ca6c2c0f935dce389b9f004575da4ad881523ffd8b4968861d489f1e1e62ec" }, "downloads": -1, "filename": "django-unjoinify-0.1.0.tar.gz", "has_sig": false, "md5_digest": "c16bf6e6c881e721d1c68c752a34bff7", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 4971, "upload_time": "2011-05-23T22:28:23", "url": "https://files.pythonhosted.org/packages/2d/a8/38b3e178c0677a1b68c28b95931b948a949712842a5eada5988bfa867fee/django-unjoinify-0.1.0.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "c16bf6e6c881e721d1c68c752a34bff7", "sha256": "63ca6c2c0f935dce389b9f004575da4ad881523ffd8b4968861d489f1e1e62ec" }, "downloads": -1, "filename": "django-unjoinify-0.1.0.tar.gz", "has_sig": false, "md5_digest": "c16bf6e6c881e721d1c68c752a34bff7", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 4971, "upload_time": "2011-05-23T22:28:23", "url": "https://files.pythonhosted.org/packages/2d/a8/38b3e178c0677a1b68c28b95931b948a949712842a5eada5988bfa867fee/django-unjoinify-0.1.0.tar.gz" } ] }