Skip to content
Browse files

version 0.2

  • Loading branch information...
1 parent 4417fde commit 633789630ab65f8d52f5f60e8601d1eb150e8f97 @coordt coordt committed Aug 1, 2012
View
2 MANIFEST.in
@@ -7,3 +7,5 @@ recursive-include articleappkit/templates *
include LICENSE
include README
include *.txt
+
+prune example
View
7 articleappkit/__init__.py
@@ -1,14 +1,15 @@
"""
-django-articleappkit
+A set of classes to make creating text- or article-based Django apps easier.
"""
__version_info__ = {
'major': 0,
- 'minor': 1,
+ 'minor': 2,
'micro': 0,
- 'releaselevel': 'final',
+ 'releaselevel': 'beta',
'serial': 1
}
+
def get_version(short=False):
assert __version_info__['releaselevel'] in ('alpha', 'beta', 'final')
vers = ["%(major)i.%(minor)i" % __version_info__, ]
View
396 articleappkit/models.py
@@ -4,205 +4,259 @@
from django.core.files.images import get_image_dimensions
from django.utils.translation import ugettext_lazy as _
-from articleappkit.settings import (FIELDNAMES, UNIQUE_TOGETHER, AUTHOR_MODEL,
- AUTHOR_MODEL_LIMIT, IMAGE_STORAGE, IMAGE_UPLOAD_TO, STATUS_CHOICES,
- PUBLISHED_STATUS, DEFAULT_STATUS, UNPUBLISHED_STATUS)
+#
+# Can we use a factory function that takes a configuration, updates the default
+# configuration and returns the class? The result would be like
+#
+# ArticleBase = get_articlebase(CONFIG)
+#
+# class MyArticle(ArticleBase)
+#
+
from articleappkit.fields import ModelUploadFileField
-class ArticleBase(models.Model):
- """
- Base article content
- """
- title = models.CharField(
- _(FIELDNAMES.get('title', 'title')),
- max_length=255)
- subtitle = models.CharField(
- _(FIELDNAMES.get('subtitle', 'subtitle')),
- max_length=255,
- blank=True,
- null=True)
- slug = models.SlugField(
- _(FIELDNAMES.get('slug', 'slug')),
- max_length=255)
- summary = models.TextField(
- _(FIELDNAMES.get('summary', 'summary')),
- blank=True,
- null=True)
- content = models.TextField(_(FIELDNAMES.get('content', 'content')))
-
- create_date = models.DateTimeField(
- _(FIELDNAMES.get('create_date', 'create_date')),
- blank=True,
- editable=False)
- update_date = models.DateTimeField(
- _(FIELDNAMES.get('update_date', 'update date')),
- help_text=_("The update date/time to display to the user"),
- blank=True,
- null=True)
- modified_date = models.DateTimeField(
- _(FIELDNAMES.get('modified_date', 'modified date')),
- default=datetime.datetime.now,
- blank=True,
- editable=False)
-
- class Meta:
- abstract = True
- get_latest_by = 'modified_date'
- ordering = ('-modified_date',)
-
- if UNIQUE_TOGETHER:
- unique_together = UNIQUE_TOGETHER
-
- def __unicode__(self):
- return self.title
-
- def save(self, *args, **kwargs):
- if not self.id:
- self.create_date = datetime.datetime.now()
- super(ArticleBase, self).save(*args, **kwargs)
-
- objects = models.Manager()
+def get_articlebase(custom_config=None):
+
+ from articleappkit.settings import USER_SETTINGS as config
+
+ if custom_config is not None:
+ config.update(custom_config)
+
+ class ArticleBase(models.Model):
+ """
+ Base article content
+ """
+ title = models.CharField(
+ _(config['FIELDNAMES'].get('title', 'title')),
+ max_length=255)
+ subtitle = models.CharField(
+ _(config['FIELDNAMES'].get('subtitle', 'subtitle')),
+ max_length=255,
+ blank=True,
+ null=True)
+ slug = models.SlugField(
+ _(config['FIELDNAMES'].get('slug', 'slug')),
+ max_length=255)
+ summary = models.TextField(
+ _(config['FIELDNAMES'].get('summary', 'summary')),
+ blank=True,
+ null=True)
+ content = models.TextField(_(config['FIELDNAMES'].get('content', 'content')))
+
+ create_date = models.DateTimeField(
+ _(config['FIELDNAMES'].get('create_date', 'create_date')),
+ blank=True,
+ editable=False)
+ update_date = models.DateTimeField(
+ _(config['FIELDNAMES'].get('update_date', 'update date')),
+ help_text=_("The update date/time to display to the user"),
+ blank=True,
+ null=True)
+ modified_date = models.DateTimeField(
+ _(config['FIELDNAMES'].get('modified_date', 'modified date')),
+ default=datetime.datetime.now,
+ blank=True,
+ editable=False)
+
+ class Meta:
+ abstract = True
+ get_latest_by = 'modified_date'
+ ordering = ('-modified_date',)
+
+ if config['UNIQUE_TOGETHER']:
+ unique_together = config['UNIQUE_TOGETHER']
+
+ def __unicode__(self):
+ return self.title
+
+ def save(self, *args, **kwargs):
+ if not self.id:
+ self.create_date = datetime.datetime.now()
+ super(ArticleBase, self).save(*args, **kwargs)
+
+ objects = models.Manager()
+
+ return ArticleBase
###
# Attribution Mixins
###
-class SingleAuthorMixin(models.Model):
- """
- A mixin that adds a relation to another model (typically auth.User)
- """
- author = models.ForeignKey(
- AUTHOR_MODEL,
- verbose_name=_(FIELDNAMES.get('author', 'author')),
- blank=True,
- null=True,
- limit_choices_to=AUTHOR_MODEL_LIMIT)
+def get_singleauthormixin(custom_config=None):
+
+ from articleappkit.settings import USER_SETTINGS as config
+
+ if custom_config is not None:
+ config.update(custom_config)
+
+ class SingleAuthorMixin(models.Model):
+ """
+ A mixin that adds a relation to another model (typically auth.User)
+ """
+ author = models.ForeignKey(
+ config['AUTHOR_MODEL'],
+ verbose_name=_(config['FIELDNAMES'].get('author', 'author')),
+ blank=True,
+ null=True,
+ limit_choices_to=config['AUTHOR_MODEL_LIMIT'])
+
+ class Meta:
+ abstract = True
+ return SingleAuthorMixin
- class Meta:
- abstract = True
+def get_multiauthormixin(custom_config=None):
-class MutliAuthorMixin(models.Model):
- """
- A mixin that adds a many-to-many relation to another model
- """
- authors = models.ManyToManyField(
- AUTHOR_MODEL,
- verbose_name=_(FIELDNAMES.get('authors', 'authors')),
- blank=True,
- null=True,
- limit_choices_to=AUTHOR_MODEL_LIMIT)
+ from articleappkit.settings import USER_SETTINGS as config
+
+ if custom_config is not None:
+ config.update(custom_config)
+
+ class MultiAuthorMixin(models.Model):
+ """
+ A mixin that adds a many-to-many relation to another model
+ """
+ authors = models.ManyToManyField(
+ config['AUTHOR_MODEL'],
+ verbose_name=_(config['FIELDNAMES'].get('authors', 'authors')),
+ blank=True,
+ null=True,
+ limit_choices_to=config['AUTHOR_MODEL_LIMIT'])
- class Meta:
- abstract = True
+ class Meta:
+ abstract = True
+ return MultiAuthorMixin
-class NonStaffAuthorMixin(models.Model):
- """
- A mixin that adds a character field to set a one-time or non-staff author
- """
- non_staff_author = models.CharField(
- _(FIELDNAMES.get('non_staff_author', 'non-staff author')),
- max_length=200,
- blank=True,
- null=True,
- help_text=_("An HTML-formatted rendering of an author(s) not on staff."))
+def get_nonstaffauthormixin(custom_config=None):
- class Meta:
- abstract = True
+ from articleappkit.settings import USER_SETTINGS as config
+
+ if custom_config is not None:
+ config.update(custom_config)
+
+ class NonStaffAuthorMixin(models.Model):
+ """
+ A mixin that adds a character field to set a one-time or non-staff author
+ """
+ non_staff_author = models.CharField(
+ _(config['FIELDNAMES'].get('non_staff_author', 'non-staff author')),
+ max_length=200,
+ blank=True,
+ null=True,
+ help_text=_("An HTML-formatted rendering of an author(s) not on staff."))
+
+ class Meta:
+ abstract = True
+ return NonStaffAuthorMixin
###
# Key Image Mixin
###
-class KeyImageMixin(models.Model):
- """
- A mixin that adds a key image field and attribution
- """
- key_image = ModelUploadFileField(
- _(FIELDNAMES.get('key_image', 'key image')),
- null=True,
- blank=True,
- storage=IMAGE_STORAGE(),
- upload_to=IMAGE_UPLOAD_TO)
- key_image_width = models.IntegerField(editable=False, blank=True, null=True)
- key_image_height = models.IntegerField(editable=False, blank=True, null=True)
- key_image_credit = models.CharField(
- _(FIELDNAMES.get('key_image_credit', 'key image credit')),
- max_length=255,
- blank=True,
- null=True)
-
- class Meta:
- abstract = True
-
- def save(self, *args, **kwargs):
- if self.key_image:
- width, height = get_image_dimensions(self.key_image.file, close=True)
- else:
- width, height = None, None
-
- self.key_image_width = width
- self.key_image_height = height
-
- super(KeyImageMixin, self).save(*args, **kwargs)
+def get_keyimagemixin(custom_config=None):
+
+ from articleappkit.settings import USER_SETTINGS as config
+
+ if custom_config is not None:
+ config.update(custom_config)
+
+ class KeyImageMixin(models.Model):
+ """
+ A mixin that adds a key image field and attribution
+ """
+ key_image = ModelUploadFileField(
+ _(config['FIELDNAMES'].get('key_image', 'key image')),
+ null=True,
+ blank=True,
+ storage=config['IMAGE_STORAGE'](),
+ upload_to=config['IMAGE_UPLOAD_TO'])
+ key_image_width = models.IntegerField(editable=False, blank=True, null=True)
+ key_image_height = models.IntegerField(editable=False, blank=True, null=True)
+ key_image_credit = models.CharField(
+ _(config['FIELDNAMES'].get('key_image_credit', 'key image credit')),
+ max_length=255,
+ blank=True,
+ null=True)
+
+ class Meta:
+ abstract = True
+
+ def save(self, *args, **kwargs):
+ if self.key_image:
+ width, height = get_image_dimensions(self.key_image.file, close=True)
+ else:
+ width, height = None, None
+
+ self.key_image_width = width
+ self.key_image_height = height
+
+ super(KeyImageMixin, self).save(*args, **kwargs)
+ return KeyImageMixin
###
# PublishingMixin
###
-class PubWorkflowManager(models.Manager):
- def published(self):
- qset = super(PubWorkflowManager, self).get_query_set()
- qset.filter(
- status=PUBLISHED_STATUS,
- pub_date__lte=datetime.datetime.now(),
- pub_time__lte=datetime.datetime.now())
- return qset
-
-
-class PubWorkflowMixin(models.Model):
- """
- A Mixin that adds basic publishing info
- """
- status = models.IntegerField(
- _(FIELDNAMES.get('status', 'status')),
- choices=STATUS_CHOICES,
- default=DEFAULT_STATUS)
- pub_date = models.DateField(
- _(FIELDNAMES.get('pub_date', 'publish date')),
- null=True,
- blank=True)
- pub_time = models.TimeField(_(FIELDNAMES.get('pub_time', 'publish time')),
- null=True,
- blank=True)
-
- class Meta:
- abstract = True
-
- @property
- def published(self):
- """
- Shortcut to set the published status in the status field. Acts like a
- boolean.
- """
- return self.status == PUBLISHED_STATUS
+def get_pubworkflowmixin(custom_config=None):
+
+ from articleappkit.settings import USER_SETTINGS as config
+
+ if custom_config is not None:
+ config.update(custom_config)
+
+ class PubWorkflowManager(models.Manager):
+ def published(self):
+ qset = super(PubWorkflowManager, self).get_query_set()
+ qset.filter(
+ status=config['PUBLISHED_STATUS'],
+ pub_date__lte=datetime.datetime.now(),
+ pub_time__lte=datetime.datetime.now())
+ return qset
- @published.setter
- def set_published(self, value):
+ class PubWorkflowMixin(models.Model):
"""
- Set the status to the unpublished status or published status
+ A Mixin that adds basic publishing info
"""
- if bool(value):
- self.status = PUBLISHED_STATUS
- if not self.pub_date:
- self.pub_date = datetime.datetime.now()
- self.pub_time = datetime.datetime.now()
- else:
- self.status = UNPUBLISHED_STATUS
-
- objects = PubWorkflowManager()
+ status = models.IntegerField(
+ _(config['FIELDNAMES'].get('status', 'status')),
+ choices=config['STATUS_CHOICES'],
+ default=config['DEFAULT_STATUS'])
+ pub_date = models.DateField(
+ _(config['FIELDNAMES'].get('pub_date', 'publish date')),
+ null=True,
+ blank=True)
+ pub_time = models.TimeField(_(config['FIELDNAMES'].get('pub_time', 'publish time')),
+ null=True,
+ blank=True)
+
+ class Meta:
+ abstract = True
+
+ @property
+ def published(self):
+ """
+ Shortcut to set the published status in the status field. Acts like a
+ boolean.
+ """
+ return self.status == config['PUBLISHED_STATUS']
+
+ @published.setter
+ def set_published(self, value):
+ """
+ Set the status to the unpublished status or published status
+ """
+ if bool(value):
+ self.status = config['PUBLISHED_STATUS']
+ if not self.pub_date:
+ self.pub_date = datetime.datetime.now()
+ self.pub_time = datetime.datetime.now()
+ else:
+ self.status = config['UNPUBLISHED_STATUS']
+
+ objects = PubWorkflowManager()
+ return PubWorkflowMixin
View
11 articleappkit/tests.py
@@ -6,4 +6,13 @@ class articleappkitTest(TestCase):
Tests for django-articleappkit
"""
def test_articleappkit(self):
- pass
+ config1 = {'UNIQUE_TOGETHER': ('slug', 'create_date')}
+ from articleappkit.models import get_articlebase
+ ArticleBase1 = get_articlebase(config1)
+ self.assertEqual(ArticleBase1._meta.unique_together, (('slug', 'create_date'), ))
+
+ def test_articleappkit2(self):
+ config2 = {'UNIQUE_TOGETHER': ('slug', 'update_date')}
+ from articleappkit.models import get_articlebase
+ ArticleBase1 = get_articlebase(config2)
+ self.assertEqual(ArticleBase1._meta.unique_together, (('slug', 'update_date'), ))
View
11 doc_src/code_sample/case1_models.py
@@ -1,8 +1,13 @@
-from articleappkit.models import (ArticleBase, SingleAuthorMixin,
- KeyImageMixin, PublishingMixin)
+from articleappkit.models import (get_articlebase, get_singleauthormixin,
+ get_keyimagemixin, get_pubworkflowmixin)
+ArticleBase = get_articlebase()
+SingleAuthorMixin = get_singleauthormixin()
+KeyImageMixin = get_keyimagemixin()
+PubWorkflowMixin = get_pubworkflowmixin()
-class Story(ArticleBase, SingleAuthorMixin, KeyImageMixin, PublishingMixin):
+
+class Story(ArticleBase, SingleAuthorMixin, KeyImageMixin, PubWorkflowMixin):
"""
Creates a basic story model with a single author, related to auth.User,
It has a Key Image and contains some useful publishing metadata.
View
16 doc_src/getting_started.rst
@@ -2,15 +2,29 @@
Getting Started
===============
+
+Installation
+============
+
+Installation is easy using ``pip`` or ``easy_install``.
+
+.. code-block:: bash
+
+ pip install django-articleappkit
+
+
+
Simple Case
===========
-Article App Kit only consists of abstract models. Therefore you will create a brand new app. We'll call this app ``Story``.
+Article App Kit consists of abstract model factories. The model factory allows you to pass a configuration dictionary to set up each class. Django Article App Kit wasn't meant to work by itself. So you will create a brand new app. We'll call this app ``Story``.
**models.py**
.. literalinclude:: code_sample/case1_models.py
+In this simple case, we aren't going to change any of the defaults. After we import several model factories, we call them to retrieve the classes. The ``Story`` class inherits from these classes, and nothing else is required except providing a proper ``verbose_name``.
+
**admin.py**
.. literalinclude:: code_sample/case1_admin.py
View
1 doc_src/index.rst
@@ -17,6 +17,5 @@ Contents
:maxdepth: 2
:glob:
- installation
getting_started
reference/index
View
15 doc_src/installation.rst
@@ -1,15 +0,0 @@
-
-Installation
-============
-
-Installation is easy using ``pip`` or ``easy_install``.
-
-.. code-block:: bash
-
- pip install django-articleappkit
-
-or
-
-.. code-block:: bash
-
- easy_install django-articleappkit
View
9 example/simpleapp/models.py
@@ -1,5 +1,10 @@
-from articleappkit.models import (ArticleBase, SingleAuthorMixin,
- KeyImageMixin, PubWorkflowMixin)
+from articleappkit.models import (get_articlebase, get_singleauthormixin,
+ get_keyimagemixin, get_pubworkflowmixin)
+
+ArticleBase = get_articlebase()
+SingleAuthorMixin = get_singleauthormixin()
+KeyImageMixin = get_keyimagemixin()
+PubWorkflowMixin = get_pubworkflowmixin()
class Story(ArticleBase, SingleAuthorMixin, KeyImageMixin, PubWorkflowMixin):

0 comments on commit 6337896

Please sign in to comment.
Something went wrong with that request. Please try again.