Skip to content

Commit

Permalink
Merge branch '0.8'
Browse files Browse the repository at this point in the history
  • Loading branch information
Corey Oordt committed Aug 22, 2011
2 parents bc7fa90 + a937dfd commit 1e049b9
Show file tree
Hide file tree
Showing 23 changed files with 216 additions and 61 deletions.
11 changes: 11 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,17 @@ Django Categories grew out of our need to provide a basic hierarchical taxonomy

As a news site, our stories, photos, and other content get divided into "sections" and we wanted all the apps to use the same set of sections. As our needs grew, the Django Categories grew in the functionality it gave to category handling within web pages.

New in 0.8
==========

**Added an active field**
As an alternative to deleting categories, you can make them inactive.

Also added a manager method ``active()`` to query only the active categories and added Admin Actions to activate or deactivate an item.

**Improved import**
Previously the import saved items in the reverse order to the imported file. Now them import in order.

New in 0.7
==========

Expand Down
4 changes: 2 additions & 2 deletions categories/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
__version_info__ = {
'major': 0,
'minor': 7,
'micro': 2,
'minor': 8,
'micro': 0,
'releaselevel': 'final',
'serial': 1
}
Expand Down
27 changes: 25 additions & 2 deletions categories/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,12 +78,12 @@ def clean(self):

class CategoryAdmin(TreeEditor, admin.ModelAdmin):
form = CategoryAdminForm
list_display = ('name', 'alternate_title', )
list_display = ('name', 'alternate_title', 'active')
search_fields = ('name', 'alternate_title', )
prepopulated_fields = {'slug': ('name',)}
fieldsets = (
(None, {
'fields': ('parent', 'name', 'thumbnail')
'fields': ('parent', 'name', 'thumbnail', 'active')
}),
('Meta Data', {
'fields': ('alternate_title', 'alternate_url', 'description',
Expand All @@ -95,6 +95,29 @@ class CategoryAdmin(TreeEditor, admin.ModelAdmin):
'classes': ('collapse',),
}),
)

actions = ['activate', 'deactivate']

def deactivate(self, request, queryset):
"""
Set active to False for selected items
"""
for item in queryset:
if item.active:
item.active = False
item.save()
deactivate.short_description = "Deactivate selected categories and their children"

def activate(self, request, queryset):
"""
Set active to True for selected items
"""
for item in queryset:
if not item.active:
item.active = True
item.save()
activate.short_description = "Activate selected categories and their children"

if RELATION_MODELS:
inlines = [InlineCategoryRelation,]

Expand Down
14 changes: 11 additions & 3 deletions categories/management/commands/import_categories.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from django.core.management.base import BaseCommand, CommandError
from categories.models import Category
from django.template.defaultfilters import slugify
from django.db import transaction

class Command(BaseCommand):
"""Import category trees from a file."""
Expand All @@ -22,17 +23,23 @@ def get_indent(self, string):
else:
return ' ' * indent_amt


@transaction.commit_on_success
def make_category(self, string, parent=None, order=1):
"""
Make and save a category object from a string
"""
return Category.objects.create(
cat = Category(
name=string.strip(),
slug=slugify(string.strip())[:49],
parent=parent,
#parent=parent,
order=order
)
cat._tree_manager.insert_node(cat, parent, 'last-child', True)
cat.save()
if parent:
parent.rght = cat.rght + 1
parent.save()
return cat

def parse_lines(self, lines):
"""
Expand Down Expand Up @@ -60,6 +67,7 @@ def parse_lines(self, lines):
else:
# We are back to a zero level, so reset the whole thing
current_parents = {0: self.make_category(line)}
current_parents[0]._tree_manager.rebuild()

def handle(self, *file_paths, **options):
"""
Expand Down
60 changes: 60 additions & 0 deletions categories/migrations/0007_auto__add_field_category_active.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# encoding: utf-8
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models

class Migration(SchemaMigration):

def forwards(self, orm):

# Adding field 'Category.active'
db.add_column('categories_category', 'active', self.gf('django.db.models.fields.BooleanField')(default=True), keep_default=False)


def backwards(self, orm):

# Deleting field 'Category.active'
db.delete_column('categories_category', 'active')


models = {
'categories.category': {
'Meta': {'ordering': "('tree_id', 'lft')", 'unique_together': "(('parent', 'name'),)", 'object_name': 'Category'},
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'alternate_title': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '100', 'blank': 'True'}),
'alternate_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}),
'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'level': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
'lft': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
'meta_extra': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
'meta_keywords': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255', 'blank': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'order': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'children'", 'null': 'True', 'to': "orm['categories.Category']"}),
'rght': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50', 'db_index': 'True'}),
'thumbnail': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
'thumbnail_height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
'thumbnail_width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
'tree_id': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'})
},
'categories.categoryrelation': {
'Meta': {'object_name': 'CategoryRelation'},
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
'relation_type': ('django.db.models.fields.CharField', [], {'max_length': "'200'", 'null': 'True', 'blank': 'True'}),
'story': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['categories.Category']"})
},
'contenttypes.contenttype': {
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
}
}

