mirror of
				https://github.com/graphql-python/graphene-django.git
				synced 2025-11-04 01:47:57 +03:00 
			
		
		
		
	Only warn if a field doesn't exist on the Django model (#862)
* Only warn if a field doesn't exist on the Django model Also don't warn if the field name matches a custom field. * Expand warning messages
This commit is contained in:
		
							parent
							
								
									1310509fa1
								
							
						
					
					
						commit
						280b38f804
					
				| 
						 | 
				
			
			@ -320,26 +320,34 @@ def test_django_objecttype_fields_exclude_type_checking():
 | 
			
		|||
 | 
			
		||||
@with_local_registry
 | 
			
		||||
def test_django_objecttype_fields_exclude_exist_on_model():
 | 
			
		||||
    with pytest.raises(Exception, match=r"Field .* doesn't exist"):
 | 
			
		||||
    with pytest.warns(UserWarning, match=r"Field name .* doesn't exist"):
 | 
			
		||||
 | 
			
		||||
        class Reporter(DjangoObjectType):
 | 
			
		||||
            class Meta:
 | 
			
		||||
                model = ReporterModel
 | 
			
		||||
                fields = ["first_name", "foo", "email"]
 | 
			
		||||
 | 
			
		||||
    with pytest.raises(Exception, match=r"Field .* doesn't exist"):
 | 
			
		||||
    with pytest.warns(
 | 
			
		||||
        UserWarning,
 | 
			
		||||
        match=r"Field name .* matches an attribute on Django model .* but it's not a model field",
 | 
			
		||||
    ) as record:
 | 
			
		||||
 | 
			
		||||
        class Reporter2(DjangoObjectType):
 | 
			
		||||
            class Meta:
 | 
			
		||||
                model = ReporterModel
 | 
			
		||||
                exclude = ["first_name", "foo", "email"]
 | 
			
		||||
                fields = ["first_name", "some_method", "email"]
 | 
			
		||||
 | 
			
		||||
    with pytest.raises(Exception, match=r".* exists on model .* but it's not a field"):
 | 
			
		||||
    # Don't warn if selecting a custom field
 | 
			
		||||
    with pytest.warns(None) as record:
 | 
			
		||||
 | 
			
		||||
        class Reporter3(DjangoObjectType):
 | 
			
		||||
            custom_field = String()
 | 
			
		||||
 | 
			
		||||
            class Meta:
 | 
			
		||||
                model = ReporterModel
 | 
			
		||||
                fields = ["first_name", "some_method", "email"]
 | 
			
		||||
                fields = ["first_name", "custom_field", "email"]
 | 
			
		||||
 | 
			
		||||
    assert len(record) == 0
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TestDjangoObjectType:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -33,24 +33,6 @@ def construct_fields(
 | 
			
		|||
):
 | 
			
		||||
    _model_fields = get_model_fields(model)
 | 
			
		||||
 | 
			
		||||
    # Validate the given fields against the model's fields.
 | 
			
		||||
    model_field_names = set(field[0] for field in _model_fields)
 | 
			
		||||
    for fields_list in (only_fields, exclude_fields):
 | 
			
		||||
        if not fields_list:
 | 
			
		||||
            continue
 | 
			
		||||
        for name in fields_list:
 | 
			
		||||
            if name in model_field_names:
 | 
			
		||||
                continue
 | 
			
		||||
 | 
			
		||||
            if hasattr(model, name):
 | 
			
		||||
                raise Exception(
 | 
			
		||||
                    '"{}" exists on model {} but it\'s not a field.'.format(name, model)
 | 
			
		||||
                )
 | 
			
		||||
            else:
 | 
			
		||||
                raise Exception(
 | 
			
		||||
                    'Field "{}" doesn\'t exist on model {}.'.format(name, model)
 | 
			
		||||
                )
 | 
			
		||||
 | 
			
		||||
    fields = OrderedDict()
 | 
			
		||||
    for name, field in _model_fields:
 | 
			
		||||
        is_not_in_only = only_fields and name not in only_fields
 | 
			
		||||
| 
						 | 
				
			
			@ -80,6 +62,44 @@ def construct_fields(
 | 
			
		|||
    return fields
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def validate_fields(type_, model, fields, only_fields, exclude_fields):
 | 
			
		||||
    # Validate the given fields against the model's fields and custom fields
 | 
			
		||||
    all_field_names = set(fields.keys())
 | 
			
		||||
    for fields_list in (only_fields, exclude_fields):
 | 
			
		||||
        if not fields_list:
 | 
			
		||||
            continue
 | 
			
		||||
        for name in fields_list:
 | 
			
		||||
            if name in all_field_names:
 | 
			
		||||
                continue
 | 
			
		||||
 | 
			
		||||
            if hasattr(model, name):
 | 
			
		||||
                warnings.warn(
 | 
			
		||||
                    (
 | 
			
		||||
                        'Field name "{field_name}" matches an attribute on Django model "{app_label}.{object_name}" '
 | 
			
		||||
                        "but it's not a model field so Graphene cannot determine what type it should be. "
 | 
			
		||||
                        'Either define the type of the field on DjangoObjectType "{type_}" or remove it from the "fields" list.'
 | 
			
		||||
                    ).format(
 | 
			
		||||
                        field_name=name,
 | 
			
		||||
                        app_label=model._meta.app_label,
 | 
			
		||||
                        object_name=model._meta.object_name,
 | 
			
		||||
                        type_=type_,
 | 
			
		||||
                    )
 | 
			
		||||
                )
 | 
			
		||||
 | 
			
		||||
            else:
 | 
			
		||||
                warnings.warn(
 | 
			
		||||
                    (
 | 
			
		||||
                        'Field name "{field_name}" doesn\'t exist on Django model "{app_label}.{object_name}". '
 | 
			
		||||
                        'Consider removing the field from the "fields" list of DjangoObjectType "{type_}" because it has no effect.'
 | 
			
		||||
                    ).format(
 | 
			
		||||
                        field_name=name,
 | 
			
		||||
                        app_label=model._meta.app_label,
 | 
			
		||||
                        object_name=model._meta.object_name,
 | 
			
		||||
                        type_=type_,
 | 
			
		||||
                    )
 | 
			
		||||
                )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class DjangoObjectTypeOptions(ObjectTypeOptions):
 | 
			
		||||
    model = None  # type: Model
 | 
			
		||||
    registry = None  # type: Registry
 | 
			
		||||
| 
						 | 
				
			
			@ -211,6 +231,9 @@ class DjangoObjectType(ObjectType):
 | 
			
		|||
            _meta=_meta, interfaces=interfaces, **options
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        # Validate fields
 | 
			
		||||
        validate_fields(cls, model, _meta.fields, fields, exclude)
 | 
			
		||||
 | 
			
		||||
        if not skip_registry:
 | 
			
		||||
            registry.register(cls)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue
	
	Block a user