Improved registry, raising only when constructing the schema.

This commit is contained in:
Syrus Akbary 2017-02-20 00:47:54 -08:00
parent 4a60da3c36
commit eadd63d096
4 changed files with 46 additions and 31 deletions

View File

@ -25,7 +25,7 @@ You retrieve using the function ``get_global_registry`` in
model = ReporterModel model = ReporterModel
global_registry = get_global_registry global_registry = get_global_registry
global_registry.get_type_for_model(ReporterModel) # == Reporter global_registry.get_unique_type_for_model(ReporterModel) # == Reporter
Multiple types for one model Multiple types for one model

View File

@ -126,7 +126,7 @@ def convert_onetoone_field_to_djangomodel(field, registry=None):
model = get_related_model(field) model = get_related_model(field)
def dynamic_type(): def dynamic_type():
_type = registry.get_type_for_model(model) _type = registry.get_unique_type_for_model(model)
if not _type: if not _type:
return return
@ -145,7 +145,7 @@ def convert_field_to_list_or_connection(field, registry=None):
model = get_related_model(field) model = get_related_model(field)
def dynamic_type(): def dynamic_type():
_type = registry.get_type_for_model(model) _type = registry.get_unique_type_for_model(model)
if not _type: if not _type:
return return
@ -163,7 +163,7 @@ def convert_relatedfield_to_djangomodel(field, registry=None):
model = field.model model = field.model
def dynamic_type(): def dynamic_type():
_type = registry.get_type_for_model(model) _type = registry.get_unique_type_for_model(model)
if not _type: if not _type:
return return
@ -183,7 +183,7 @@ def convert_field_to_djangomodel(field, registry=None):
model = get_related_model(field) model = get_related_model(field)
def dynamic_type(): def dynamic_type():
_type = registry.get_type_for_model(model) _type = registry.get_unique_type_for_model(model)
if not _type: if not _type:
return return

View File

@ -1,30 +1,40 @@
from collections import defaultdict
class Registry(object): class Registry(object):
def __init__(self): def __init__(self):
self._registry = {} self._registry = defaultdict(list)
self._registry_models = {}
def register(self, cls): def register(self, cls):
from .types import DjangoObjectType from .types import DjangoObjectType
model = cls._meta.model model = cls._meta.model
assert self._registry.get(model, cls) == cls, (
'Django Model "{}.{}" already associated with {}. '
'You can use a different registry for {} or skip '
'the global Registry with "{}.Meta.skip_global_registry = True".'
).format(
model._meta.app_label,
model._meta.object_name,
repr(self.get_type_for_model(cls._meta.model)),
repr(cls),
cls
)
assert issubclass( assert issubclass(
cls, DjangoObjectType), 'Only DjangoObjectTypes can be registered, received "{}"'.format( cls, DjangoObjectType), 'Only DjangoObjectTypes can be registered, received "{}"'.format(
cls.__name__) cls.__name__)
assert cls._meta.registry == self, 'Registry for a Model have to match.' assert cls._meta.registry == self, 'Registry for a Model have to match.'
self._registry[cls._meta.model] = cls self._registry[model].append(cls)
def get_type_for_model(self, model): def get_unique_type_for_model(self, model):
types = self.get_types_for_model(model)
if not types:
return None
# If there is more than one type for the model, we should
# raise an error so both types don't collide in the same schema.
assert len(types) == 1, (
'Found multiple ObjectTypes associated with the same Django Model "{}.{}": {}. '
'You can use a different registry for each or skip '
'the global Registry with Meta.skip_global_registry = True". '
'Read more at http://docs.graphene-python.org/projects/django/en/latest/registry/ .'
).format(
model._meta.app_label,
model._meta.object_name,
repr(types),
)
return types[0]
def get_types_for_model(self, model):
return self._registry.get(model) return self._registry.get(model)

View File

@ -18,29 +18,34 @@ def test_registry_basic():
model = ReporterModel model = ReporterModel
assert Reporter._meta.registry == global_registry assert Reporter._meta.registry == global_registry
assert global_registry.get_type_for_model(ReporterModel) == Reporter assert global_registry.get_unique_type_for_model(ReporterModel) == Reporter
def test_registry_multiple_types(): def test_registry_multiple_types():
global_registry = get_global_registry()
class Reporter(DjangoObjectType): class Reporter(DjangoObjectType):
'''Reporter description''' '''Reporter description'''
class Meta: class Meta:
model = ReporterModel model = ReporterModel
class Reporter2(object):
pass
with raises(Exception) as exc_info:
class Reporter2(DjangoObjectType): class Reporter2(DjangoObjectType):
'''Reporter2 description''' '''Reporter2 description'''
class Meta: class Meta:
model = ReporterModel model = ReporterModel
assert global_registry.get_types_for_model(ReporterModel) == [Reporter, Reporter2]
with raises(Exception) as exc_info:
global_registry.get_unique_type_for_model(ReporterModel) == [Reporter, Reporter2]
assert str(exc_info.value) == ( assert str(exc_info.value) == (
'Django Model "tests.Reporter" already associated with {}. ' 'Found multiple ObjectTypes associated with the same '
'You can use a different registry for {} ' 'Django Model "tests.Reporter": {}. You can use a different '
'or skip the global Registry with "Reporter2.Meta.skip_global_registry = True".' 'registry for each or skip the global Registry with '
).format(repr(Reporter), repr(Reporter2)) 'Meta.skip_global_registry = True". '
'Read more at http://docs.graphene-python.org/projects/django/en/latest/registry/ .'
).format(repr([Reporter, Reporter2]))
def test_registry_multiple_types_dont_collision_if_skip_global_registry(): def test_registry_multiple_types_dont_collision_if_skip_global_registry():