mirror of
https://github.com/jazzband/django-categories.git
synced 2026-03-16 22:30:24 +00:00
Merge branch '1.1.2'
This commit is contained in:
commit
a92ab30f9c
9 changed files with 172 additions and 118 deletions
|
|
@ -1,7 +1,7 @@
|
|||
__version_info__ = {
|
||||
'major': 1,
|
||||
'minor': 1,
|
||||
'micro': 1,
|
||||
'micro': 2,
|
||||
'releaselevel': 'final',
|
||||
'serial': 1
|
||||
}
|
||||
|
|
@ -18,98 +18,12 @@ def get_version(short=False):
|
|||
|
||||
__version__ = get_version()
|
||||
|
||||
field_registry = {}
|
||||
model_registry = {}
|
||||
|
||||
try:
|
||||
import fields
|
||||
|
||||
from django.db.models import FieldDoesNotExist
|
||||
|
||||
class AlreadyRegistered(Exception):
|
||||
"""
|
||||
An attempt was made to register a model more than once.
|
||||
"""
|
||||
pass
|
||||
|
||||
# The field registry keeps track of the individual fields created.
|
||||
# {'app.model.field': Field(**extra_params)}
|
||||
# Useful for doing a schema migration
|
||||
field_registry = {}
|
||||
|
||||
# The model registry keeps track of which models have one or more fields
|
||||
# registered.
|
||||
# {'app': [model1, model2]}
|
||||
# Useful for admin alteration
|
||||
model_registry = {}
|
||||
|
||||
def register_m2m(model, field_name='categories', extra_params={}):
|
||||
return _register(model, field_name, extra_params, fields.CategoryM2MField)
|
||||
|
||||
def register_fk(model, field_name='category', extra_params={}):
|
||||
return _register(model, field_name, extra_params, fields.CategoryFKField)
|
||||
|
||||
def _register(model, field_name, extra_params={}, field=fields.CategoryFKField):
|
||||
app_label = model._meta.app_label
|
||||
registry_name = ".".join((app_label, model.__name__, field_name)).lower()
|
||||
|
||||
if registry_name in field_registry:
|
||||
return #raise AlreadyRegistered
|
||||
opts = model._meta
|
||||
try:
|
||||
opts.get_field(field_name)
|
||||
except FieldDoesNotExist:
|
||||
if app_label not in model_registry:
|
||||
model_registry[app_label] = []
|
||||
if model not in model_registry[app_label]:
|
||||
model_registry[app_label].append(model)
|
||||
field_registry[registry_name] = field(**extra_params)
|
||||
field_registry[registry_name].contribute_to_class(model, field_name)
|
||||
|
||||
from categories import settings
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
from django.db.models.loading import get_model
|
||||
|
||||
for key, value in settings.FK_REGISTRY.items():
|
||||
model = get_model(*key.split('.'))
|
||||
if model is None:
|
||||
raise ImproperlyConfigured('%s is not a model' % key)
|
||||
if isinstance(value, (tuple, list)):
|
||||
for item in value:
|
||||
if isinstance(item, basestring):
|
||||
register_fk(model, item)
|
||||
elif isinstance(item, dict):
|
||||
field_name = item.pop('name')
|
||||
register_fk(model, field_name, extra_params=item)
|
||||
else:
|
||||
raise ImproperlyConfigured("CATEGORY_SETTINGS['FK_REGISTRY'] doesn't recognize the value of %s" % key)
|
||||
elif isinstance(value, basestring):
|
||||
register_fk(model, value)
|
||||
elif isinstance(item, dict):
|
||||
field_name = item.pop('name')
|
||||
register_fk(model, field_name, extra_params=item)
|
||||
else:
|
||||
raise ImproperlyConfigured("CATEGORY_SETTINGS['FK_REGISTRY'] doesn't recognize the value of %s" % key)
|
||||
for key, value in settings.M2M_REGISTRY.items():
|
||||
model = get_model(*key.split('.'))
|
||||
if model is None:
|
||||
raise ImproperlyConfigured('%s is not a model' % key)
|
||||
if isinstance(value, (tuple, list)):
|
||||
for item in value:
|
||||
if isinstance(item, basestring):
|
||||
register_m2m(model, item)
|
||||
elif isinstance(item, dict):
|
||||
field_name = item.pop('name')
|
||||
register_m2m(model, field_name, extra_params=item)
|
||||
else:
|
||||
raise ImproperlyConfigured("CATEGORY_SETTINGS['M2M_REGISTRY'] doesn't recognize the value of %s: %s" % (key, item))
|
||||
elif isinstance(value, basestring):
|
||||
register_m2m(model, value)
|
||||
elif isinstance(value, dict):
|
||||
field_name = value.pop('name')
|
||||
register_m2m(model, field_name, extra_params=value)
|
||||
else:
|
||||
raise ImproperlyConfigured("CATEGORY_SETTINGS['M2M_REGISTRY'] doesn't recognize the value of %s" % key)
|
||||
|
||||
from categories.registration import (_process_registry, register_fk,
|
||||
register_m2m)
|
||||
_process_registry(settings.FK_REGISTRY, register_fk)
|
||||
_process_registry(settings.M2M_REGISTRY, register_m2m)
|
||||
except ImportError:
|
||||
pass
|
||||
|
|
|
|||
|
|
@ -5,8 +5,7 @@ from .genericcollection import GenericCollectionTabularInline
|
|||
from .settings import RELATION_MODELS, JAVASCRIPT_URL, REGISTER_ADMIN
|
||||
from .models import Category
|
||||
from .base import CategoryBaseAdminForm, CategoryBaseAdmin
|
||||
|
||||
from categories import model_registry
|
||||
from .settings import MODEL_REGISTRY
|
||||
|
||||
|
||||
class NullTreeNodeChoiceField(forms.ModelChoiceField):
|
||||
|
|
@ -68,9 +67,9 @@ if REGISTER_ADMIN:
|
|||
admin.site.register(Category, CategoryAdmin)
|
||||
|
||||
for model, modeladmin in admin.site._registry.items():
|
||||
if model in model_registry.values() and modeladmin.fieldsets:
|
||||
if model in MODEL_REGISTRY.values() and modeladmin.fieldsets:
|
||||
fieldsets = getattr(modeladmin, 'fieldsets', ())
|
||||
fields = [cat.split('.')[2] for cat in model_registry if model_registry[cat] == model]
|
||||
fields = [cat.split('.')[2] for cat in MODEL_REGISTRY if MODEL_REGISTRY[cat] == model]
|
||||
# check each field to see if already defined
|
||||
for cat in fields:
|
||||
for k, v in fieldsets:
|
||||
|
|
|
|||
|
|
@ -1,4 +1,8 @@
|
|||
from django.db.models.signals import post_syncdb
|
||||
from categories.migration import migrate_app
|
||||
try:
|
||||
from south.db import db
|
||||
from django.db.models.signals import post_syncdb
|
||||
from categories.migration import migrate_app
|
||||
|
||||
post_syncdb.connect(migrate_app)
|
||||
post_syncdb.connect(migrate_app)
|
||||
except ImportError:
|
||||
pass
|
||||
|
|
|
|||
|
|
@ -20,10 +20,10 @@ class Command(BaseCommand):
|
|||
raise ImproperlyConfigured("South must be installed for this command to work")
|
||||
|
||||
from categories.migration import migrate_app
|
||||
from categories import model_registry
|
||||
from categories import MODEL_REGISTRY
|
||||
if args:
|
||||
for app in args:
|
||||
migrate_app(app)
|
||||
else:
|
||||
for app in model_registry:
|
||||
for app in MODEL_REGISTRY:
|
||||
migrate_app(app)
|
||||
|
|
|
|||
|
|
@ -1,35 +1,39 @@
|
|||
from django.db import models, DatabaseError
|
||||
|
||||
from south.db import db
|
||||
from south.signals import post_migrate
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
from .fields import CategoryM2MField, CategoryFKField
|
||||
from .models import Category
|
||||
from categories import model_registry, field_registry
|
||||
from .settings import FIELD_REGISTRY
|
||||
|
||||
|
||||
def migrate_app(app, *args, **kwargs):
|
||||
"""
|
||||
Migrate all models of this app registered
|
||||
"""
|
||||
try:
|
||||
from south.db import db
|
||||
except ImportError:
|
||||
raise ImproperlyConfigured("South must be installed for this command to work")
|
||||
|
||||
# pull the information from the registry
|
||||
if not isinstance(app, basestring):
|
||||
return
|
||||
fields = [fld for fld in field_registry.keys() if fld.startswith(app)]
|
||||
|
||||
fields = [fld for fld in FIELD_REGISTRY.keys() if fld.startswith(app)]
|
||||
|
||||
# call the south commands to add the fields/tables
|
||||
for fld in fields:
|
||||
app_name, model_name, field_name = fld.split('.')
|
||||
|
||||
|
||||
# Table is typically appname_modelname, but it could be different
|
||||
# always best to be sure.
|
||||
mdl = models.get_model(app_name, model_name)
|
||||
|
||||
if isinstance(field_registry[fld], CategoryFKField):
|
||||
|
||||
if isinstance(FIELD_REGISTRY[fld], CategoryFKField):
|
||||
print "Adding ForeignKey %s to %s" % (field_name, model_name)
|
||||
try:
|
||||
db.start_transaction()
|
||||
table_name = mdl._meta.db_table
|
||||
field_registry[fld].default=-1
|
||||
db.add_column(table_name, field_name, field_registry[fld], keep_default=False)
|
||||
FIELD_REGISTRY[fld].default = -1
|
||||
db.add_column(table_name, field_name, FIELD_REGISTRY[fld], keep_default=False)
|
||||
db.commit_transaction()
|
||||
except DatabaseError, e:
|
||||
db.rollback_transaction()
|
||||
|
|
@ -37,7 +41,7 @@ def migrate_app(app, *args, **kwargs):
|
|||
print "Already exists"
|
||||
else:
|
||||
raise e
|
||||
elif isinstance(field_registry[fld], CategoryM2MField):
|
||||
elif isinstance(FIELD_REGISTRY[fld], CategoryM2MField):
|
||||
print "Adding Many2Many table between %s and %s" % (model_name, 'category')
|
||||
table_name = "%s_%s" % (mdl._meta.db_table, 'categories')
|
||||
try:
|
||||
|
|
@ -56,17 +60,22 @@ def migrate_app(app, *args, **kwargs):
|
|||
else:
|
||||
raise e
|
||||
|
||||
|
||||
def drop_field(app_name, model_name, field_name):
|
||||
"""
|
||||
Drop the given field from the app's model
|
||||
"""
|
||||
# Table is typically appname_modelname, but it could be different
|
||||
# always best to be sure.
|
||||
try:
|
||||
from south.db import db
|
||||
except ImportError:
|
||||
raise ImproperlyConfigured("South must be installed for this command to work")
|
||||
mdl = models.get_model(app_name, model_name)
|
||||
|
||||
|
||||
fld = "%s.%s.%s" % (app_name, model_name, field_name)
|
||||
|
||||
if isinstance(field_registry[fld], CategoryFKField):
|
||||
|
||||
if isinstance(FIELD_REGISTRY[fld], CategoryFKField):
|
||||
print "Dropping ForeignKey %s from %s" % (field_name, model_name)
|
||||
try:
|
||||
db.start_transaction()
|
||||
|
|
@ -76,7 +85,7 @@ def drop_field(app_name, model_name, field_name):
|
|||
except DatabaseError, e:
|
||||
db.rollback_transaction()
|
||||
raise e
|
||||
elif isinstance(field_registry[fld], CategoryM2MField):
|
||||
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')
|
||||
try:
|
||||
|
|
@ -87,5 +96,8 @@ def drop_field(app_name, model_name, field_name):
|
|||
db.rollback_transaction()
|
||||
raise e
|
||||
|
||||
|
||||
post_migrate.connect(migrate_app)
|
||||
try:
|
||||
from south.signals import post_migrate
|
||||
post_migrate.connect(migrate_app)
|
||||
except ImportError:
|
||||
pass
|
||||
|
|
|
|||
61
categories/registration.py
Normal file
61
categories/registration.py
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
"""
|
||||
These functions handle the adding of fields to other models
|
||||
"""
|
||||
from django.db.models import FieldDoesNotExist
|
||||
import fields
|
||||
from settings import FIELD_REGISTRY, MODEL_REGISTRY
|
||||
|
||||
|
||||
def register_m2m(model, field_name='categories', extra_params={}):
|
||||
return _register(model, field_name, extra_params, fields.CategoryM2MField)
|
||||
|
||||
|
||||
def register_fk(model, field_name='category', extra_params={}):
|
||||
return _register(model, field_name, extra_params, fields.CategoryFKField)
|
||||
|
||||
|
||||
def _register(model, field_name, extra_params={}, field=fields.CategoryFKField):
|
||||
app_label = model._meta.app_label
|
||||
registry_name = ".".join((app_label, model.__name__, field_name)).lower()
|
||||
|
||||
if registry_name in FIELD_REGISTRY:
|
||||
return # raise AlreadyRegistered
|
||||
opts = model._meta
|
||||
try:
|
||||
opts.get_field(field_name)
|
||||
except FieldDoesNotExist:
|
||||
if app_label not in MODEL_REGISTRY:
|
||||
MODEL_REGISTRY[app_label] = []
|
||||
if model not in MODEL_REGISTRY[app_label]:
|
||||
MODEL_REGISTRY[app_label].append(model)
|
||||
FIELD_REGISTRY[registry_name] = field(**extra_params)
|
||||
FIELD_REGISTRY[registry_name].contribute_to_class(model, field_name)
|
||||
|
||||
|
||||
def _process_registry(registry, call_func):
|
||||
"""
|
||||
Given a dictionary, and a registration function, process the registry
|
||||
"""
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
from django.db.models.loading import get_model
|
||||
|
||||
for key, value in registry.items():
|
||||
model = get_model(*key.split('.'))
|
||||
if model is None:
|
||||
raise ImproperlyConfigured('%s is not a model' % key)
|
||||
if isinstance(value, (tuple, list)):
|
||||
for item in value:
|
||||
if isinstance(item, basestring):
|
||||
call_func(model, item)
|
||||
elif isinstance(item, dict):
|
||||
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)
|
||||
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)
|
||||
|
|
@ -14,6 +14,7 @@ DEFAULT_SETTINGS = {
|
|||
'JAVASCRIPT_URL': getattr(settings, 'STATIC_URL', settings.MEDIA_URL) + 'js/',
|
||||
'SLUG_TRANSLITERATOR': '',
|
||||
'REGISTER_ADMIN': True,
|
||||
'RELATION_MODELS': [],
|
||||
}
|
||||
|
||||
DEFAULT_SETTINGS.update(getattr(settings, 'CATEGORIES_SETTINGS', {}))
|
||||
|
|
@ -54,3 +55,14 @@ if hasattr(settings, 'CATEGORIES_RELATION_MODELS'):
|
|||
globals().update(DEFAULT_SETTINGS)
|
||||
|
||||
RELATIONS = [Q(app_label=al, model=m) for al, m in [x.split('.') for x in RELATION_MODELS]]
|
||||
|
||||
# The field registry keeps track of the individual fields created.
|
||||
# {'app.model.field': Field(**extra_params)}
|
||||
# Useful for doing a schema migration
|
||||
FIELD_REGISTRY = {}
|
||||
|
||||
# The model registry keeps track of which models have one or more fields
|
||||
# registered.
|
||||
# {'app': [model1, model2]}
|
||||
# Useful for admin alteration
|
||||
MODEL_REGISTRY = {}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
from categories.tests.category_import import *
|
||||
from categories.tests.templatetags import *
|
||||
from categories.tests.manager import *
|
||||
from categories.tests.registration import *
|
||||
|
||||
__fixtures__ = ['categories.json']
|
||||
|
|
|
|||
51
categories/tests/registration.py
Normal file
51
categories/tests/registration.py
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
# Test adding 1 fk string
|
||||
# Test adding 1 fk dict
|
||||
# test adding many-to-many
|
||||
# test adding 1 fk, 1 m2m
|
||||
|
||||
from django.test import TestCase
|
||||
|
||||
from categories.registration import (_process_registry, register_fk,
|
||||
register_m2m)
|
||||
|
||||
|
||||
class CategoryRegistrationTest(TestCase):
|
||||
"""
|
||||
Test various aspects of adding fields to a model.
|
||||
"""
|
||||
|
||||
def test_foreignkey_string(self):
|
||||
FK_REGISTRY = {
|
||||
'flatpages.flatpage': 'category'
|
||||
}
|
||||
_process_registry(FK_REGISTRY, register_fk)
|
||||
from django.contrib.flatpages.models import FlatPage
|
||||
self.assertTrue('category' in FlatPage()._meta.get_all_field_names())
|
||||
|
||||
def test_foreignkey_dict(self):
|
||||
FK_REGISTRY = {
|
||||
'flatpages.flatpage': {'name': 'category'}
|
||||
}
|
||||
_process_registry(FK_REGISTRY, register_fk)
|
||||
from django.contrib.flatpages.models import FlatPage
|
||||
self.assertTrue('category' in FlatPage()._meta.get_all_field_names())
|
||||
|
||||
def test_foreignkey_list(self):
|
||||
FK_REGISTRY = {
|
||||
'flatpages.flatpage': (
|
||||
{'name': 'category', 'related_name': 'cats'},
|
||||
)
|
||||
}
|
||||
_process_registry(FK_REGISTRY, register_fk)
|
||||
from django.contrib.flatpages.models import FlatPage
|
||||
self.assertTrue('category' in FlatPage()._meta.get_all_field_names())
|
||||
|
||||
|
||||
# class Categorym2mTest(TestCase):
|
||||
# def test_m2m_string(self):
|
||||
# M2M_REGISTRY = {
|
||||
# 'flatpages.flatpage': 'categories'
|
||||
# }
|
||||
# _process_registry(M2M_REGISTRY, register_m2m)
|
||||
# from django.contrib.flatpages.models import FlatPage
|
||||
# self.assertTrue('category' in FlatPage()._meta.get_all_field_names())
|
||||
Loading…
Reference in a new issue