mirror of
				https://github.com/graphql-python/graphene-django.git
				synced 2025-11-04 18:08:01 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			127 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			127 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
from collections import OrderedDict
 | 
						|
 | 
						|
import six
 | 
						|
 | 
						|
from django.utils.functional import SimpleLazyObject
 | 
						|
from graphene import Field, ObjectType
 | 
						|
from graphene.types.objecttype import ObjectTypeMeta
 | 
						|
from graphene.types.options import Options
 | 
						|
from graphene.types.utils import merge, yank_fields_from_attrs
 | 
						|
from graphene.utils.is_base_type import is_base_type
 | 
						|
 | 
						|
from .converter import convert_django_field_with_choices
 | 
						|
from .registry import Registry, get_global_registry
 | 
						|
from .utils import (DJANGO_FILTER_INSTALLED, get_model_fields,
 | 
						|
                    is_valid_django_model)
 | 
						|
 | 
						|
 | 
						|
def construct_fields(options):
 | 
						|
    _model_fields = get_model_fields(options.model)
 | 
						|
    only_fields = options.only_fields
 | 
						|
    exclude_fields = options.exclude_fields
 | 
						|
 | 
						|
    fields = OrderedDict()
 | 
						|
    for field in _model_fields:
 | 
						|
        name = field.name
 | 
						|
        is_not_in_only = only_fields and name not in options.only_fields
 | 
						|
        is_already_created = name in options.fields
 | 
						|
        is_excluded = name in exclude_fields or is_already_created
 | 
						|
        # https://docs.djangoproject.com/en/1.10/ref/models/fields/#django.db.models.ForeignKey.related_query_name
 | 
						|
        is_no_backref = str(name).endswith('+')
 | 
						|
        if is_not_in_only or is_excluded or is_no_backref:
 | 
						|
            # We skip this field if we specify only_fields and is not
 | 
						|
            # in there. Or when we exclude this field in exclude_fields.
 | 
						|
            # Or when there is no back reference.
 | 
						|
            continue
 | 
						|
        converted = convert_django_field_with_choices(field, options.registry)
 | 
						|
        if not converted:
 | 
						|
            continue
 | 
						|
        fields[name] = converted
 | 
						|
 | 
						|
    return fields
 | 
						|
 | 
						|
 | 
						|
class DjangoObjectTypeMeta(ObjectTypeMeta):
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def __new__(cls, name, bases, attrs):
 | 
						|
        # Also ensure initialization is only performed for subclasses of
 | 
						|
        # DjangoObjectType
 | 
						|
        if not is_base_type(bases, DjangoObjectTypeMeta):
 | 
						|
            return type.__new__(cls, name, bases, attrs)
 | 
						|
 | 
						|
        defaults = dict(
 | 
						|
            name=name,
 | 
						|
            description=attrs.pop('__doc__', None),
 | 
						|
            model=None,
 | 
						|
            local_fields=None,
 | 
						|
            only_fields=(),
 | 
						|
            exclude_fields=(),
 | 
						|
            interfaces=(),
 | 
						|
            registry=None
 | 
						|
        )
 | 
						|
        if DJANGO_FILTER_INSTALLED:
 | 
						|
            # In case Django filter is available, then
 | 
						|
            # we allow more attributes in Meta
 | 
						|
            defaults.update(
 | 
						|
                filter_fields=(),
 | 
						|
            )
 | 
						|
 | 
						|
        options = Options(
 | 
						|
            attrs.pop('Meta', None),
 | 
						|
            **defaults
 | 
						|
        )
 | 
						|
        if not options.registry:
 | 
						|
            options.registry = get_global_registry()
 | 
						|
        assert isinstance(options.registry, Registry), (
 | 
						|
            'The attribute registry in {}.Meta needs to be an instance of '
 | 
						|
            'Registry, received "{}".'
 | 
						|
        ).format(name, options.registry)
 | 
						|
        assert is_valid_django_model(options.model), (
 | 
						|
            'You need to pass a valid Django Model in {}.Meta, received "{}".'
 | 
						|
        ).format(name, options.model)
 | 
						|
 | 
						|
        cls = ObjectTypeMeta.__new__(cls, name, bases, dict(attrs, _meta=options))
 | 
						|
 | 
						|
        options.registry.register(cls)
 | 
						|
 | 
						|
        options.django_fields = yank_fields_from_attrs(
 | 
						|
            construct_fields(options),
 | 
						|
            _as=Field,
 | 
						|
        )
 | 
						|
        options.fields = merge(
 | 
						|
            options.interface_fields,
 | 
						|
            options.django_fields,
 | 
						|
            options.base_fields,
 | 
						|
            options.local_fields
 | 
						|
        )
 | 
						|
 | 
						|
        return cls
 | 
						|
 | 
						|
 | 
						|
class DjangoObjectType(six.with_metaclass(DjangoObjectTypeMeta, ObjectType)):
 | 
						|
 | 
						|
    def resolve_id(self, args, context, info):
 | 
						|
        return self.pk
 | 
						|
 | 
						|
    @classmethod
 | 
						|
    def is_type_of(cls, root, context, info):
 | 
						|
        if isinstance(root, SimpleLazyObject):
 | 
						|
            root._setup()
 | 
						|
            root = root._wrapped
 | 
						|
        if isinstance(root, cls):
 | 
						|
            return True
 | 
						|
        if not is_valid_django_model(type(root)):
 | 
						|
            raise Exception((
 | 
						|
                'Received incompatible instance "{}".'
 | 
						|
            ).format(root))
 | 
						|
        model = root._meta.model
 | 
						|
        return model == cls._meta.model
 | 
						|
 | 
						|
    @classmethod
 | 
						|
    def get_node(cls, id, context, info):
 | 
						|
        try:
 | 
						|
            return cls._meta.model.objects.get(pk=id)
 | 
						|
        except cls._meta.model.DoesNotExist:
 | 
						|
            return None
 |