{ "info": { "author": "Bertrand Bordage", "author_email": "bordage.bertrand@gmail.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 3 - Alpha", "Framework :: Django", "Intended Audience :: Developers", "License :: OSI Approved :: BSD License", "Operating System :: OS Independent", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Topic :: Internet :: WWW/HTTP" ], "description": "Django-tree\n===========\n\nFast and easy tree structures.\n\n.. image:: http://img.shields.io/pypi/v/django-tree.svg?style=flat-square\n :target: https://pypi.python.org/pypi/django-tree\n\n.. image:: http://img.shields.io/travis/BertrandBordage/django-tree/master.svg?style=flat-square\n :target: https://travis-ci.org/BertrandBordage/django-tree\n\n.. image:: http://img.shields.io/coveralls/BertrandBordage/django-tree/master.svg?style=flat-square\n :target: https://coveralls.io/r/BertrandBordage/django-tree?branch=master\n\n**In alpha, it can\u2019t be used yet in production.**\n\nThis tool works in a very similar way to **django-mptt**\nand **django-treebeard**, however it\u2019s so different in conception\nthat it was better and faster to start from scratch\nthan to rewrite the existing solutions.\n\nCompared to these solutions, django-tree aims to have these advantages\n(some of them are already there):\n\n- less intrusive (no more inheriting issues\n due to Model, Manager & Queryset subclasses)\n- easier to install\n- easier to use\n- more complete\n- minimalist (less code, less database fields)\n- bug-free\n- safe (most of the logic is written directly in database)\n- faster for all operations\n\nHowever, there is nothing groundbreaking here: this is only the result of\na proper use of the latest Django improvements, combined with a good knowledge\nof SQL.\n\n\nInstallation\n------------\n\nDjango-tree requires Django 1.8, 1.11 or 2.0 and Python 2 or 3.\nFor the moment, django-tree is only for PostgreSQL.\nIt will be adapted in the future for other databases.\n\nAfter installing the module, you need to add ``'tree',`` to your\n``INSTALLED_APPS``, then add a ``PathField`` to a model with a\n``ForeignKey('self')``, typically named ``parent`` (use the ``parent_field``\nargument of ``CreateTreeTrigger`` if the field has another name).\n``PathField`` stores ``Path`` objects which have methods to execute queries,\nsuch as getting all the descendants of the current object, its siblings, etc.\nTo call these methods more conveniently, you can add ``TreeModelMixin``\nto your model. The inheriting order is not important, as the mixin methods\ndo not clash with Django. If you have multiple ``PathField``\non the same model, you will have to specify the field name in the method\nyou\u2019re calling using ``path_field``.\n\nThis should give you a model like this:\n\n.. code:: python\n\n from django.db.models import Model, CharField, ForeignKey, BooleanField\n from tree.fields import PathField\n from tree.models import TreeModelMixin\n\n class YourModel(Model, TreeModelMixin):\n name = CharField(max_length=30)\n parent = ForeignKey('self', null=True, blank=True)\n path = PathField()\n public = BooleanField(default=False)\n\n class Meta:\n ordering = ('path',)\n\nThen you need to create the SQL trigger that will automatically update ``path``.\nTo do that, create a migration with a dependency\nto the latest django-tree migration and add a ``CreateTreeTrigger`` operation:\n\n.. code:: python\n\n from django.db import migrations\n from tree.operations import CreateTreeTrigger\n\n class Migration(migrations.Migration):\n dependencies = [\n ('tree', '0001_initial'),\n ]\n\n operations = [\n CreateTreeTrigger('your_app.YourModel'),\n ]\n\nIf you already have data in ``YourModel``, you will need to add an operation\nfor allowing SQL ``NULL`` values before creating the trigger,\nthen rebuild the paths and revert the allowance of ``NULL`` values:\n\n.. code:: python\n\n from django.db import migrations\n from tree.fields import PathField\n from tree.operations import CreateTreeTrigger, RebuildPaths\n\n class Migration(migrations.Migration):\n dependencies = [\n ('tree', '0001_initial'),\n ]\n\n operations = [\n migrations.AlterField('YourModel', 'path', PathField(null=True)),\n CreateTreeTrigger('YourModel'),\n RebuildPaths('YourModel', 'path'),\n migrations.AlterField('YourModel', 'path', PathField()),\n ]\n\nHowever, the model above is not ordered. The children of a same parent will be\nordered by primary key. You can specify how children are ordered using the\n``order_by`` argument of ``PathField``. If needed, you can add a field\nfor users to explicitly order these objects, typically a position field.\nExample model:\n\n.. code:: python\n\n from django.db.models import (\n Model, CharField, ForeignKey, IntegerField, BooleanField)\n from tree.fields import PathField\n from tree.models import TreeModelMixin\n\n class YourModel(Model, TreeModelMixin):\n name = CharField(max_length=30)\n parent = ForeignKey('self', null=True, blank=True)\n position = IntegerField(default=1)\n path = PathField(order_by=['position', 'name'])\n public = BooleanField(default=False)\n\n class Meta:\n ordering = ('path',)\n\nAnd the corresponding migration:\n\n.. code:: python\n\n from django.db import models, migrations\n from tree.operations import CreateTreeTrigger\n\n class Migration(migrations.Migration):\n dependencies = [\n ('tree', '0001_initial'),\n ]\n\n operations = [\n migrations.AddField('YourModel', 'position',\n models.IntegerField(default=1))\n CreateTreeTrigger('YourModel'),\n ]\n\nHere, the children of a same parent will be ordered by position, and then\nby name if the position is the same.\n\n.. note::\n\n You can also use ``PathField`` without adding a ``CreateTreeTrigger``\n operation. However, the field will not automatically be updated, you\n will have to do it by yourself. In most cases this is not useful, so you\n should not use ``PathField`` without ``CreateTreeTrigger`` unless you know\n what you are doing.\n\n\nUsage\n-----\n\n``PathField`` is automatically filled thanks to ``CreateTreeTrigger``,\nyou don\u2019t need to set, modify, or even see its value once it is installed.\nBut you can use the ``Path`` object it stores or the more convenient\n``TreeModelMixin`` to get tree information about the current instance,\nor make complex queries on the whole tree structure.\nExample to show you most of the possibilities:\n\n.. code:: python\n\n obj = YourModel.objects.all()[0]\n obj.path.get_level()\n obj.get_level() # Shortcut for the previous method, if you use\n # `TreeModelMixin`. Same for other object methods below.\n obj.is_root()\n obj.is_leaf()\n obj.get_children()\n obj.get_children().filter(public=True)\n obj.get_ancestors()\n obj.get_ancestors(include_self=True)\n obj.get_descendants(include_self=True)\n obj.get_siblings()\n obj.get_prev_sibling() # Fetches the previous sibling.\n obj.get_next_sibling()\n # Same as `get_prev_sibling`, except that we get the first public one.\n obj.get_prev_siblings().filter(public=True).first()\n other = YourModel.objects.all()[1]\n obj.is_ancestor_of(other)\n obj.is_descendant_of(other, include_self=True)\n YourModel.get_roots()\n\n #\n # Advanced usage\n # Use the following methods only if you understand exactly what they mean.\n #\n\n YourModel.rebuild_paths() # Rebuilds all paths of this field, useful only\n # if something is broken, which shouldn\u2019t happen.\n YourModel.disable_tree_trigger() # Disables the SQL trigger.\n YourModel.enable_tree_trigger() # Restores the SQL trigger.\n with YourModel.disabled_tree_trigger():\n # What happens inside this context manager is ignored\n # by the SQL trigger.\n # The trigger is restored after that, even if there an error occurred.\n pass\n\nThere is also a bunch of less useful lookups and transforms\navailable. They will be documented with examples in the future.\n\n\nDifferences with MPTT and treebeard\n-----------------------------------\n\nLevel vs depth\n..............\n\ndjango-mptt and django-treebeard use two different names to designate almost\nthe same thing: MPTT uses level and treebeard uses depth.\nBoth are integers to show how much distant is a node from the top of the tree.\nThe only difference is that level should start by convention with 1 and depth\nshould start with 0.\n\nUnfortunately, **both MPTT and treebeard are wrong about the indexing**:\nMPTT starts its level with 0 and treebeard starts its depth with 1.\n\n**Django-tree finally fixes this issue by implementing a level starting by 1**,\nand no depth to avoid confusion. One name had to be chosen, and I find that\n\u201clevel\u201d represents more accurately the idea that we deal with an abstract tree,\nwhere all the node of the same level are on the same row.\nIn comparison, \u201cdepth\u201d sounds like we\u2019re actually digging a real root,\nand it gives the impression that a child of a root\ncan be at a different depth than a child of another root, like in real life.\n", "description_content_type": "", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/BertrandBordage/django-tree", "keywords": "", "license": "BSD", "maintainer": "", "maintainer_email": "", "name": "django-tree", "package_url": "https://pypi.org/project/django-tree/", "platform": "", "project_url": "https://pypi.org/project/django-tree/", "project_urls": { "Homepage": "https://github.com/BertrandBordage/django-tree" }, "release_url": "https://pypi.org/project/django-tree/0.3.2/", "requires_dist": null, "requires_python": "", "summary": "Fast and easy tree structures.", "version": "0.3.2" }, "last_serial": 3700906, "releases": { "0.1.0": [ { "comment_text": "", "digests": { "md5": "6c6ef16028f70059c1bc7309f7d98253", "sha256": "734fc9ea7867bcdbb70c6aeb6ba8f9b2cf53debba4d9d4c47f2a23ca99d5a071" }, "downloads": -1, "filename": "django_tree-0.1.0-py3-none-any.whl", "has_sig": false, "md5_digest": "6c6ef16028f70059c1bc7309f7d98253", "packagetype": "bdist_wheel", "python_version": "3.6", "requires_python": null, "size": 34028, "upload_time": "2018-03-23T16:24:35", "url": "https://files.pythonhosted.org/packages/be/d8/882d45b4f32fbf0503d667eff6d0d30c172c1cf4fdc2c5bfffaab9d90bc6/django_tree-0.1.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "95a32e5bb6684444d8c189b15379a2f6", "sha256": "ca4f9e51101b33f3f7d3a799bbfe5152429ca7e1461a6ec84f64f601cda999dc" }, "downloads": -1, "filename": "django-tree-0.1.0.tar.gz", "has_sig": false, "md5_digest": "95a32e5bb6684444d8c189b15379a2f6", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 30244, "upload_time": "2018-03-23T16:24:33", "url": "https://files.pythonhosted.org/packages/88/69/483b12abfb2638dd20aa5d205562103ac597e815ad8dcc1bfd165b91dac2/django-tree-0.1.0.tar.gz" } ], "0.2.0": [ { "comment_text": "", "digests": { "md5": "1b283ae85b8cb6f36043de225b7f06ba", "sha256": "55a8c8746a37adafad23b3a937d07ac20d733ca5e1fbb980b08b78a2d0430940" }, "downloads": -1, "filename": "django_tree-0.2.0-py3-none-any.whl", "has_sig": false, "md5_digest": "1b283ae85b8cb6f36043de225b7f06ba", "packagetype": "bdist_wheel", "python_version": "3.6", "requires_python": null, "size": 34023, "upload_time": "2018-03-23T16:35:56", "url": "https://files.pythonhosted.org/packages/be/93/baa46270827b3e16c6538f0c9b32eed060a38e60d5183f0923c27a193bf6/django_tree-0.2.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "25c583c4eb48089c65c755cf176811f1", "sha256": "374d746254f21bb559a256c009cb5a922a742ba143628b0b64204c8eadf07db1" }, "downloads": -1, "filename": "django-tree-0.2.0.tar.gz", "has_sig": false, "md5_digest": "25c583c4eb48089c65c755cf176811f1", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 30248, "upload_time": "2018-03-23T16:35:54", "url": "https://files.pythonhosted.org/packages/47/f9/dbddfc56ad1e61d9f5092417a096bf696db4f22f85d4ce66f1b84dc39492/django-tree-0.2.0.tar.gz" } ], "0.3.0": [ { "comment_text": "", "digests": { "md5": "3c07fadcc75673e05415cf0e6daee627", "sha256": "802e7b152ddde9ad87c381a0353ee7b8bfb83c1b6ac0e758d0d93004e276021e" }, "downloads": -1, "filename": "django_tree-0.3.0-py3-none-any.whl", "has_sig": false, "md5_digest": "3c07fadcc75673e05415cf0e6daee627", "packagetype": "bdist_wheel", "python_version": "3.6", "requires_python": null, "size": 35326, "upload_time": "2018-03-23T22:43:36", "url": "https://files.pythonhosted.org/packages/ff/f5/e3fb2578c81d045fb925736ca74935d97c4a354b1b7b72e795ed3fae73e6/django_tree-0.3.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "82af1a47c03979466b8b98d84e52bd1d", "sha256": "0161a870ad579f6f364f493e7f03332084cbf4ef72cbb8d6f30f2985d81abb7f" }, "downloads": -1, "filename": "django-tree-0.3.0.tar.gz", "has_sig": false, "md5_digest": "82af1a47c03979466b8b98d84e52bd1d", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 31149, "upload_time": "2018-03-23T22:43:34", "url": "https://files.pythonhosted.org/packages/16/b1/638ae29224a26163a29b89dfc5cd7e96b3d28bc60cc6d63f3afc9de7f30c/django-tree-0.3.0.tar.gz" } ], "0.3.1": [ { "comment_text": "", "digests": { "md5": "094d51b901dbeade4d57dd0bd76db626", "sha256": "8597c901661928c1fdc70fe9a03fec6e8639989ce896a57d02c98352737bd1af" }, "downloads": -1, "filename": "django_tree-0.3.1-py3-none-any.whl", "has_sig": false, "md5_digest": "094d51b901dbeade4d57dd0bd76db626", "packagetype": "bdist_wheel", "python_version": "3.6", "requires_python": null, "size": 35384, "upload_time": "2018-03-24T02:28:43", "url": "https://files.pythonhosted.org/packages/47/3e/e2b1e18d535a109a2853ab42468708c33fe4fedb39dfa2c0cab70c6a5e6c/django_tree-0.3.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "83c596d3666d0503490a363999667032", "sha256": "fa5b1794b21b33137f7a57fb8f0114a530d545d0a96fee9e8a28b16e81be88b6" }, "downloads": -1, "filename": "django-tree-0.3.1.tar.gz", "has_sig": false, "md5_digest": "83c596d3666d0503490a363999667032", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 31191, "upload_time": "2018-03-24T02:28:41", "url": "https://files.pythonhosted.org/packages/e1/2c/a2c81b75656a6b7409ef1846d5e48f0ba520450b058419d2d39fa71adb6d/django-tree-0.3.1.tar.gz" } ], "0.3.2": [ { "comment_text": "", "digests": { "md5": "81d691959bb21017d65d6d796549411e", "sha256": "9df8d5b15a083ca457bcca2294d4241f8d0b41db6e18df9697a3c09c522ad9de" }, "downloads": -1, "filename": "django_tree-0.3.2-py3-none-any.whl", "has_sig": false, "md5_digest": "81d691959bb21017d65d6d796549411e", "packagetype": "bdist_wheel", "python_version": "3.6", "requires_python": null, "size": 35587, "upload_time": "2018-03-24T04:30:41", "url": "https://files.pythonhosted.org/packages/bd/f7/4e0a5bbe3bec1b27c7887b090b15a5d7209daec731b96c0d8130d220f072/django_tree-0.3.2-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "12ddb72e857bdd868d6a4adb42bfcd03", "sha256": "bd1528e9cedfb0b7d25b47a827ec4ff40741d510d387f17b2213f175b1377ec1" }, "downloads": -1, "filename": "django-tree-0.3.2.tar.gz", "has_sig": false, "md5_digest": "12ddb72e857bdd868d6a4adb42bfcd03", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 31390, "upload_time": "2018-03-24T04:30:39", "url": "https://files.pythonhosted.org/packages/ce/da/4976a3f46dac026ef1dba74dfc9d2032e8b5ca904c74fcbbee7313705124/django-tree-0.3.2.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "81d691959bb21017d65d6d796549411e", "sha256": "9df8d5b15a083ca457bcca2294d4241f8d0b41db6e18df9697a3c09c522ad9de" }, "downloads": -1, "filename": "django_tree-0.3.2-py3-none-any.whl", "has_sig": false, "md5_digest": "81d691959bb21017d65d6d796549411e", "packagetype": "bdist_wheel", "python_version": "3.6", "requires_python": null, "size": 35587, "upload_time": "2018-03-24T04:30:41", "url": "https://files.pythonhosted.org/packages/bd/f7/4e0a5bbe3bec1b27c7887b090b15a5d7209daec731b96c0d8130d220f072/django_tree-0.3.2-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "12ddb72e857bdd868d6a4adb42bfcd03", "sha256": "bd1528e9cedfb0b7d25b47a827ec4ff40741d510d387f17b2213f175b1377ec1" }, "downloads": -1, "filename": "django-tree-0.3.2.tar.gz", "has_sig": false, "md5_digest": "12ddb72e857bdd868d6a4adb42bfcd03", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 31390, "upload_time": "2018-03-24T04:30:39", "url": "https://files.pythonhosted.org/packages/ce/da/4976a3f46dac026ef1dba74dfc9d2032e8b5ca904c74fcbbee7313705124/django-tree-0.3.2.tar.gz" } ] }