complete_apps = ['categories']
17 changes: 17 additions & 0 deletions categories/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,16 @@

STORAGE = get_storage_class(THUMBNAIL_STORAGE)

class CategoryManager(models.Manager):
"""
A manager that adds an "active()" method for all active categories
"""
def active(self):
"""
Only categories that are active
"""
return self.get_query_set().filter(active=True)

class Category(MPTTModel):
parent = models.ForeignKey('self',
blank=True,
Expand Down Expand Up @@ -49,6 +59,9 @@ class Category(MPTTModel):
blank=True,
default="",
help_text="(Advanced) Any additional HTML to be placed verbatim in the <head>")
active = models.BooleanField(default=True)

objects = CategoryManager()

@property
def short_title(self):
Expand Down Expand Up @@ -88,6 +101,10 @@ def save(self, *args, **kwargs):
self.thumbnail_width = width
self.thumbnail_height = height

for item in self.get_descendants():
if item.active != self.active:
item.active = self.active
item.save()
super(Category, self).save(*args, **kwargs)

class Meta:
Expand Down
1 change: 1 addition & 0 deletions categories/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from categories.tests.category_import import *
from categories.tests.templatetags import *
from categories.tests.manager import *

__fixtures__ = ['categories.json']
12 changes: 12 additions & 0 deletions categories/tests/category_import.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,23 @@ def _import_file(self, filename):
def testImportSpaceDelimited(self):
Category.objects.all().delete()
self._import_file('test_category_spaces.txt')

items = Category.objects.all()

self.assertEqual(items[0].name, 'Category 1')
self.assertEqual(items[1].name, 'Category 1-1')
self.assertEqual(items[2].name, 'Category 1-2')


def testImportTabDelimited(self):
Category.objects.all().delete()
self._import_file('test_category_tabs.txt')

items = Category.objects.all()

self.assertEqual(items[0].name, 'Category 1')
self.assertEqual(items[1].name, 'Category 1-1')
self.assertEqual(items[2].name, 'Category 1-2')


def testMixingTabsSpaces(self):
Expand Down
23 changes: 23 additions & 0 deletions categories/tests/manager.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# test active returns only active items
import unittest, os
from categories.models import Category
from categories.management.commands.import_categories import Command
from django.core.management.base import CommandError

class CategoryManagerTest(unittest.TestCase):
def setUp(self):
pass

def testActive(self):
"""
Should raise an exception.
"""
all_count = Category.objects.all().count()
self.assertEqual(Category.objects.active().count(), all_count)

cat1 = Category.objects.get(name='Category 1')
cat1.active = False
cat1.save()

active_count = all_count - cat1.get_descendants(True).count()
self.assertEqual(Category.objects.active().count(), active_count)
8 changes: 4 additions & 4 deletions docs/adding_the_fields.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

