Welcome to dj-contentmodel’s documentation!¶
Contents:
dj-contentmodel¶
Boilerplate for taxonomies, content collections, and content models using django-mptt and django-taggit.
Features¶
- Drag and drop construction of taxonomies.
- Arbitrary relationships among groups, taxonomies, collections, content, and attachments.
- Templates for displaying taxonomies with and without collections’ contents.
Documentation¶
dj-content model is just boilerplate for django-mptt and django-taggit. It defines a hierarchical structure with arbitrary relationships via collections. The Quickstart example is a sufficient starting point for many projects. Each abstract class provided by dj-contentmodel is a descendant of django.db.models, so extend them as you would a Django model. The Group and Taxonomy classes are also descendants of django-mptt’s MPTTModel class and can be extended accordingly. Additional examples dj-contentmodel’s abstract classes are available at https://dj-contentmodel.readthedocs.org.
Quickstart¶
First, install dj-contentmodel:
pip install dj-contentmodel
Then, import the abstract base classes.:
from dj_contentmodel.models import Taxonomy, Collection, Content, Attachment
Next, subclass the imported classes to create taxonomies and content models as needed. The following example is of a minimum configuration. The names of defined classes are arbitrary, but the relationships among classes are not.
class Sitemap(Taxonomy):
"""Main navigation"""
collections = models.ManyToManyField('Bucket', blank=True)
class Meta:
verbose_name = "Category"
verbose_name_plural = "Categories"
...
class Bucket(Collection):
"""Arbitrary collections to group content."""
contents = models.ManyToManyField('Page', blank=True)
...
class Page(Content):
...
class Report(Attachment):
parents = models.ManyToManyField('Page', blank=True)
...
Finally, register your models with the admin.
from django.contrib import admin
from mptt.admin import DraggableMPTTAdmin
admin.site.register(
Sitemap,
DraggableMPTTAdmin,
list_display=(
'tree_actions',
'indented_title',),
list_display_links=(
'indented_title',),)
admin.site.register(Bucket)
admin.site.register(Page)
admin.site.register(Report)
Without a migration, it may be necessary to create the tables.:
python manage.py migrate --run-syncdb
Running Tests¶
Does the code actually work? For now I have my fingers crossed. Later iterations will be test driven and include integration and performance testing.
source <YOURVIRTUALENV>/bin/activate
(myenv) $ pip install -r requirements_test.txt
(myenv) $ python runtests.py
Credits¶
Tools used in rendering this package:
Installation¶
At the command line.
$ easy_install dj-contentmodel
If you have virtualenvwrapper installed.
$ mkvirtualenv dj-contentmodel
$ pip install dj-contentmodel
If you are using conda.
$ conda create --name dj-contentmodel python=3.5
$ source activate dj-contentmodel
$ pip install dj-contentmodel
Usage¶
First, install dj-contentmodel:
pip install dj-contentmodel
Add django-mptt, django-taggit, and dj-contentmodel in INSTALLED_APPS.
INSTALLED_APPS = [
...
'mptt',
'taggit',
'dj_contentmodel',
...
]
Then, import the abstract base classes.:
from dj_contentmodel.models import Taxonomy, Collection, Content, Attachment
Next, subclass the imported classes to create taxonomies and content models as needed. The following example is of a minimum configuration. The names of defined classes are arbitrary, but the relationships among classes are not.
class Sitemap(AbstractTaxonomy):
"""Main navigation"""
collections = models.ManyToManyField('Collection', blank=True)
class Collection(AbstractCollection):
"""Arbitrary collections to group content."""
contents = models.ManyToManyField('Page', blank=True)
class Page(AbstractContent):
body = models.TextField(blank=True, null=True)
class Attachment(AbstractAttachment):
parents = models.ManyToManyField('Page', blank=True)
After creating your models register the subclass of Taxonomy using DraggableMPTTAdmin. Collection, Content, and Attachment subclasses do not require customization.
from django.contrib import admin
from mptt.admin import DraggableMPTTAdmin
from .models import Sitemap, Collection, Page, Attachment
admin.site.register(
Sitemap,
DraggableMPTTAdmin,
list_display=(
'tree_actions',
'indented_title',),
list_display_links=(
'indented_title',),)
admin.site.register(Collection)
admin.site.register(Page)
admin.site.register(Attachment)
Without a migration, it may be necessary to create the tables using syncdb.
python manage.py migrate --run-syncdb
python manage.py migrate dj-contentmodel
Once a taxonomy is defined and registered in the admin, create your views. For simplicity, funtional views are shown here but class based views are preferred. Until authentication and authorization are implemented, you may filter taxonomies by group to feign authorization but this is not secure.
from django.shortcuts import render_to_response, RequestContext
from .models import Sitemap
def get_content_tree(request, group=None):
if group == None:
nodes = Sitemap.objects.all()
else:
nodes = Sitemap.objects.filter(groups=group)
templatePath = "dj_contentmodel/taxonomy.html" #use navigation.html to omit content nodes
return render_to_response(templatePath, {'nodes': nodes}, context_instance=RequestContext(request))
Then, create your urls.
urlpatterns = [
url(r'^navigation/(?P<group>[0-9]+)?$', views.get_navigation_tree),
url(r'^sitemap/(?P<group>[0-9]+)?$', views.get_content_tree),
]
Finally, create a template from the templates provided.
Sitemap.
{% load mptt_tags %}
{% load staticfiles %}
<ul>
{% recursetree nodes %}
<li>
<a href="{% url 'app:url' %}{{ node.id }}">{{ node.name }}</a>
{% if not node.is_leaf_node %}
<ul class="children">
{{ children }}
</ul>
{% endif %}
</li>
{% endrecursetree %}
</ul>
Sitemap and associated content. Additional tags are provided by django-mptt and django-taggit.Note that content assigned to multiple collections associated with the same taxa will display duplicate content.
{% load mptt_tags %}
<ul>
{% recursetree nodes %}
<li>
<a href="{% url 'app:url' %}{{ node.id }}">{{ node.name }}</a>
{% if not node.is_leaf_node %}
<ul class="children">
{{ children }}
</ul>
{% endif %}
{% if node.collections.contents.count > 0 %}
<ul>
{% for content in node.collections.contents.prefetch_related %}
<li><a href="{% url 'app:url' %}{{ content.id }}">{{ content.name }}</a></li>
{% endfor %}
</ul>
{% endif %}
</li>
{% endrecursetree %}
</ul>
Contributing¶
Contributions are welcome, and they are greatly appreciated! Every little bit helps, and credit will always be given.
You can contribute in many ways:
Types of Contributions¶
Report Bugs¶
Report bugs at https://github.com/infosmith/dj-contentmodel/issues.
If you are reporting a bug, please include:
- Your operating system name and version.
- Any details about your local setup that might be helpful in troubleshooting.
- Detailed steps to reproduce the bug.
Fix Bugs¶
Look through the GitHub issues for bugs. Anything tagged with “bug” is open to whoever wants to implement it.
Implement Features¶
Look through the GitHub issues for features. Anything tagged with “feature” is open to whoever wants to implement it.
Write Documentation¶
dj-contentmodel could always use more documentation, whether as part of the official dj-contentmodel docs, in docstrings, or even on the web in blog posts, articles, and such.
Submit Feedback¶
The best way to send feedback is to file an issue at https://github.com/infosmith/dj-contentmodel/issues.
If you are proposing a feature:
- Explain in detail how it would work.
- Keep the scope as narrow as possible, to make it easier to implement.
- Remember that this is a volunteer-driven project, and that contributions are welcome :)
Get Started!¶
Ready to contribute? Here’s how to set up dj-contentmodel for local development.
Fork the dj-contentmodel repo on GitHub.
Clone your fork locally:
$ git clone git@github.com:your_name_here/dj-contentmodel.git
Install your local copy into a virtualenv. Assuming you have virtualenvwrapper installed, this is how you set up your fork for local development:
$ mkvirtualenv dj-contentmodel $ cd dj-contentmodel/ $ python setup.py develop
Create a branch for local development:
$ git checkout -b name-of-your-bugfix-or-feature
Now you can make your changes locally.
When you’re done making changes, check that your changes pass flake8 and the tests, including testing other Python versions with tox:
$ flake8 dj_contentmodel tests $ python setup.py test $ tox
To get flake8 and tox, just pip install them into your virtualenv.
Commit your changes and push your branch to GitHub:
$ git add . $ git commit -m "Your detailed description of your changes." $ git push origin name-of-your-bugfix-or-feature
Submit a pull request through the GitHub website.
Pull Request Guidelines¶
Before you submit a pull request, check that it meets these guidelines:
- The pull request should include tests.
- If the pull request adds functionality, the docs should be updated. Put your new functionality into a function with a docstring, and add the feature to the list in README.rst.
- The pull request should work for Python 2.6, 2.7, and 3.3, and for PyPy. Check https://travis-ci.org/infosmith/dj-contentmodel/pull_requests and make sure that the tests pass for all supported Python versions.
Credits¶
Development Lead¶
- David S. <infosmith@protonmail.com>
Contributors¶
None yet. Why not be the first?