From: Joseph Spiros Date: Wed, 25 May 2011 21:55:26 +0000 (-0400) Subject: Merge branch 'release' of git://github.com/melinath/philo X-Git-Tag: philo-0.9~10 X-Git-Url: http://git.ithinksw.org/philo.git/commitdiff_plain/886de29e37c1dbfe17a69c65d4aa010a0d60e1c1?hp=c19bf577d44606d2b284e6058d633f4a174b61cc Merge branch 'release' of git://github.com/melinath/philo * 'release' of git://github.com/melinath/philo: Minor correction to django-mptt requirements. Upped version information to 0.1rc. Switched from distutils to setuptools and added dependency information and metadata. Added documentation for has_navigation and navigation_host filters. Added examples of Node.navigation use to Navigation docs. Added more human-friendly general docs for shipherd. --- diff --git a/docs/contrib/shipherd.rst b/docs/contrib/shipherd.rst index 0f3b59d..915dac8 100644 --- a/docs/contrib/shipherd.rst +++ b/docs/contrib/shipherd.rst @@ -3,6 +3,26 @@ Shipherd .. automodule:: philo.contrib.shipherd :members: + + :class:`.Node`\ s are useful for structuring a website; however, they are inherently unsuitable for creating site navigation. + + The most glaring problem is that a navigation tree based on :class:`.Node`\ s would have one :class:`.Node` as the root, whereas navigation usually has multiple objects at the top level. + + Additionally, navigation needs to have display text that is relevant to the current context; however, :class:`.Node`\ s do not have a field for that, and :class:`.View` subclasses with a name or title field will generally need to use it for database-searchable names. + + Finally, :class:`.Node` structures are inherently unordered, while navigation is inherently ordered. + + :mod:`~philo.contrib.shipherd` exists to resolve these issues by separating navigation structures from :class:`.Node` structures. It is instead structured around the way that site navigation works in the wild: + + * A site may have one or more independent navigation bars (Main navigation, side navigation, etc.) + * A navigation bar may be shared by sections of the website, or even by the entire site. + * A navigation bar has a certain depth that it displays to. + + The :class:`.Navigation` model supplies these features by attaching itself to a :class:`.Node` via :class:`ForeignKey` and adding a :attr:`navigation` property to :class:`.Node` which provides access to a :class:`.Node` instance's inherited :class:`.Navigation`\ s. + + Each entry in the navigation bar is then represented by a :class:`.NavigationItem`, which stores information such as the :attr:`~.NavigationItem.order` and :attr:`~.NavigationItem.text` for the entry. Given an :class:`HttpRequest`, a :class:`.NavigationItem` can also tell whether it :meth:`~.NavigationItem.is_active` or :meth:`~.NavigationItem.has_active_descendants`. + + Since the common pattern is to recurse through a navigation tree and render each part similarly, :mod:`~philo.contrib.shipherd` also ships with the :ttag:`~philo.contrib.shipherd.templatetags.shipherd.recursenavigation` template tag. Models ++++++ @@ -28,3 +48,7 @@ Template tags .. automodule:: philo.contrib.shipherd.templatetags.shipherd .. autotemplatetag:: recursenavigation + +.. autotemplatefilter:: has_navigation + +.. autotemplatefilter:: navigation_host diff --git a/philo/__init__.py b/philo/__init__.py index 32297e0..e574b70 100644 --- a/philo/__init__.py +++ b/philo/__init__.py @@ -1 +1 @@ -VERSION = (0, 0) +VERSION = (0, '1rc') diff --git a/philo/contrib/shipherd/models.py b/philo/contrib/shipherd/models.py index f35be3c..a520fbe 100644 --- a/philo/contrib/shipherd/models.py +++ b/philo/contrib/shipherd/models.py @@ -179,6 +179,15 @@ class Navigation(Entity): """ :class:`Navigation` represents a group of :class:`NavigationItem`\ s that have an intrinsic relationship in terms of navigating a website. For example, a ``main`` navigation versus a ``side`` navigation, or a ``authenticated`` navigation versus an ``anonymous`` navigation. + A :class:`Navigation`'s :class:`NavigationItem`\ s will be accessible from its related :class:`.Node` and that :class:`.Node`'s descendants through a :class:`NavigationMapper` instance at :attr:`Node.navigation`. Example:: + + >>> node.navigation_set.all() + [] + >>> parent = node.parent + >>> items = parent.navigation_set.get(key='main').roots.all() + >>> parent.navigation["main"] == node.navigation["main"] == list(items) + True + """ #: A :class:`NavigationManager` instance. objects = NavigationManager() diff --git a/philo/contrib/shipherd/templatetags/shipherd.py b/philo/contrib/shipherd/templatetags/shipherd.py index 508eace..9e572aa 100644 --- a/philo/contrib/shipherd/templatetags/shipherd.py +++ b/philo/contrib/shipherd/templatetags/shipherd.py @@ -155,6 +155,7 @@ def recursenavigation(parser, token): @register.filter def has_navigation(node, key=None): + """Returns ``True`` if the node has a :class:`.Navigation` with the given key and ``False`` otherwise. If ``key`` is ``None``, returns whether the node has any :class:`.Navigation`\ s at all.""" try: nav = node.navigation if key is not None: @@ -169,6 +170,7 @@ def has_navigation(node, key=None): @register.filter def navigation_host(node, key): + """Returns the :class:`.Node` which hosts the :class:`.Navigation` which ``node`` has inherited for ``key``. Returns ``node`` if any exceptions are encountered.""" try: return Navigation.objects.filter(node__in=node.get_ancestors(include_self=True), key=key).order_by('-node__level')[0].node except: diff --git a/setup.py b/setup.py index 3c18b16..6dca288 100644 --- a/setup.py +++ b/setup.py @@ -1,6 +1,6 @@ #!/usr/bin/env python -from distutils.core import setup +from setuptools import setup import os @@ -40,8 +40,43 @@ for dirpath, dirnames, filenames in os.walk(philo_dir): version = __import__('philo').VERSION setup( - name = 'Philo', - version = '%s.%s' % (version[0], version[1]), + name = 'philo', + version = '.'.join([str(v) for v in version]), + url = "https://github.com/ithinksw/philo", + description = "A foundation for developing web content management systems.", + long_description = open(os.path.join(root_dir, 'README.markdown')).read(), + maintainer = "Joseph Spiros", + maintainer_email = "joseph.spiros@ithinksw.com", packages = packages, data_files = data_files, + + classifiers = [ + 'Environment :: Web Environment', + 'Framework :: Django', + 'Intended Audience :: Developers', + 'License :: OSI Approved :: ISC License (ISCL)', + 'Operating System :: OS Independent', + 'Programming Language :: Python', + 'Topic :: Internet :: WWW/HTTP :: Dynamic Content', + 'Topic :: Software Development :: Libraries :: Application Frameworks', + ], + platforms = ['OS Independent'], + license = 'ISC License (ISCL)', + + install_requires = [ + 'django>=1.3', + 'python>=2.5.4', + 'django-mptt>0.4.2,==dev', + ], + extras_require = { + 'docs': ["sphinx>=1.0"], + 'grappelli': ['django-grappelli>=2.3'], + 'migrations': ['south>=0.7.2'], + 'waldo-recaptcha': ['recaptcha-django'], + 'sobol-eventlet': ['eventlet'], + 'sobol-scrape': ['BeautifulSoup'], + }, + dependency_links = [ + 'https://github.com/django-mptt/django-mptt/tarball/master#egg=django-mptt-dev' + ] ) \ No newline at end of file