Skip to content

Commit

Permalink
Version 0.1.0.
Browse files Browse the repository at this point in the history
  • Loading branch information
BertrandBordage committed Feb 28, 2016
0 parents commit 74dbc72
Show file tree
Hide file tree
Showing 14 changed files with 604 additions and 0 deletions.
56 changes: 56 additions & 0 deletions .gitignore
@@ -0,0 +1,56 @@
# Created by .ignore support plugin (hsz.mobi)
### Python template
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# C extensions
*.so

# Distribution / packaging
.Python
env/
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
*.egg-info/
.installed.cfg
*.egg

# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*,cover

# Django stuff:
*.log

# Sphinx documentation
docs/_build/

# PyBuilder
target/
Empty file added CHANGELOG.rst
Empty file.
27 changes: 27 additions & 0 deletions LICENSE
@@ -0,0 +1,27 @@
Copyright (c) 2016, Bertrand Bordage
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.

* Neither the name of django-tree nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2 changes: 2 additions & 0 deletions MANIFEST.in
@@ -0,0 +1,2 @@
include README.rst LICENSE CHANGELOG.rst requirements.txt
recursive-include tree *.js *.json *.html
106 changes: 106 additions & 0 deletions README.rst
@@ -0,0 +1,106 @@
Django-tree
===========

Fast and easy tree structures.

**In alpha, it can’t be used yet in production.**

This tool works in a very similar way to **django-mptt**
and **django-treebeard**, however it’s so different in conception
that it was better and faster to start from scratch
than to rewrite the existing solutions.

Compared to these solutions, django-tree aims to have these advantages
(some of them are already there):

- less intrusive (no more inheriting issues
due to Model, Manager & Queryset subclasses)
- easier to install
- easier to use
- more complete
- minimalist (less code, less database fields)
- bug-free
- safe (thanks to database constraints)
- faster for all operations

However, there is nothing groundbreaking here: this is only the result of
a proper use of the latest Django improvements, combined with a good knowledge
of SQL.


Installation
------------

Django-tree requires Django 1.8 or 1.9 and Python 3.
For the moment, django-tree is only for PostgreSQL because it uses a specific
data type not available in other databases. It will be adapted to also use
a standard text field in the future for other databases, but it will be slower.

After installing the module, you need to add `'tree',` to your
`INSTALLED_APPS`, then add a `PathField` to a model with a
`ForeignKey('self')`, typically named `parent` (use the `parent_field`
argument of `PathField` if the field has another name).
This should give you something like this:

.. code:: python
from django.db.models import Model, CharField, ForeignKey, BooleanField
from tree.fields import PathField
class YourModel(Model):
name = CharField(max_length=30)
parent = ForeignKey('self', null=True, blank=True)
path = PathField(null=True, blank=True)
public = BooleanField(default=False)
However, the model above is not ordered. The children of a same parent will be
ordered by primary key. You can specify how children are ordered using the
`order_by` argument of `PathField`. If needed, you can add a field for users
to explicitly order these objects. Example:

.. code:: python
from django.db.models import (
Model, CharField, ForeignKey, IntegerField, BooleanField)
from tree.fields import PathField
class YourModel(Model):
name = CharField(max_length=30)
parent = ForeignKey('self', null=True, blank=True)
position = IntegerField(default=1)
path = PathField(order_by=('position', 'name'), null=True, blank=True)
public = BooleanField(default=False)
Here, the children of a same parent will be ordered by position, and then
by name if the position is the same.


Usage
-----

A `PathField` is an automatic field, you don’t need to set, modify, or even see
its value once it is installed. But you can use the `Path` object it returns to
get tree information about the current instance, or make complex queries
on the whole tree structure. Example to show you most of the possibilities:

.. code:: python
obj = YourModel.objects.first()
obj.path.rebuild_tree() # Rebuilds the whole tree,
# typically useful after a major migration.
obj.path.level
obj.path.is_root
obj.path.is_leaf
obj.path.get_children()
obj.path.get_children().filter(public=True)
obj.path.get_ancestors()
obj.path.get_ancestors(include_self=True)
obj.path.get_descendants(include_self=True)
obj.path.get_siblings()
obj.path.get_prev_sibling() # Fetches the previous sibling.
obj.path.get_next_sibling()
# Same as `get_prev_sibling`, except that we get the first public one.
obj.path.get_prev_siblings().filter(public=True).first()
There is also a bunch of less useful lookups, transforms and functions
available. They will be documented with examples in the future.
1 change: 1 addition & 0 deletions requirements.txt
@@ -0,0 +1 @@
Django>=1.8,<1.10
38 changes: 38 additions & 0 deletions setup.py
@@ -0,0 +1,38 @@
#!/usr/bin/env python

import os
from setuptools import setup, find_packages
from tree import __version__


CURRENT_PATH = os.path.abspath(os.path.dirname(__file__))

with open(os.path.join(CURRENT_PATH, 'requirements.txt')) as f:
required = f.read().splitlines()


setup(
name='django-tree',
version=__version__,
author='Bertrand Bordage',
author_email='bordage.bertrand@gmail.com',
url='https://github.com/BertrandBordage/django-tree',
description='Fast and easy tree structures.',
long_description=open('README.rst').read(),
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',
],
license='BSD',
packages=find_packages(),
install_requires=required,
include_package_data=True,
zip_safe=False,
)
4 changes: 4 additions & 0 deletions tree/__init__.py
@@ -0,0 +1,4 @@
VERSION = (0, 1, 0)
__version__ = '.'.join(map(str, VERSION))

default_app_config = 'tree.apps.TreeAppConfig'
19 changes: 19 additions & 0 deletions tree/apps.py
@@ -0,0 +1,19 @@
from django.apps import AppConfig

from .fields import PathField
from .lookups import DescendantOf, AncestorOf, Match, MatchAny, Search
from .transforms import Level


class TreeAppConfig(AppConfig):
name = 'tree'
verbose_name = 'Tree'

def ready(self):
PathField.register_lookup(DescendantOf)
PathField.register_lookup(AncestorOf)
PathField.register_lookup(Match)
PathField.register_lookup(MatchAny)
PathField.register_lookup(Search)

PathField.register_lookup(Level)

0 comments on commit 74dbc72

Please sign in to comment.