mirror of
https://github.com/jazzband/django-categories.git
synced 2026-05-28 00:44:02 +00:00
Merge branch '1.2'
This commit is contained in:
commit
0bb8af6351
23 changed files with 437 additions and 158 deletions
|
|
@ -12,4 +12,7 @@ recursive-include doc_src *.rst *.txt *.png *.css *.html *.js
|
|||
include doc_src/Makefile
|
||||
include doc_src/make.bat
|
||||
|
||||
recursive-include categories/locale *.mo *.po
|
||||
recursive-include categories/editor/locale *.mo *.po
|
||||
|
||||
prune example
|
||||
|
|
|
|||
|
|
@ -13,6 +13,15 @@ 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 1.2
|
||||
==========
|
||||
|
||||
* Support for Django 1.5
|
||||
* Dropped support for Django 1.2
|
||||
* Dropped caching within the app
|
||||
* Removed the old settings compatibility layer. *Must use new dictionary-based settings!*
|
||||
|
||||
|
||||
|
||||
New in 1.1
|
||||
==========
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
__version_info__ = {
|
||||
'major': 1,
|
||||
'minor': 1,
|
||||
'micro': 4,
|
||||
'minor': 2,
|
||||
'micro': 0,
|
||||
'releaselevel': 'final',
|
||||
'serial': 1
|
||||
}
|
||||
|
|
@ -25,5 +25,5 @@ try:
|
|||
register_m2m)
|
||||
_process_registry(settings.FK_REGISTRY, register_fk)
|
||||
_process_registry(settings.M2M_REGISTRY, register_m2m)
|
||||
except ImportError:
|
||||
except:
|
||||
pass
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
from django.contrib import admin
|
||||
from django import forms
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from .genericcollection import GenericCollectionTabularInline
|
||||
from .settings import RELATION_MODELS, JAVASCRIPT_URL, REGISTER_ADMIN
|
||||
|
|
@ -46,12 +47,12 @@ class CategoryAdmin(CategoryBaseAdmin):
|
|||
(None, {
|
||||
'fields': ('parent', 'name', 'thumbnail', 'active')
|
||||
}),
|
||||
('Meta Data', {
|
||||
(_('Meta Data'), {
|
||||
'fields': ('alternate_title', 'alternate_url', 'description',
|
||||
'meta_keywords', 'meta_extra'),
|
||||
'classes': ('collapse',),
|
||||
}),
|
||||
('Advanced', {
|
||||
(_('Advanced'), {
|
||||
'fields': ('order', 'slug'),
|
||||
'classes': ('collapse',),
|
||||
}),
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ from django.db import models
|
|||
from django import forms
|
||||
from django.template.defaultfilters import slugify
|
||||
from django.utils.encoding import force_unicode
|
||||
from django.utils.translation import ugettext as _
|
||||
|
||||
from mptt.models import MPTTModel
|
||||
from mptt.fields import TreeForeignKey
|
||||
|
|
@ -36,11 +37,11 @@ class CategoryBase(MPTTModel):
|
|||
parent = TreeForeignKey('self',
|
||||
blank=True,
|
||||
null=True,
|
||||
related_name="children",
|
||||
verbose_name='Parent')
|
||||
name = models.CharField(max_length=100)
|
||||
slug = models.SlugField()
|
||||
active = models.BooleanField(default=True)
|
||||
related_name='children',
|
||||
verbose_name=_('parent'))
|
||||
name = models.CharField(max_length=100, verbose_name=_('name'))
|
||||
slug = models.SlugField(verbose_name=_('slug'))
|
||||
active = models.BooleanField(default=True, verbose_name=_('active'))
|
||||
|
||||
objects = CategoryManager()
|
||||
tree = TreeManager()
|
||||
|
|
@ -100,8 +101,8 @@ class CategoryBaseAdminForm(forms.ModelForm):
|
|||
**kwargs).values('id', 'slug'
|
||||
) if c['id'] != self.instance.id]
|
||||
if self.cleaned_data['slug'] in this_level_slugs:
|
||||
raise forms.ValidationError("The slug must be unique among "
|
||||
"the items at its level.")
|
||||
raise forms.ValidationError(_('The slug must be unique among '
|
||||
'the items at its level.'))
|
||||
|
||||
# Validate Category Parent
|
||||
# Make sure the category doesn't set itself or any of its children as
|
||||
|
|
@ -110,11 +111,11 @@ class CategoryBaseAdminForm(forms.ModelForm):
|
|||
if self.cleaned_data.get('parent', None) is None or self.instance.id is None:
|
||||
return self.cleaned_data
|
||||
elif self.cleaned_data['parent'].id == self.instance.id:
|
||||
raise forms.ValidationError("You can't set the parent of the "
|
||||
"item to itself.")
|
||||
raise forms.ValidationError(_("You can't set the parent of the "
|
||||
"item to itself."))
|
||||
elif self.cleaned_data['parent'].id in decendant_ids:
|
||||
raise forms.ValidationError("You can't set the parent of the "
|
||||
"item to a descendant.")
|
||||
raise forms.ValidationError(_("You can't set the parent of the "
|
||||
"item to a descendant."))
|
||||
return self.cleaned_data
|
||||
|
||||
|
||||
|
|
@ -144,7 +145,7 @@ class CategoryBaseAdmin(TreeEditor, admin.ModelAdmin):
|
|||
item.active = False
|
||||
item.save()
|
||||
item.children.all().update(active=False)
|
||||
deactivate.short_description = "Deactivate selected categories and their children"
|
||||
deactivate.short_description = _('Deactivate selected categories and their children')
|
||||
|
||||
def activate(self, request, queryset):
|
||||
"""
|
||||
|
|
@ -157,4 +158,4 @@ class CategoryBaseAdmin(TreeEditor, admin.ModelAdmin):
|
|||
item.active = True
|
||||
item.save()
|
||||
item.children.all().update(active=True)
|
||||
activate.short_description = "Activate selected categories and their children"
|
||||
activate.short_description = _('Activate selected categories and their children')
|
||||
|
|
|
|||
BIN
categories/editor/locale/de/LC_MESSAGES/django.mo
Normal file
BIN
categories/editor/locale/de/LC_MESSAGES/django.mo
Normal file
Binary file not shown.
40
categories/editor/locale/de/LC_MESSAGES/django.po
Normal file
40
categories/editor/locale/de/LC_MESSAGES/django.po
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
# German translation of django-categories
|
||||
# Copyright (C) 2012 winniehell
|
||||
# This file is distributed under the same license as django-categories.
|
||||
# winniehell <git@winniehell.de>, 2012.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: django-categories 1.1.4\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2012-09-02 12:39+0200\n"
|
||||
"PO-Revision-Date: 2012-09-01 02:38+0200\n"
|
||||
"Last-Translator: winniehell <git@winniehell.de>\n"
|
||||
"Language-Team: winniehell <git@winniehell.de>\n"
|
||||
"Language: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
|
||||
|
||||
#: tree_editor.py:167
|
||||
msgid "Database error"
|
||||
msgstr ""
|
||||
|
||||
#: tree_editor.py:206
|
||||
#, python-format
|
||||
msgid "%(count)s %(name)s was changed successfully."
|
||||
msgid_plural "%(count)s %(name)s were changed successfully."
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
|
||||
#: tree_editor.py:247
|
||||
#, python-format
|
||||
msgid "%(total_count)s selected"
|
||||
msgid_plural "All %(total_count)s selected"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
|
||||
#: tree_editor.py:252
|
||||
#, python-format
|
||||
msgid "0 of %(cnt)s selected"
|
||||
msgstr ""
|
||||
|
|
@ -8,10 +8,19 @@
|
|||
<table cellspacing="0" id="result_list">
|
||||
<thead>
|
||||
<tr>
|
||||
{% for header in result_headers %}<th{{ header.class_attrib }}>
|
||||
{% if header.sortable %}<a href="{{ header.url }}">{% endif %}
|
||||
{{ header.text|capfirst }}
|
||||
{% if header.sortable %}</a>{% endif %}</th>{% endfor %}
|
||||
{% for header in result_headers %}<th scope="col" {{ header.class_attrib }}>
|
||||
{% if header.sortable %}
|
||||
{% if header.sort_priority > 0 %}
|
||||
<div class="sortoptions">
|
||||
<a class="sortremove" href="{{ header.url_remove }}" title="{% trans "Remove from sorting" %}"></a>
|
||||
{% if num_sorted_fields > 1 %}<span class="sortpriority" title="{% blocktrans with priority_number=header.sort_priority %}Sorting priority: {{ priority_number }}{% endblocktrans %}">{{ header.sort_priority }}</span>{% endif %}
|
||||
<a href="{{ header.url_toggle }}" class="toggle {% if header.ascending %}ascending{% else %}descending{% endif %}" title="{% trans "Toggle sorting" %}"></a>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
<div class="text">{% if header.sortable %}<a href="{{ header.url_primary }}">{{ header.text|capfirst }}</a>{% else %}<span>{{ header.text|capfirst }}</span>{% endif %}</div>
|
||||
<div class="clear"></div>
|
||||
</th>{% endfor %}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
|
|
|||
BIN
categories/locale/de/LC_MESSAGES/django.mo
Normal file
BIN
categories/locale/de/LC_MESSAGES/django.mo
Normal file
Binary file not shown.
154
categories/locale/de/LC_MESSAGES/django.po
Normal file
154
categories/locale/de/LC_MESSAGES/django.po
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
# German translation of django-categories
|
||||
# Copyright (C) 2012 winniehell
|
||||
# This file is distributed under the same license as django-categories.
|
||||
# winniehell <git@winniehell.de>, 2012.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: django-categories 1.1.4\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2012-09-02 15:59+0200\n"
|
||||
"PO-Revision-Date: 2012-09-01 02:38+0200\n"
|
||||
"Last-Translator: winniehell <git@winniehell.de>\n"
|
||||
"Language-Team: winniehell <git@winniehell.de>\n"
|
||||
"Language: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
|
||||
|
||||
#: admin.py:50
|
||||
msgid "Meta Data"
|
||||
msgstr "Meta-Daten"
|
||||
|
||||
#: admin.py:55
|
||||
msgid "Advanced"
|
||||
msgstr "Erweitert"
|
||||
|
||||
#: base.py:41
|
||||
msgid "parent"
|
||||
msgstr "oberkategorie"
|
||||
|
||||
#: base.py:42
|
||||
msgid "name"
|
||||
msgstr "name"
|
||||
|
||||
#: base.py:43
|
||||
msgid "slug"
|
||||
msgstr "slug"
|
||||
|
||||
#: base.py:44
|
||||
msgid "active"
|
||||
msgstr "aktiv"
|
||||
|
||||
#: base.py:99
|
||||
msgid "The slug must be unique among the items at its level."
|
||||
msgstr "Der Slug muss eindeutig innerhalb der Kategorien einer Ebene sein."
|
||||
|
||||
#: base.py:109
|
||||
msgid "You can't set the parent of the item to itself."
|
||||
msgstr "Eine Kategorie kann nicht Oberkategorie von sich selbst sein."
|
||||
|
||||
#: base.py:112
|
||||
msgid "You can't set the parent of the item to a descendant."
|
||||
msgstr "Die Oberkategorie kann keine untergeordnete Kategorie sein."
|
||||
|
||||
#: base.py:143
|
||||
msgid "Deactivate selected categories and their children"
|
||||
msgstr "Markierte Kategorien und ihre Unterkategorien deaktivieren"
|
||||
|
||||
#: base.py:156
|
||||
msgid "Activate selected categories and their children"
|
||||
msgstr "Markierte Kategorien und ihre Unterkategorien aktivieren"
|
||||
|
||||
#: migration.py:21 migration.py:91
|
||||
msgid "%(dependency) must be installed for this command to work"
|
||||
msgstr ""
|
||||
"%(dependency) muss installiert sein, damit dieses Kommando funktioniert"
|
||||
|
||||
#: migration.py:43
|
||||
msgid "Added ForeignKey %(field_name) to %(model_name)"
|
||||
msgstr "Fremdschlüssel %(field_name) zu %(model_name) hinzugefügt"
|
||||
|
||||
#: migration.py:49
|
||||
msgid "ForeignKey %(field_name) to %(model_name) already exists"
|
||||
msgstr "Fremdschlüssel %(field_name) zu %(model_name) existiert bereits"
|
||||
|
||||
#: migration.py:66
|
||||
msgid "Added Many2Many table between %(model_name) and %(category_table)"
|
||||
msgstr "M:N-Beziehung zwischen %(model_name) und %(category_table) hinzugefügt"
|
||||
|
||||
#: migration.py:72
|
||||
msgid ""
|
||||
"Many2Many table between %(model_name) and %(category_table) already exists"
|
||||
msgstr ""
|
||||
"M:N-Beziehung zwischen %(model_name) und %(category_table) existiert bereits"
|
||||
|
||||
#: migration.py:98
|
||||
msgid "Dropping ForeignKey %(field_name) from %(model_name)"
|
||||
msgstr "Entferne Fremdschlüssel %(field_name) zu %(model_name)"
|
||||
|
||||
#: migration.py:109
|
||||
msgid "Dropping Many2Many table between %(model_name) and %(category_table)"
|
||||
msgstr "Entferne M:N-Beziehung zwischen %(model_name) und %(category_table)"
|
||||
|
||||
#: models.py:91 models.py:122
|
||||
msgid "category"
|
||||
msgstr "kategorie"
|
||||
|
||||
#: models.py:92
|
||||
msgid "categories"
|
||||
msgstr "kategorien"
|
||||
|
||||
#: models.py:124
|
||||
msgid "content type"
|
||||
msgstr "content type"
|
||||
|
||||
#: models.py:125
|
||||
msgid "object id"
|
||||
msgstr "objekt-ID"
|
||||
|
||||
#: models.py:127
|
||||
msgid "relation type"
|
||||
msgstr "relationstyp"
|
||||
|
||||
#: models.py:131
|
||||
msgid "A generic text field to tag a relation, like 'leadphoto'."
|
||||
msgstr ""
|
||||
"Ein generisches Textfeld um eine Relation zu bezeichnen, z.B. 'leadphoto'"
|
||||
|
||||
#: registration.py:45
|
||||
#, python-format
|
||||
msgid "%(key) is not a model"
|
||||
msgstr "%(key) ist kein Model"
|
||||
|
||||
#: registration.py:54 registration.py:62
|
||||
msgid "%(settings) doesn't recognize the value of %(key)"
|
||||
msgstr "%(settings) erkennt den Wert von %(key) nicht"
|
||||
|
||||
#: settings.py:33
|
||||
msgid "%(transliterator) must be a callable or a string."
|
||||
msgstr "%(transliterator) muss callable oder string sein"
|
||||
|
||||
#: settings.py:39
|
||||
#, python-format
|
||||
msgid "%(deprecated_setting) is deprecated; use %(replacement)s instead."
|
||||
msgstr ""
|
||||
"%(deprecated_setting) ist veraltet und wurde durch %(replacement)s ersetzt."
|
||||
|
||||
#: views.py:73
|
||||
msgid "Category detail view %(view) must be called with a %(path_field)."
|
||||
msgstr ""
|
||||
"Kategorie-Detailansicht %(view) muss ein %(path_field) übergeben bekommen."
|
||||
|
||||
#: views.py:80
|
||||
#, python-format
|
||||
msgid "No %(verbose_name)s found matching the query"
|
||||
msgstr "Es wurde kein passendes Objekt für %(verbose_name)s gefunden"
|
||||
|
||||
#: templates/admin/edit_inline/gen_coll_tabular.html:13
|
||||
msgid "Delete?"
|
||||
msgstr "Löschen?"
|
||||
|
||||
#: templates/admin/edit_inline/gen_coll_tabular.html:24
|
||||
msgid "View on site"
|
||||
msgstr "Anzeigen"
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
from django.db import models, DatabaseError
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
|
||||
def migrate_app(sender, app, created_models, verbosity, *args, **kwargs):
|
||||
|
|
@ -17,7 +18,8 @@ def migrate_app(sender, app, created_models, verbosity, *args, **kwargs):
|
|||
try:
|
||||
from south.db import db
|
||||
except ImportError:
|
||||
raise ImproperlyConfigured("South must be installed for this command to work")
|
||||
raise ImproperlyConfigured(_('%(dependency) must be installed for this command to work') %
|
||||
{'dependency' : 'South'})
|
||||
# pull the information from the registry
|
||||
app_name = app.__name__.split('.')[-2]
|
||||
|
||||
|
|
@ -38,17 +40,19 @@ def migrate_app(sender, app, created_models, verbosity, *args, **kwargs):
|
|||
db.add_column(table_name, field_name, FIELD_REGISTRY[fld], keep_default=False)
|
||||
db.commit_transaction()
|
||||
if verbosity:
|
||||
print "Added ForeignKey %s to %s" % (field_name, model_name)
|
||||
print (_('Added ForeignKey %(field_name) to %(model_name)') %
|
||||
{'field_name' : field_name, 'model_name' : model_name})
|
||||
except DatabaseError, e:
|
||||
db.rollback_transaction()
|
||||
if "already exists" in str(e):
|
||||
if verbosity > 1:
|
||||
print "ForeignKey %s to %s already exists" % (field_name, model_name)
|
||||
print (_('ForeignKey %(field_name) to %(model_name) already exists') %
|
||||
{'field_name' : field_name, 'model_name' : model_name})
|
||||
else:
|
||||
sys.stderr = org_stderror
|
||||
raise e
|
||||
elif isinstance(FIELD_REGISTRY[fld], CategoryM2MField):
|
||||
table_name = "%s_%s" % (mdl._meta.db_table, 'categories')
|
||||
table_name = '%s_%s' % (mdl._meta.db_table, 'categories')
|
||||
try:
|
||||
db.start_transaction()
|
||||
db.create_table(table_name, (
|
||||
|
|
@ -59,12 +63,14 @@ def migrate_app(sender, app, created_models, verbosity, *args, **kwargs):
|
|||
db.create_unique(table_name, ['%s_id' % model_name, 'category_id'])
|
||||
db.commit_transaction()
|
||||
if verbosity:
|
||||
print "Added Many2Many table between %s and %s" % (model_name, 'category')
|
||||
print (_('Added Many2Many table between %(model_name) and %(category_table)') %
|
||||
{'model_name' : model_name, 'category_table' : 'category'})
|
||||
except DatabaseError, e:
|
||||
db.rollback_transaction()
|
||||
if "already exists" in str(e):
|
||||
if verbosity > 1:
|
||||
print "Many2Many table between %s and %s already exists" % (model_name, 'category')
|
||||
print (_('Many2Many table between %(model_name) and %(category_table) already exists') %
|
||||
{'model_name' : model_name, 'category_table' : 'category'})
|
||||
else:
|
||||
sys.stderr = org_stderror
|
||||
raise e
|
||||
|
|
@ -82,13 +88,15 @@ def drop_field(app_name, model_name, field_name):
|
|||
try:
|
||||
from south.db import db
|
||||
except ImportError:
|
||||
raise ImproperlyConfigured("South must be installed for this command to work")
|
||||
raise ImproperlyConfigured(_('%(dependency) must be installed for this command to work') %
|
||||
{'dependency' : 'South'})
|
||||
mdl = models.get_model(app_name, model_name)
|
||||
|
||||
fld = "%s.%s.%s" % (app_name, model_name, field_name)
|
||||
fld = '%s.%s.%s' % (app_name, model_name, field_name)
|
||||
|
||||
if isinstance(FIELD_REGISTRY[fld], CategoryFKField):
|
||||
print "Dropping ForeignKey %s from %s" % (field_name, model_name)
|
||||
print (_('Dropping ForeignKey %(field_name) from %(model_name)') %
|
||||
{'field_name' : field_name, 'model_name' : model_name})
|
||||
try:
|
||||
db.start_transaction()
|
||||
table_name = mdl._meta.db_table
|
||||
|
|
@ -98,8 +106,8 @@ def drop_field(app_name, model_name, field_name):
|
|||
db.rollback_transaction()
|
||||
raise e
|
||||
elif isinstance(FIELD_REGISTRY[fld], CategoryM2MField):
|
||||
print "Dropping Many2Many table between %s and %s" % (model_name, 'category')
|
||||
table_name = "%s_%s" % (mdl._meta.db_table, 'categories')
|
||||
print (_('Dropping Many2Many table between %(model_name) and %(category_table)') %
|
||||
{'model_name' : model_name, 'category_table' : 'category'})
|
||||
try:
|
||||
db.start_transaction()
|
||||
db.delete_table(table_name, cascade=False)
|
||||
|
|
|
|||
|
|
@ -88,7 +88,8 @@ class Category(CategoryBase):
|
|||
super(Category, self).save(*args, **kwargs)
|
||||
|
||||
class Meta(CategoryBase.Meta):
|
||||
verbose_name_plural = 'categories'
|
||||
verbose_name = _('category')
|
||||
verbose_name_plural = _('categories')
|
||||
|
||||
class MPTTMeta:
|
||||
order_insertion_by = ('order', 'name')
|
||||
|
|
@ -118,12 +119,12 @@ class CategoryRelationManager(models.Manager):
|
|||
|
||||
class CategoryRelation(models.Model):
|
||||
"""Related category item"""
|
||||
category = models.ForeignKey(Category)
|
||||
category = models.ForeignKey(Category, verbose_name=_('category'))
|
||||
content_type = models.ForeignKey(
|
||||
ContentType, limit_choices_to=CATEGORY_RELATION_LIMITS)
|
||||
object_id = models.PositiveIntegerField()
|
||||
ContentType, limit_choices_to=CATEGORY_RELATION_LIMITS, verbose_name=_('content type'))
|
||||
object_id = models.PositiveIntegerField(verbose_name=_('object id'))
|
||||
content_object = generic.GenericForeignKey('content_type', 'object_id')
|
||||
relation_type = models.CharField(_("Relation Type"),
|
||||
relation_type = models.CharField(verbose_name=_('relation type'),
|
||||
max_length="200",
|
||||
blank=True,
|
||||
null=True,
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ def _process_registry(registry, call_func):
|
|||
for key, value in registry.items():
|
||||
model = get_model(*key.split('.'))
|
||||
if model is None:
|
||||
raise ImproperlyConfigured('%s is not a model' % key)
|
||||
raise ImproperlyConfigured(_('%(key) is not a model') % {'key' : key})
|
||||
if isinstance(value, (tuple, list)):
|
||||
for item in value:
|
||||
if isinstance(item, basestring):
|
||||
|
|
@ -51,11 +51,13 @@ def _process_registry(registry, call_func):
|
|||
field_name = item.pop('name')
|
||||
call_func(model, field_name, extra_params=item)
|
||||
else:
|
||||
raise ImproperlyConfigured("CATEGORY_SETTINGS doesn't recognize the value of %s" % key)
|
||||
raise ImproperlyConfigured(_("%(settings) doesn't recognize the value of %(key)") %
|
||||
{'settings' : 'CATEGORY_SETTINGS', 'key' : key})
|
||||
elif isinstance(value, basestring):
|
||||
call_func(model, value)
|
||||
elif isinstance(value, dict):
|
||||
field_name = value.pop('name')
|
||||
call_func(model, field_name, extra_params=value)
|
||||
else:
|
||||
raise ImproperlyConfigured("CATEGORY_SETTINGS doesn't recognize the value of %s" % key)
|
||||
raise ImproperlyConfigured(_("%(settings) doesn't recognize the value of %(key)") %
|
||||
{'settings' : 'CATEGORY_SETTINGS', 'key' : key})
|
||||
|
|
|
|||
|
|
@ -1,11 +1,9 @@
|
|||
import warnings
|
||||
|
||||
from django.conf import settings
|
||||
from django.db.models import Q
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
DEFAULT_SETTINGS = {
|
||||
'ALLOW_SLUG_CHANGE': False,
|
||||
'CACHE_VIEW_LENGTH': 600,
|
||||
'RELATION_MODELS': [],
|
||||
'M2M_REGISTRY': {},
|
||||
'FK_REGISTRY': {},
|
||||
|
|
@ -29,27 +27,11 @@ if DEFAULT_SETTINGS['SLUG_TRANSLITERATOR']:
|
|||
DEFAULT_SETTINGS['SLUG_TRANSLITERATOR'] = getattr(module, bits[-1])
|
||||
else:
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
raise ImproperlyConfigured("SLUG_TRANSLITERATOR must be a callable or a string.")
|
||||
raise ImproperlyConfigured(_('%(transliterator) must be a callable or a string.') %
|
||||
{'transliterator': 'SLUG_TRANSLITERATOR'})
|
||||
else:
|
||||
DEFAULT_SETTINGS['SLUG_TRANSLITERATOR'] = lambda x: x
|
||||
|
||||
ERR_MSG = "settings.%s is deprecated; use settings.CATEGORIES_SETTINGS instead."
|
||||
|
||||
if hasattr(settings, 'CATEGORIES_ALLOW_SLUG_CHANGE'):
|
||||
warnings.warn(ERR_MSG % 'CATEGORIES_ALLOW_SLUG_CHANGE', DeprecationWarning)
|
||||
DEFAULT_SETTINGS["ALLOW_SLUG_CHANGE"] = getattr(settings, 'CATEGORIES_ALLOW_SLUG_CHANGE')
|
||||
|
||||
if hasattr(settings, 'CATEGORIES_CACHE_VIEW_LENGTH'):
|
||||
warnings.warn(ERR_MSG % "CATEGORIES_CACHE_VIEW_LENGTH", DeprecationWarning)
|
||||
DEFAULT_SETTINGS["CACHE_VIEW_LENGTH"] = getattr(settings, 'CATEGORIES_CACHE_VIEW_LENGTH')
|
||||
|
||||
if hasattr(settings, 'CATEGORIES_THUMBNAIL_UPLOAD_PATH'):
|
||||
warnings.warn(ERR_MSG % "CATEGORIES_THUMBNAIL_UPLOAD_PATH", DeprecationWarning)
|
||||
DEFAULT_SETTINGS["THUMBNAIL_UPLOAD_PATH"] = getattr(settings, 'CATEGORIES_THUMBNAIL_UPLOAD_PATH')
|
||||
|
||||
if hasattr(settings, 'CATEGORIES_RELATION_MODELS'):
|
||||
warnings.warn(ERR_MSG % "CATEGORIES_RELATION_MODELS", DeprecationWarning)
|
||||
DEFAULT_SETTINGS["RELATION_MODELS"] = getattr(settings, 'CATEGORIES_RELATION_MODELS')
|
||||
|
||||
# Add all the keys/values to the module's namespace
|
||||
globals().update(DEFAULT_SETTINGS)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
{% load category_tags %}{% spaceless %}
|
||||
<ul><li><a href="{% url categories_tree_list %}">Top</a>
|
||||
<ul><li><a href="{% url 'categories_tree_list' %}">Top</a>
|
||||
{% for node,structure in path|tree_info %}
|
||||
{% if structure.new_level %}<ul><li>
|
||||
{% else %}</li><li>
|
||||
|
|
|
|||
|
|
@ -1,13 +1,23 @@
|
|||
from django.conf.urls.defaults import *
|
||||
from django.conf.urls import patterns, url
|
||||
from .models import Category
|
||||
|
||||
try:
|
||||
from django.views.generic import DetailView, ListView
|
||||
except ImportError:
|
||||
try:
|
||||
from cbv import DetailView, ListView
|
||||
except ImportError:
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
raise ImproperlyConfigured("For older versions of Django, you need django-cbv.")
|
||||
|
||||
|
||||
categorytree_dict = {
|
||||
'queryset': Category.objects.filter(level=0)
|
||||
}
|
||||
|
||||
urlpatterns = patterns('django.views.generic.list_detail',
|
||||
urlpatterns = patterns('',
|
||||
url(
|
||||
r'^$', 'object_list', categorytree_dict, name='categories_tree_list'
|
||||
r'^$', ListView.as_view(**categorytree_dict), name='categories_tree_list'
|
||||
),
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,17 +1,22 @@
|
|||
import django
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.core.exceptions import ObjectDoesNotExist
|
||||
from django.template import RequestContext
|
||||
from django.http import HttpResponse, Http404
|
||||
from django.views.decorators.cache import cache_page
|
||||
from django.template.loader import select_template
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
try:
|
||||
from django.views.generic import DetailView, ListView
|
||||
except ImportError:
|
||||
try:
|
||||
from cbv import DetailView, ListView
|
||||
except ImportError:
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
raise ImproperlyConfigured("For older versions of Django, you need django-cbv.")
|
||||
|
||||
|
||||
from .models import Category
|
||||
from .settings import CACHE_VIEW_LENGTH
|
||||
|
||||
|
||||
@cache_page(CACHE_VIEW_LENGTH)
|
||||
def category_detail(request, path,
|
||||
template_name='categories/category_detail.html', extra_context={}):
|
||||
path_items = path.strip('/').split('/')
|
||||
|
|
@ -51,59 +56,78 @@ def get_category_for_path(path, queryset=Category.objects.all()):
|
|||
level=len(path_items) - 1)
|
||||
return queryset.get()
|
||||
|
||||
try:
|
||||
import cbv
|
||||
HAS_CBV = True
|
||||
except ImportError:
|
||||
HAS_CBV = False
|
||||
|
||||
if ((django.VERSION[0] >= 1 and django.VERSION[1] >= 3) or HAS_CBV):
|
||||
if HAS_CBV:
|
||||
from cbv import DetailView, ListView
|
||||
else:
|
||||
from django.views.generic import DetailView, ListView
|
||||
class CategoryDetailView(DetailView):
|
||||
model = Category
|
||||
path_field = 'path'
|
||||
|
||||
class CategoryDetailView(DetailView):
|
||||
def get_object(self, **kwargs):
|
||||
if self.path_field not in self.kwargs:
|
||||
raise AttributeError(u"Category detail view %s must be called with "
|
||||
u"a %s." % self.__class__.__name__, self.path_field)
|
||||
if self.queryset is None:
|
||||
queryset = self.get_queryset()
|
||||
try:
|
||||
return get_category_for_path(self.kwargs[self.path_field])
|
||||
except ObjectDoesNotExist:
|
||||
raise Http404(_(u"No %(verbose_name)s found matching the query") %
|
||||
{'verbose_name': queryset.model._meta.verbose_name})
|
||||
|
||||
model = Category
|
||||
path_field = 'path'
|
||||
def get_template_names(self):
|
||||
names = []
|
||||
path_items = self.kwargs[self.path_field].strip('/').split('/')
|
||||
while path_items:
|
||||
names.append('categories/%s.html' % '_'.join(path_items))
|
||||
path_items.pop()
|
||||
names.extend(super(CategoryDetailView, self).get_template_names())
|
||||
return names
|
||||
|
||||
def get_object(self, **kwargs):
|
||||
if self.path_field not in self.kwargs:
|
||||
raise AttributeError(u"Category detail view %s must be called with "
|
||||
u"a %s." % self.__class__.__name__, self.path_field)
|
||||
if self.queryset is None:
|
||||
queryset = self.get_queryset()
|
||||
try:
|
||||
return get_category_for_path(self.kwargs[self.path_field])
|
||||
except ObjectDoesNotExist:
|
||||
raise Http404(_(u"No %(verbose_name)s found matching the query") %
|
||||
{'verbose_name': queryset.model._meta.verbose_name})
|
||||
|
||||
def get_template_names(self):
|
||||
names = []
|
||||
class CategoryRelatedDetail(DetailView):
|
||||
path_field = 'category_path'
|
||||
object_name_field = None
|
||||
|
||||
def get_object(self, **kwargs):
|
||||
queryset = super(CategoryRelatedDetail, self).get_queryset()
|
||||
category = get_category_for_path(self.kwargs[self.path_field])
|
||||
return queryset.get(category=category, slug=self.kwargs[self.slug_field])
|
||||
|
||||
def get_template_names(self):
|
||||
names = []
|
||||
opts = self.object._meta
|
||||
path_items = self.kwargs[self.path_field].strip('/').split('/')
|
||||
if self.object_name_field:
|
||||
path_items.append(getattr(self.object, self.object_name_field))
|
||||
while path_items:
|
||||
names.append('%s/category_%s_%s%s.html' % (
|
||||
opts.app_label,
|
||||
'_'.join(path_items),
|
||||
opts.object_name.lower(),
|
||||
self.template_name_suffix)
|
||||
)
|
||||
path_items.pop()
|
||||
names.append('%s/category_%s%s.html' % (
|
||||
opts.app_label,
|
||||
opts.object_name.lower(),
|
||||
self.template_name_suffix)
|
||||
)
|
||||
names.extend(super(CategoryRelatedDetail, self).get_template_names())
|
||||
return names
|
||||
|
||||
|
||||
class CategoryRelatedList(ListView):
|
||||
path_field = 'category_path'
|
||||
|
||||
def get_queryset(self):
|
||||
queryset = super(CategoryRelatedList, self).get_queryset()
|
||||
category = get_category_for_path(self.kwargs['category_path'])
|
||||
return queryset.filter(category=category)
|
||||
|
||||
def get_template_names(self):
|
||||
names = []
|
||||
if hasattr(self.object_list, 'model'):
|
||||
opts = self.object_list.model._meta
|
||||
path_items = self.kwargs[self.path_field].strip('/').split('/')
|
||||
while path_items:
|
||||
names.append('categories/%s.html' % '_'.join(path_items))
|
||||
path_items.pop()
|
||||
names.extend(super(CategoryDetailView, self).get_template_names())
|
||||
return names
|
||||
|
||||
class CategoryRelatedDetail(DetailView):
|
||||
path_field = 'category_path'
|
||||
object_name_field = None
|
||||
|
||||
def get_object(self, **kwargs):
|
||||
queryset = super(CategoryRelatedDetail, self).get_queryset()
|
||||
category = get_category_for_path(self.kwargs[self.path_field])
|
||||
return queryset.get(category=category, slug=self.kwargs[self.slug_field])
|
||||
|
||||
def get_template_names(self):
|
||||
names = []
|
||||
opts = self.object._meta
|
||||
path_items = self.kwargs[self.path_field].strip('/').split('/')
|
||||
if self.object_name_field:
|
||||
path_items.append(getattr(self.object, self.object_name_field))
|
||||
while path_items:
|
||||
names.append('%s/category_%s_%s%s.html' % (
|
||||
opts.app_label,
|
||||
|
|
@ -117,34 +141,5 @@ if ((django.VERSION[0] >= 1 and django.VERSION[1] >= 3) or HAS_CBV):
|
|||
opts.object_name.lower(),
|
||||
self.template_name_suffix)
|
||||
)
|
||||
names.extend(super(CategoryRelatedDetail, self).get_template_names())
|
||||
return names
|
||||
|
||||
class CategoryRelatedList(ListView):
|
||||
path_field = 'category_path'
|
||||
|
||||
def get_queryset(self):
|
||||
queryset = super(CategoryRelatedList, self).get_queryset()
|
||||
category = get_category_for_path(self.kwargs['category_path'])
|
||||
return queryset.filter(category=category)
|
||||
|
||||
def get_template_names(self):
|
||||
names = []
|
||||
if hasattr(self.object_list, 'model'):
|
||||
opts = self.object_list.model._meta
|
||||
path_items = self.kwargs[self.path_field].strip('/').split('/')
|
||||
while path_items:
|
||||
names.append('%s/category_%s_%s%s.html' % (
|
||||
opts.app_label,
|
||||
'_'.join(path_items),
|
||||
opts.object_name.lower(),
|
||||
self.template_name_suffix)
|
||||
)
|
||||
path_items.pop()
|
||||
names.append('%s/category_%s%s.html' % (
|
||||
opts.app_label,
|
||||
opts.object_name.lower(),
|
||||
self.template_name_suffix)
|
||||
)
|
||||
names.extend(super(CategoryRelatedList, self).get_template_names())
|
||||
return names
|
||||
names.extend(super(CategoryRelatedList, self).get_template_names())
|
||||
return names
|
||||
|
|
|
|||
49
doc_src/admin_settings.rst
Normal file
49
doc_src/admin_settings.rst
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
.. _admin_settings:
|
||||
|
||||
==============================
|
||||
Adding the fields to the Admin
|
||||
==============================
|
||||
|
||||
By default, Django Categories adds the fields you configure to the model's Admin class. If your ModelAdmin class does not use the ``fieldsets`` attribute, the configured category fields are simply appended to the bottom the fields. If your ModelAdmin uses the ``fieldsets`` attribute, a new fieldset named ``Categories``, containing all the configured fields is appended to the fieldsets. You can override or alter this behavior with the :ref:`ADMIN_FIELDSETS` setting.
|
||||
|
||||
ADMIN_FIELDSETS allows you to:
|
||||
|
||||
* Prevent Django Categories from adding the fields or fieldsets to a model's ModelAdmin class.
|
||||
* Change the name of the fieldset (from the default: "Categories")
|
||||
* Change the placement of the fieldset (from the default: bottom)
|
||||
|
||||
Preventing fields in the admin class
|
||||
====================================
|
||||
|
||||
If you don't want Django Categories to add any fields to the admin class, simply use the following format::
|
||||
|
||||
CATEGORIES_SETTINGS = {
|
||||
'ADMIN_FIELDSETS': [
|
||||
'app.model': None,
|
||||
]
|
||||
}
|
||||
|
||||
Changing the name of the field set
|
||||
==================================
|
||||
|
||||
To rename the field set, use the following format::
|
||||
|
||||
CATEGORIES_SETTINGS = {
|
||||
'ADMIN_FIELDSETS': [
|
||||
'app.model': 'Taxonomy',
|
||||
]
|
||||
}
|
||||
|
||||
Putting the field set exactly where you want it
|
||||
===============================================
|
||||
|
||||
For complete control over the field set, use the following format::
|
||||
|
||||
CATEGORIES_SETTINGS = {
|
||||
'ADMIN_FIELDSETS': [
|
||||
'app.model': {
|
||||
'name': 'Categories',
|
||||
'index': 0
|
||||
},
|
||||
]
|
||||
}
|
||||
|
|
@ -31,6 +31,7 @@ Contents
|
|||
usage
|
||||
registering_models
|
||||
adding_the_fields
|
||||
admin_settings
|
||||
custom_categories
|
||||
reference/index
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ The ``CATEGORIES_SETTINGS`` dictionary is where you can override the default set
|
|||
The default settings are:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
|
||||
CATEGORIES_SETTINGS = {
|
||||
'ALLOW_SLUG_CHANGE': False,
|
||||
'CACHE_VIEW_LENGTH': 0,
|
||||
|
|
@ -23,6 +23,7 @@ The default settings are:
|
|||
'THUMBNAIL_UPLOAD_PATH': 'uploads/categories/thumbnails',
|
||||
'THUMBNAIL_STORAGE': settings.DEFAULT_FILE_STORAGE,
|
||||
'SLUG_TRANSLITERATOR': lambda x: x,
|
||||
'ADMIN_FIELDSETS': {}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -119,3 +120,12 @@ JAVASCRIPT_URL
|
|||
**Default:** ``STATIC_URL or MEDIA_URL + 'js/'``
|
||||
|
||||
**Description:** Allows for customization of javascript placement.
|
||||
|
||||
.. _ADMIN_FIELDSETS:
|
||||
|
||||
ADMIN_FIELDSETS
|
||||
===============
|
||||
|
||||
**Default:** ``{}``
|
||||
|
||||
**Description:** Allows for selective customization of the default behavior of adding the fields to the admin class. See :ref:`admin_settings` for more information.
|
||||
|
|
@ -123,7 +123,7 @@ CATEGORIES_SETTINGS = {
|
|||
},
|
||||
}
|
||||
|
||||
if django.VERSION[1] == 4:
|
||||
if django.VERSION[1] >= 4:
|
||||
from settings14 import *
|
||||
if django.VERSION[1] == 3:
|
||||
from settings13 import *
|
||||
|
|
|
|||
|
|
@ -3,9 +3,13 @@ from django.contrib import admin
|
|||
|
||||
from categories.admin import CategoryBaseAdmin, CategoryBaseAdminForm
|
||||
|
||||
# class SimpleTextAdmin(admin.ModelAdmin):
|
||||
# filter_horizontal = ['cats',]
|
||||
#
|
||||
class SimpleTextAdmin(admin.ModelAdmin):
|
||||
fieldsets = (
|
||||
(None, {
|
||||
'fields': ('name', 'description', )
|
||||
}),
|
||||
)
|
||||
|
||||
|
||||
class SimpleCategoryAdminForm(CategoryBaseAdminForm):
|
||||
class Meta:
|
||||
|
|
@ -13,6 +17,6 @@ class SimpleCategoryAdminForm(CategoryBaseAdminForm):
|
|||
|
||||
class SimpleCategoryAdmin(CategoryBaseAdmin):
|
||||
form = SimpleCategoryAdminForm
|
||||
|
||||
admin.site.register(SimpleText) #, SimpleTextAdmin)
|
||||
|
||||
admin.site.register(SimpleText, SimpleTextAdmin)
|
||||
admin.site.register(SimpleCategory, SimpleCategoryAdmin)
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
from django.conf.urls.defaults import *
|
||||
from django.conf.urls import patterns, include
|
||||
|
||||
# Uncomment the next two lines to enable the admin:
|
||||
from django.contrib import admin
|
||||
|
|
@ -13,7 +13,7 @@ urlpatterns = patterns('',
|
|||
# Example:
|
||||
# (r'^sample/', include('sample.foo.urls')),
|
||||
|
||||
# Uncomment the admin/doc line below and add 'django.contrib.admindocs'
|
||||
# Uncomment the admin/doc line below and add 'django.contrib.admindocs'
|
||||
# to INSTALLED_APPS to enable admin documentation:
|
||||
# (r'^admin/doc/', include('django.contrib.admindocs.urls')),
|
||||
|
||||
|
|
@ -32,4 +32,4 @@ urlpatterns = patterns('',
|
|||
(r'^static/(?P<path>.*)$', 'django.views.static.serve',
|
||||
{'document_root': os.path.join(ROOT_PATH, 'example', 'static')}),
|
||||
|
||||
)
|
||||
)
|
||||
|
|
|
|||
Loading…
Reference in a new issue