{ "info": { "author": "\u0141ukasz Langa", "author_email": "lukasz@langa.pl", "bugtrack_url": null, "classifiers": [ "Development Status :: 5 - Production/Stable", "Framework :: Django", "License :: OSI Approved :: MIT License", "Natural Language :: English", "Programming Language :: Python", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.2", "Programming Language :: Python :: 3.3", "Topic :: Internet :: WWW/HTTP", "Topic :: Software Development :: Libraries :: Python Modules" ], "description": "========\ndj.chain\n========\n\n.. image:: https://secure.travis-ci.org/ambv/dj.chain.png\n :target: https://secure.travis-ci.org/ambv/dj.chain\n\nThis module provides a way to chain multiple finite iterables for consumption as\na QuerySet-compatible object.\n\n\nQuickstart\n----------\n\nLet's start with an example. Say we have a couple of abstract database models\nwhich enables us to reuse fields later on::\n\n class Titled(db.Model):\n title = db.CharField(max_length=100)\n\n class Meta:\n abstract = True\n\n class Dynamic(db.Model):\n duration = db.PositiveIntegerField()\n\n class Meta:\n abstract = True\n\nWe also have concrete database models that share some of those fields::\n\n class Video(Titled, Dynamic):\n RESOLUTION = (\n (1, '240p'), (2, '320p'), (3, '480p'),\n (4, '720p'), (5, '1080p')\n )\n\n author = db.CharField(max_length=100)\n resolution = db.IntegerField(choices=RESOLUTION)\n\n class Song(Titled, Dynamic):\n GENRE = (\n (1, 'Country'), (2, 'Folk'), (3, 'Polka'),\n (4, 'Western'), (5, 'World')\n )\n\n artist = db.CharField(max_length=100)\n genre = db.IntegerField(choices=GENRE)\n\nOur database already contains some data::\n\n >>> Video.objects.all()\n [,\n ,\n ,\n ]\n >>> Song.objects.all()\n [,\n ,\n ,\n ]\n\n\nA basic chain\n~~~~~~~~~~~~~\n\nLet's create a simple chain::\n\n >>> from dj.chain import chain\n >>> media = chain(Video.objects.all(), Song.objects.all())\n\nWe can collectively call QuerySet-related methods on it::\n\n >>> media.count()\n 8\n\nWe can also filter it further::\n\n >>> list(media.filter(duration__gt=250))\n [,\n ,\n ,\n ]\n\nCheck the cumulative length::\n\n >>> media.filter(duration__gt=250).count()\n 4\n\nUse indices and slices::\n\n >>> media.filter(duration__gt=250)[1]\n \n >>> list(media[3:6])\n [,\n ,\n ]\n >>> list(media[1::3])\n [, \n ,\n ]\n\nUse cumulative sorting and filtering::\n\n >>> list(media.order_by('title'))\n [,\n ,\n ,\n ,\n ,\n ,\n ,\n ]\n >>> list(media.order_by('-duration').filter(duration__lt=300))\n [,\n ,\n ,\n ,\n ,\n ]\n\nEtc.\n\n\nChaining heterogenic iterables\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nWe can add iterables that aren't QuerySets to the bunch::\n\n >>> from collections import namedtuple\n >>> Book = namedtuple('Book', \"author title page_count\")\n >>> books=(\n ... Book(author='Charles Dickens', title='A Tale of Two Cities', page_count=869),\n ... Book(author='Miguel de Cervantes', title='Don Quixote', page_count=1212),\n ... )\n >>> media=chain(Video.objects.all(), books)\n >>> media.count()\n 6\n >>> list(media)\n [,\n ,\n ,\n ,\n Book(author='Charles Dickens', title='A Tale of Two Cities', page_count=869),\n Book(author='Miguel de Cervantes', title='Don Quixote', page_count=1212)]\n\nYou can also use cumulative ordering in this case. The only thing you need to\nkeep in mind is that iterables which are not QuerySets should be presorted for\nthe cumulative result to be ordered correctly. An example::\n\n >>> list(media.order_by('title'))\n [Book(author='Charles Dickens', title='A Tale of Two Cities', page_count=869),\n ,\n ,\n Book(author='Miguel de Cervantes', title='Don Quixote', page_count=1212),\n ,\n ]\n\nYou can also use the cumulative ``values`` and ``values_list`` transformations::\n\n >>> media = chain(mt.Video.objects.all(), mt.books)\n >>> list(media.values('title'))\n [{'title': u'Gangnam Style'}, {'title': u'Baby'}, {'title': u'Bad Romance'},\n {'title': u'Waka Waka'}, {'title': u'A Tale of Two Cities'},\n {'title': u'Don Quixote'}]\n >>> list(media.values_list('title', 'author'))\n [(u'Gangnam Style', u'Psy'), (u'Baby', u'Justin Bieber'),\n (u'Bad Romance', u'Lady Gaga'), (u'Waka Waka', u'Shakira'),\n (u'A Tale of Two Cities', u'Charles Dickens'),\n (u'Don Quixote', u'Miguel de Cervantes')]\n >>> list(media.values_list('author', flat=True))\n [u'Psy', u'Justin Bieber', u'Lady Gaga', u'Shakira', u'Charles Dickens',\n u'Miguel de Cervantes']\n\nCustom filtering, sorting and transformations\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nChains provide special overridable static methods used while yielding values:\n\n* ``xfilter(value)`` - yield a value only if ``xfilter(value)`` returns\n ``True``. See known issues below.\n\n* ``xform(value)`` - transforms the value JIT before yielding it back. It is\n only called for values within the specified slice and those which passed\n ``xfilter``.\n\n* ``xkey(value)`` - returns a value to be used in comparison between elements if\n sorting should be used. Individual iterables should be presorted for the\n complete result to be sorted properly. Any cumulative ``order_by`` clauses are\n executed before the ``xkey`` method is used. \n\n\nMethods silently ignored on incompatible iterables\n--------------------------------------------------\n\nChains may contain both QuerySet-like objects and other iterables. There are\nmethods which apply only to the former if called collectively on the chain\nobject. These are:\n\n* ``defer``\n\n* ``exclude``\n\n* ``extra``\n\n* ``filter``\n\n* ``only``\n\n* ``prefetch_related``\n\n* ``select_for_update``\n\n* ``select_related``\n\n* ``using``\n\nBy default ``dj.chain`` considers any iterable a QuerySet-like object as long as\nit has a method required for the collective call. For example if your custom\niterable supports a ``defer`` method, it will be used on collective ``defer``\ncalls. If that behaviour is undesirable, you should pass ``strict=True`` when\nconstructing a chain::\n\n c = chain(Article.objects.all(), custom_entries, strict=True)\n\nIn this case the above methods will only be called on actual QuerySet instances.\nNote that methods with custom handling of other iterables (like ``count`` and\n``order_by``) still work.\n\n\nUnsupported methods\n-------------------\n\nThe following methods cannot be supported in a heterogenic context:\n\n* ``create``\n\n* ``get_or_create``\n\n* ``bulk_create``\n\n\nMethods below are not supported yet but the support is planned in a future\nrelease:\n\n* ``aggregate``\n\n* ``annotate``\n\n* ``dates``\n\n* ``delete``\n\n* ``distinct``\n\n* ``get``\n\n* ``in_bulk``\n\n* ``reverse``\n\n* ``update``\n\n\nKnown issues\n------------\n\n1. If slicing or ``xfilter`` is used, reported ``len()`` is computed by\n iterating over all iterables so performance is weak. Note that ``len()`` is\n used by ``list()`` when you convert your chain to a list or when iterating\n over the chain in Django templates. If this is not expected, you can convert\n to a list using a workaround like this::\n\n list(e for e in some_chain)\n\n2. Indexing on chains uses iteration underneath so performance is weak. This\n feature is only available as a last resort. Slicing on the other hand is also\n lazy.\n\n3. Collective ``filter`` and ``exclude`` silently skip filtering on incompatible\n iterables. Use ``xfilter(value)`` as a workaround.\n\n\nHow do I run the tests?\n-----------------------\n\nThe easiest way would be to run::\n\n $ DJANGO_SETTINGS_MODULE=\"dj._chaintestproject.settings\" django-admin.py test\n\n\nChange Log\n----------\n\n0.9.2\n-----\n\n* Long overdue Python 3 support (considered experimental)\n\n\n0.9.1\n~~~~~\n\n* support for collective ``values`` and ``values_list`` transformations\n\n* support for collective ``defer``, ``extra``, ``only``, ``prefetch_related``,\n ``select_for_update``, ``select_related`` and ``using`` methods (silently\n ignored for incompatible iterables)\n\n* strict mode (non-QuerySet objects are not tried for compatibility with\n collective methods)\n\n* fixed an import error due to incomplete separation from ``lck.django``\n\n\n0.9.0\n~~~~~\n\n* code separated from ``lck.django``\n\n* support for collective sort using QuerySet-like ``order_by`` on a chain\n\n* fix for slices with custom steps\n\n* PEP8-fied all sources \n\n\nAuthors\n-------\n\nGlued together by `\u0141ukasz Langa `_.", "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/ambv/dj.chain/", "keywords": "django dj extra contrib chain iterator iteration queryset lazy", "license": "MIT", "maintainer": null, "maintainer_email": null, "name": "dj.chain", "package_url": "https://pypi.org/project/dj.chain/", "platform": "any", "project_url": "https://pypi.org/project/dj.chain/", "project_urls": { "Download": "UNKNOWN", "Homepage": "https://github.com/ambv/dj.chain/" }, "release_url": "https://pypi.org/project/dj.chain/0.9.2/", "requires_dist": null, "requires_python": null, "summary": "An object that enables chaining multiple iterables to serve them lazily as a queryset-compatible object.", "version": "0.9.2" }, "last_serial": 648554, "releases": { "0.9.0": [ { "comment_text": "", "digests": { "md5": "882bb5a66fe74e1d4162b96634e944d2", "sha256": "792f72788373cf274c835d7b171fa3431b9c6eeec4429147cfb854bbedb3ac91" }, "downloads": -1, "filename": "dj.chain-0.9.0.tar.gz", "has_sig": false, "md5_digest": "882bb5a66fe74e1d4162b96634e944d2", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 14231, "upload_time": "2012-11-06T02:00:03", "url": "https://files.pythonhosted.org/packages/91/50/398d9fa1f2c456acc1ab3c125ad2538ac586a80c25c34e62acd4491b444a/dj.chain-0.9.0.tar.gz" } ], "0.9.1": [ { "comment_text": "", "digests": { "md5": "4557f33660d4324ec9f9374921f3f89c", "sha256": "54c0633a764e4d7289f6230765a6b5e35bed5cb8c74b7eba5bfb639b4f75a5f0" }, "downloads": -1, "filename": "dj.chain-0.9.1.tar.gz", "has_sig": false, "md5_digest": "4557f33660d4324ec9f9374921f3f89c", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 17758, "upload_time": "2012-11-16T14:29:55", "url": "https://files.pythonhosted.org/packages/53/69/132df128f9cca7c276bac96f251db7f434184b095dc34b16f98c34a73c9b/dj.chain-0.9.1.tar.gz" } ], "0.9.2": [ { "comment_text": "", "digests": { "md5": "539230aa498f8d987cc6112c5684bb26", "sha256": "b52b0820b7939fef4e4f3b2132a40b934149d9433badba8a69acc5f7c46ee47b" }, "downloads": -1, "filename": "dj.chain-0.9.2.tar.gz", "has_sig": false, "md5_digest": "539230aa498f8d987cc6112c5684bb26", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 17993, "upload_time": "2013-03-05T12:33:08", "url": "https://files.pythonhosted.org/packages/52/ed/d534fa81cb6c9d0b24d933f2c062dbf694045f628de30ee689266e95755e/dj.chain-0.9.2.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "539230aa498f8d987cc6112c5684bb26", "sha256": "b52b0820b7939fef4e4f3b2132a40b934149d9433badba8a69acc5f7c46ee47b" }, "downloads": -1, "filename": "dj.chain-0.9.2.tar.gz", "has_sig": false, "md5_digest": "539230aa498f8d987cc6112c5684bb26", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 17993, "upload_time": "2013-03-05T12:33:08", "url": "https://files.pythonhosted.org/packages/52/ed/d534fa81cb6c9d0b24d933f2c062dbf694045f628de30ee689266e95755e/dj.chain-0.9.2.tar.gz" } ] }