<title>Adding the fields to the database &mdash; Django Categories v0.7 documentation</title>
<title>Adding the fields to the database &mdash; Django Categories v0.8 documentation</title>
<link rel="stylesheet" href="_static/default.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT: '',
VERSION: '0.7',
VERSION: '0.8',
COLLAPSE_INDEX: false,
FILE_SUFFIX: '.html',
HAS_SOURCE: true
Expand All @@ -21,13 +21,13 @@
<script type="text/javascript" src="_static/jquery.js"></script>
<script type="text/javascript" src="_static/underscore.js"></script>
<script type="text/javascript" src="_static/doctools.js"></script>
<link rel="top" title="Django Categories v0.7 documentation" href="index.html" />
<link rel="top" title="Django Categories v0.8 documentation" href="index.html" />
<link rel="next" title="Reference" href="reference/index.html" />
<link rel="prev" title="Registering Models" href="registering_models.html" />
</head>
<body>
<div id="docstitle">
<p>Django Categories v0.7 documentation</p>
<p>Django Categories v0.8 documentation</p>
</div>
<div id="header">
<div id="title"><h1>Adding the fields to the database</h1></div>
Expand Down
8 changes: 4 additions & 4 deletions docs/genindex.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

<title>Index &mdash; Django Categories v0.7 documentation</title>
<title>Index &mdash; Django Categories v0.8 documentation</title>
<link rel="stylesheet" href="_static/default.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT: '',
VERSION: '0.7',
VERSION: '0.8',
COLLAPSE_INDEX: false,
FILE_SUFFIX: '.html',
HAS_SOURCE: true
Expand All @@ -21,11 +21,11 @@
<script type="text/javascript" src="_static/jquery.js"></script>
<script type="text/javascript" src="_static/underscore.js"></script>
<script type="text/javascript" src="_static/doctools.js"></script>
<link rel="top" title="Django Categories v0.7 documentation" href="index.html" />
<link rel="top" title="Django Categories v0.8 documentation" href="index.html" />
</head>
<body>
<div id="docstitle">
<p>Django Categories v0.7 documentation</p>
<p>Django Categories v0.8 documentation</p>
</div>
<div id="header">
<div id="title"><h1>Index</h1></div>
Expand Down
12 changes: 6 additions & 6 deletions docs/getting_started.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

<title>Getting Started &mdash; Django Categories v0.7 documentation</title>
<title>Getting Started &mdash; Django Categories v0.8 documentation</title>
<link rel="stylesheet" href="_static/default.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT: '',
VERSION: '0.7',
VERSION: '0.8',
COLLAPSE_INDEX: false,
FILE_SUFFIX: '.html',
HAS_SOURCE: true
Expand All @@ -21,13 +21,13 @@
<script type="text/javascript" src="_static/jquery.js"></script>
<script type="text/javascript" src="_static/underscore.js"></script>
<script type="text/javascript" src="_static/doctools.js"></script>
<link rel="top" title="Django Categories v0.7 documentation" href="index.html" />
<link rel="top" title="Django Categories v0.8 documentation" href="index.html" />
<link rel="next" title="Using categories in templates" href="usage.html" />
<link rel="prev" title="Django Categories v 0.7" href="index.html" />
<link rel="prev" title="Django Categories v 0.8" href="index.html" />
</head>
<body>
<div id="docstitle">
<p>Django Categories v0.7 documentation</p>
<p>Django Categories v0.8 documentation</p>
</div>
<div id="header">
<div id="title"><h1>Getting Started</h1></div>
Expand All @@ -36,7 +36,7 @@
<li id="page_buttons">
<div class="headerButton"><a href="genindex.html" title="General Index" accesskey="I">index</a></div>
<div class="headerButton"><a href="usage.html" title="Using categories in templates" accesskey="N">next</a></div>
<div class="headerButton"><a href="index.html" title="Django Categories v 0.7" accesskey="P">previous</a></div>
<div class="headerButton"><a href="index.html" title="Django Categories v 0.8" accesskey="P">previous</a></div>
</li>
</ul>
</div>
Expand Down
Loading

0 comments on commit 1e049b9

Please sign in to comment.