Merge branch '1.1.2'

This commit is contained in:
Corey Oordt 2012-08-18 13:07:46 -04:00
commit a92ab30f9c
9 changed files with 172 additions and 118 deletions

View file

@ -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

View file

@ -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:

View file

@ -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

View file

@ -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)

View file

@ -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

View 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)

View file

@ -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 = {}

View file

@ -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']

View 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())