mirror of
				https://github.com/encode/django-rest-framework.git
				synced 2025-11-04 01:47:59 +03:00 
			
		
		
		
	Lots of validator tests passing after refactor
This commit is contained in:
		
							parent
							
								
									136c9b5271
								
							
						
					
					
						commit
						a9df917d10
					
				| 
						 | 
					@ -9,7 +9,6 @@ from django.template import RequestContext, loader
 | 
				
			||||||
from django import forms
 | 
					from django import forms
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from djangorestframework.response import NoContent, ResponseException
 | 
					from djangorestframework.response import NoContent, ResponseException
 | 
				
			||||||
from djangorestframework.validators import FormValidatorMixin
 | 
					 | 
				
			||||||
from djangorestframework.utils import dict2xml, url_resolves
 | 
					from djangorestframework.utils import dict2xml, url_resolves
 | 
				
			||||||
from djangorestframework.markdownwrapper import apply_markdown
 | 
					from djangorestframework.markdownwrapper import apply_markdown
 | 
				
			||||||
from djangorestframework.breadcrumbs import get_breadcrumbs
 | 
					from djangorestframework.breadcrumbs import get_breadcrumbs
 | 
				
			||||||
| 
						 | 
					@ -217,15 +216,11 @@ class DocumentingTemplateEmitter(BaseEmitter):
 | 
				
			||||||
        #form_instance = resource.form_instance
 | 
					        #form_instance = resource.form_instance
 | 
				
			||||||
        # TODO! Reinstate this
 | 
					        # TODO! Reinstate this
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        form_instance = None
 | 
					        form_instance = getattr(resource, 'bound_form_instance', None)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if isinstance(resource, FormValidatorMixin):
 | 
					        if not form_instance and hasattr(resource, 'get_bound_form'):
 | 
				
			||||||
            # If we already have a bound form instance (IE provided by the input parser, then use that)
 | 
					 | 
				
			||||||
            if resource.bound_form_instance is not None:
 | 
					 | 
				
			||||||
                form_instance = resource.bound_form_instance
 | 
					 | 
				
			||||||
                
 | 
					 | 
				
			||||||
            # Otherwise if we have a response that is valid against the form then use that
 | 
					            # Otherwise if we have a response that is valid against the form then use that
 | 
				
			||||||
            if not form_instance and resource.response.has_content_body:
 | 
					            if resource.response.has_content_body:
 | 
				
			||||||
                try:
 | 
					                try:
 | 
				
			||||||
                    form_instance = resource.get_bound_form(resource.response.cleaned_content)
 | 
					                    form_instance = resource.get_bound_form(resource.response.cleaned_content)
 | 
				
			||||||
                    if form_instance and not form_instance.is_valid():
 | 
					                    if form_instance and not form_instance.is_valid():
 | 
				
			||||||
| 
						 | 
					@ -233,12 +228,12 @@ class DocumentingTemplateEmitter(BaseEmitter):
 | 
				
			||||||
                except:
 | 
					                except:
 | 
				
			||||||
                    form_instance = None
 | 
					                    form_instance = None
 | 
				
			||||||
            
 | 
					            
 | 
				
			||||||
            # If we still don't have a form instance then try to get an unbound form
 | 
					        # If we still don't have a form instance then try to get an unbound form
 | 
				
			||||||
            if not form_instance:
 | 
					        if not form_instance:
 | 
				
			||||||
                try:
 | 
					            try:
 | 
				
			||||||
                    form_instance = resource.get_bound_form()
 | 
					                form_instance = resource.get_bound_form()
 | 
				
			||||||
                except:
 | 
					            except:
 | 
				
			||||||
                    pass
 | 
					                pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # If we still don't have a form instance then try to get an unbound form which can tunnel arbitrary content types
 | 
					        # If we still don't have a form instance then try to get an unbound form which can tunnel arbitrary content types
 | 
				
			||||||
        if not form_instance:
 | 
					        if not form_instance:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,15 +5,14 @@ from django.db.models.fields.related import RelatedField
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from djangorestframework.response import Response, ResponseException
 | 
					from djangorestframework.response import Response, ResponseException
 | 
				
			||||||
from djangorestframework.resource import Resource
 | 
					from djangorestframework.resource import Resource
 | 
				
			||||||
from djangorestframework.validators import ModelFormValidatorMixin
 | 
					from djangorestframework import status, validators
 | 
				
			||||||
from djangorestframework import status
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
import decimal
 | 
					import decimal
 | 
				
			||||||
import inspect
 | 
					import inspect
 | 
				
			||||||
import re
 | 
					import re
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ModelResource(Resource, ModelFormValidatorMixin):
 | 
					class ModelResource(Resource):
 | 
				
			||||||
    """A specialized type of Resource, for resources that map directly to a Django Model.
 | 
					    """A specialized type of Resource, for resources that map directly to a Django Model.
 | 
				
			||||||
    Useful things this provides:
 | 
					    Useful things this provides:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -21,6 +20,9 @@ class ModelResource(Resource, ModelFormValidatorMixin):
 | 
				
			||||||
    1. Nice serialization of returned Models and QuerySets.
 | 
					    1. Nice serialization of returned Models and QuerySets.
 | 
				
			||||||
    2. A default set of create/read/update/delete operations."""
 | 
					    2. A default set of create/read/update/delete operations."""
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
 | 
					    # List of validators to validate, cleanup and type-ify the request content    
 | 
				
			||||||
 | 
					    validators = (validators.ModelFormValidator,)
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
    # The model attribute refers to the Django Model which this Resource maps to.
 | 
					    # The model attribute refers to the Django Model which this Resource maps to.
 | 
				
			||||||
    # (The Model's class, rather than an instance of the Model)
 | 
					    # (The Model's class, rather than an instance of the Model)
 | 
				
			||||||
    model = None
 | 
					    model = None
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -196,6 +196,29 @@ class RequestMixin(object):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return parser.parse(stream)
 | 
					        return parser.parse(stream)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def validate(self, content):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Validate, cleanup, and type-ify the request content.
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        for validator_cls in self.validators:
 | 
				
			||||||
 | 
					            validator = validator_cls(self)
 | 
				
			||||||
 | 
					            content = validator.validate(content)
 | 
				
			||||||
 | 
					        return content
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_bound_form(self, content=None):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Return a bound form instance for the given content,
 | 
				
			||||||
 | 
					        if there is an appropriate form validator attached to the view.
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        for validator_cls in self.validators:
 | 
				
			||||||
 | 
					            if hasattr(validator_cls, 'get_bound_form'):
 | 
				
			||||||
 | 
					                validator = validator_cls(self)
 | 
				
			||||||
 | 
					                return validator.get_bound_form(content)
 | 
				
			||||||
 | 
					        return None
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @property
 | 
					    @property
 | 
				
			||||||
    def parsed_media_types(self):
 | 
					    def parsed_media_types(self):
 | 
				
			||||||
        """Return an list of all the media types that this view can parse."""
 | 
					        """Return an list of all the media types that this view can parse."""
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,10 +3,9 @@ from django.views.decorators.csrf import csrf_exempt
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from djangorestframework.compat import View
 | 
					from djangorestframework.compat import View
 | 
				
			||||||
from djangorestframework.emitters import EmitterMixin
 | 
					from djangorestframework.emitters import EmitterMixin
 | 
				
			||||||
from djangorestframework.validators import FormValidatorMixin
 | 
					 | 
				
			||||||
from djangorestframework.response import Response, ResponseException
 | 
					from djangorestframework.response import Response, ResponseException
 | 
				
			||||||
from djangorestframework.request import RequestMixin, AuthMixin
 | 
					from djangorestframework.request import RequestMixin, AuthMixin
 | 
				
			||||||
from djangorestframework import emitters, parsers, authenticators, status
 | 
					from djangorestframework import emitters, parsers, authenticators, validators, status
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# TODO: Figure how out references and named urls need to work nicely
 | 
					# TODO: Figure how out references and named urls need to work nicely
 | 
				
			||||||
| 
						 | 
					@ -17,7 +16,7 @@ from djangorestframework import emitters, parsers, authenticators, status
 | 
				
			||||||
__all__ = ['Resource']
 | 
					__all__ = ['Resource']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Resource(EmitterMixin, AuthMixin, FormValidatorMixin, RequestMixin, View):
 | 
					class Resource(EmitterMixin, AuthMixin, RequestMixin, View):
 | 
				
			||||||
    """Handles incoming requests and maps them to REST operations,
 | 
					    """Handles incoming requests and maps them to REST operations,
 | 
				
			||||||
    performing authentication, input deserialization, input validation, output serialization."""
 | 
					    performing authentication, input deserialization, input validation, output serialization."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -38,7 +37,10 @@ class Resource(EmitterMixin, AuthMixin, FormValidatorMixin, RequestMixin, View):
 | 
				
			||||||
    parsers = ( parsers.JSONParser,
 | 
					    parsers = ( parsers.JSONParser,
 | 
				
			||||||
                parsers.FormParser,
 | 
					                parsers.FormParser,
 | 
				
			||||||
                parsers.MultipartParser )
 | 
					                parsers.MultipartParser )
 | 
				
			||||||
    
 | 
					
 | 
				
			||||||
 | 
					    # List of validators to validate, cleanup and type-ify the request content    
 | 
				
			||||||
 | 
					    validators = (validators.FormValidator,)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # List of all authenticating methods to attempt.
 | 
					    # List of all authenticating methods to attempt.
 | 
				
			||||||
    authenticators = ( authenticators.UserLoggedInAuthenticator,
 | 
					    authenticators = ( authenticators.UserLoggedInAuthenticator,
 | 
				
			||||||
                       authenticators.BasicAuthenticator )
 | 
					                       authenticators.BasicAuthenticator )
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,7 +2,7 @@ from django import forms
 | 
				
			||||||
from django.db import models
 | 
					from django.db import models
 | 
				
			||||||
from django.test import TestCase
 | 
					from django.test import TestCase
 | 
				
			||||||
from djangorestframework.compat import RequestFactory
 | 
					from djangorestframework.compat import RequestFactory
 | 
				
			||||||
from djangorestframework.validators import ValidatorMixin, FormValidatorMixin, ModelFormValidatorMixin
 | 
					from djangorestframework.validators import BaseValidator, FormValidator, ModelFormValidator
 | 
				
			||||||
from djangorestframework.response import ResponseException
 | 
					from djangorestframework.response import ResponseException
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -11,59 +11,68 @@ class TestValidatorMixinInterfaces(TestCase):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_validator_mixin_interface(self):
 | 
					    def test_validator_mixin_interface(self):
 | 
				
			||||||
        """Ensure the ValidatorMixin base class interface is as expected."""
 | 
					        """Ensure the ValidatorMixin base class interface is as expected."""
 | 
				
			||||||
        self.assertRaises(NotImplementedError, ValidatorMixin().validate, None)
 | 
					        self.assertRaises(NotImplementedError, BaseValidator(None).validate, None)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_form_validator_mixin_interface(self):
 | 
					    #def test_form_validator_mixin_interface(self):
 | 
				
			||||||
        """Ensure the FormValidatorMixin interface is as expected."""
 | 
					    #    """Ensure the FormValidatorMixin interface is as expected."""
 | 
				
			||||||
        self.assertTrue(issubclass(FormValidatorMixin, ValidatorMixin))
 | 
					    #    self.assertTrue(issubclass(FormValidator, BaseValidator))
 | 
				
			||||||
        getattr(FormValidatorMixin, 'form')
 | 
					    #    getattr(FormValidator, 'form')
 | 
				
			||||||
        getattr(FormValidatorMixin, 'validate')
 | 
					    #    getattr(FormValidator, 'validate')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_model_form_validator_mixin_interface(self):
 | 
					    #def test_model_form_validator_mixin_interface(self):
 | 
				
			||||||
        """Ensure the ModelFormValidatorMixin interface is as expected."""
 | 
					    #    """Ensure the ModelFormValidatorMixin interface is as expected."""
 | 
				
			||||||
        self.assertTrue(issubclass(ModelFormValidatorMixin, FormValidatorMixin))
 | 
					    #    self.assertTrue(issubclass(ModelFormValidator, FormValidator))
 | 
				
			||||||
        getattr(ModelFormValidatorMixin, 'model')
 | 
					    #    getattr(ModelFormValidator, 'model')
 | 
				
			||||||
        getattr(ModelFormValidatorMixin, 'form')
 | 
					    #    getattr(ModelFormValidator, 'form')
 | 
				
			||||||
        getattr(ModelFormValidatorMixin, 'fields')
 | 
					    #    getattr(ModelFormValidator, 'fields')
 | 
				
			||||||
        getattr(ModelFormValidatorMixin, 'exclude_fields')
 | 
					    #    getattr(ModelFormValidator, 'exclude_fields')
 | 
				
			||||||
        getattr(ModelFormValidatorMixin, 'validate')
 | 
					    #    getattr(ModelFormValidator, 'validate')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class TestDisabledValidations(TestCase):
 | 
					class TestDisabledValidations(TestCase):
 | 
				
			||||||
    """Tests on Validator Mixins with validation disabled by setting form to None"""
 | 
					    """Tests on FormValidator with validation disabled by setting form to None"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_disabled_form_validator_returns_content_unchanged(self):
 | 
					    def test_disabled_form_validator_returns_content_unchanged(self):
 | 
				
			||||||
        """If the form attribute is None on FormValidatorMixin then validate(content) should just return the content unmodified."""
 | 
					        """If the view's form attribute is None then FormValidator(view).validate(content)
 | 
				
			||||||
        class DisabledFormValidator(FormValidatorMixin):
 | 
					        should just return the content unmodified."""
 | 
				
			||||||
 | 
					        class DisabledFormView(object):
 | 
				
			||||||
            form = None
 | 
					            form = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        view = DisabledFormView()
 | 
				
			||||||
        content = {'qwerty':'uiop'}       
 | 
					        content = {'qwerty':'uiop'}       
 | 
				
			||||||
        self.assertEqual(DisabledFormValidator().validate(content), content)
 | 
					        self.assertEqual(FormValidator(view).validate(content), content)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_disabled_form_validator_get_bound_form_returns_none(self):
 | 
					    def test_disabled_form_validator_get_bound_form_returns_none(self):
 | 
				
			||||||
        """If the form attribute is None on FormValidatorMixin then get_bound_form(content) should just return None."""
 | 
					        """If the view's form attribute is None on then
 | 
				
			||||||
        class DisabledFormValidator(FormValidatorMixin):
 | 
					        FormValidator(view).get_bound_form(content) should just return None."""
 | 
				
			||||||
            form = None
 | 
					        class DisabledFormView(object):
 | 
				
			||||||
 | 
					 | 
				
			||||||
        content = {'qwerty':'uiop'}     
 | 
					 | 
				
			||||||
        self.assertEqual(DisabledFormValidator().get_bound_form(content), None)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def test_disabled_model_form_validator_returns_content_unchanged(self):
 | 
					 | 
				
			||||||
        """If the form attribute is None on FormValidatorMixin then validate(content) should just return the content unmodified."""
 | 
					 | 
				
			||||||
        class DisabledModelFormValidator(ModelFormValidatorMixin):
 | 
					 | 
				
			||||||
            form = None
 | 
					            form = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        view = DisabledFormView()
 | 
				
			||||||
        content = {'qwerty':'uiop'}       
 | 
					        content = {'qwerty':'uiop'}       
 | 
				
			||||||
        self.assertEqual(DisabledModelFormValidator().validate(content), content)
 | 
					        self.assertEqual(FormValidator(view).get_bound_form(content), None)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					    def test_disabled_model_form_validator_returns_content_unchanged(self):
 | 
				
			||||||
 | 
					        """If the view's form and model attributes are None then
 | 
				
			||||||
 | 
					        ModelFormValidator(view).validate(content) should just return the content unmodified."""
 | 
				
			||||||
 | 
					        class DisabledModelFormView(object):
 | 
				
			||||||
 | 
					            form = None
 | 
				
			||||||
 | 
					            model = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        view = DisabledModelFormView()
 | 
				
			||||||
 | 
					        content = {'qwerty':'uiop'}       
 | 
				
			||||||
 | 
					        self.assertEqual(ModelFormValidator(view).get_bound_form(content), None)#
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_disabled_model_form_validator_get_bound_form_returns_none(self):
 | 
					    def test_disabled_model_form_validator_get_bound_form_returns_none(self):
 | 
				
			||||||
        """If the form attribute is None on FormValidatorMixin then get_bound_form(content) should just return None."""
 | 
					        """If the form attribute is None on FormValidatorMixin then get_bound_form(content) should just return None."""
 | 
				
			||||||
        class DisabledModelFormValidator(ModelFormValidatorMixin):
 | 
					        class DisabledModelFormView(object):
 | 
				
			||||||
            form = None
 | 
					            form = None
 | 
				
			||||||
 | 
					            model = None
 | 
				
			||||||
        content = {'qwerty':'uiop'}     
 | 
					 
 | 
				
			||||||
        self.assertEqual(DisabledModelFormValidator().get_bound_form(content), None)
 | 
					        view = DisabledModelFormView()
 | 
				
			||||||
 | 
					        content = {'qwerty':'uiop'}       
 | 
				
			||||||
 | 
					        self.assertEqual(ModelFormValidator(view).get_bound_form(content), None)# 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class TestNonFieldErrors(TestCase):
 | 
					class TestNonFieldErrors(TestCase):
 | 
				
			||||||
    """Tests against form validation errors caused by non-field errors.  (eg as might be caused by some custom form validation)"""
 | 
					    """Tests against form validation errors caused by non-field errors.  (eg as might be caused by some custom form validation)"""
 | 
				
			||||||
| 
						 | 
					@ -80,12 +89,13 @@ class TestNonFieldErrors(TestCase):
 | 
				
			||||||
                    raise forms.ValidationError(self.ERROR_TEXT)
 | 
					                    raise forms.ValidationError(self.ERROR_TEXT)
 | 
				
			||||||
                return self.cleaned_data  #pragma: no cover
 | 
					                return self.cleaned_data  #pragma: no cover
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        class MockValidator(FormValidatorMixin):
 | 
					        class MockView(object):
 | 
				
			||||||
            form = MockForm
 | 
					            form = MockForm
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
 | 
					        view = MockView()
 | 
				
			||||||
        content = {'field1': 'example1', 'field2': 'example2'}
 | 
					        content = {'field1': 'example1', 'field2': 'example2'}
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
            MockValidator().validate(content)
 | 
					            FormValidator(view).validate(content)
 | 
				
			||||||
        except ResponseException, exc:           
 | 
					        except ResponseException, exc:           
 | 
				
			||||||
            self.assertEqual(exc.response.raw_content, {'errors': [MockForm.ERROR_TEXT]})
 | 
					            self.assertEqual(exc.response.raw_content, {'errors': [MockForm.ERROR_TEXT]})
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
| 
						 | 
					@ -95,19 +105,21 @@ class TestNonFieldErrors(TestCase):
 | 
				
			||||||
class TestFormValidation(TestCase):
 | 
					class TestFormValidation(TestCase):
 | 
				
			||||||
    """Tests which check basic form validation.
 | 
					    """Tests which check basic form validation.
 | 
				
			||||||
    Also includes the same set of tests with a ModelFormValidator for which the form has been explicitly set.
 | 
					    Also includes the same set of tests with a ModelFormValidator for which the form has been explicitly set.
 | 
				
			||||||
    (ModelFormValidatorMixin should behave as FormValidatorMixin if form is set rather than relying on the default ModelForm)"""
 | 
					    (ModelFormValidator should behave as FormValidator if a form is set rather than relying on the default ModelForm)"""
 | 
				
			||||||
    def setUp(self):       
 | 
					    def setUp(self):       
 | 
				
			||||||
        class MockForm(forms.Form):
 | 
					        class MockForm(forms.Form):
 | 
				
			||||||
            qwerty = forms.CharField(required=True)
 | 
					            qwerty = forms.CharField(required=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        class MockFormValidator(FormValidatorMixin):
 | 
					        class MockFormView(object):
 | 
				
			||||||
            form = MockForm
 | 
					            form = MockForm
 | 
				
			||||||
 | 
					            validators = (FormValidator,)
 | 
				
			||||||
        class MockModelFormValidator(ModelFormValidatorMixin):
 | 
					 
 | 
				
			||||||
 | 
					        class MockModelFormView(object):
 | 
				
			||||||
            form = MockForm
 | 
					            form = MockForm
 | 
				
			||||||
        
 | 
					            validators = (ModelFormValidator,)
 | 
				
			||||||
        self.MockFormValidator = MockFormValidator
 | 
					         
 | 
				
			||||||
        self.MockModelFormValidator = MockModelFormValidator       
 | 
					        self.MockFormView = MockFormView
 | 
				
			||||||
 | 
					        self.MockModelFormView = MockModelFormView       
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def validation_returns_content_unchanged_if_already_valid_and_clean(self, validator):
 | 
					    def validation_returns_content_unchanged_if_already_valid_and_clean(self, validator):
 | 
				
			||||||
| 
						 | 
					@ -181,111 +193,129 @@ class TestFormValidation(TestCase):
 | 
				
			||||||
    # Tests on FormValidtionMixin
 | 
					    # Tests on FormValidtionMixin
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_form_validation_returns_content_unchanged_if_already_valid_and_clean(self):
 | 
					    def test_form_validation_returns_content_unchanged_if_already_valid_and_clean(self):
 | 
				
			||||||
        self.validation_returns_content_unchanged_if_already_valid_and_clean(self.MockFormValidator())
 | 
					        validator = FormValidator(self.MockFormView())
 | 
				
			||||||
 | 
					        self.validation_returns_content_unchanged_if_already_valid_and_clean(validator)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_form_validation_failure_raises_response_exception(self):
 | 
					    def test_form_validation_failure_raises_response_exception(self):
 | 
				
			||||||
        self.validation_failure_raises_response_exception(self.MockFormValidator())
 | 
					        validator = FormValidator(self.MockFormView())
 | 
				
			||||||
 | 
					        self.validation_failure_raises_response_exception(validator)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_validation_does_not_allow_extra_fields_by_default(self):
 | 
					    def test_validation_does_not_allow_extra_fields_by_default(self):
 | 
				
			||||||
        self.validation_does_not_allow_extra_fields_by_default(self.MockFormValidator())
 | 
					        validator = FormValidator(self.MockFormView())
 | 
				
			||||||
 | 
					        self.validation_does_not_allow_extra_fields_by_default(validator)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_validation_allows_extra_fields_if_explicitly_set(self):
 | 
					    def test_validation_allows_extra_fields_if_explicitly_set(self):
 | 
				
			||||||
        self.validation_allows_extra_fields_if_explicitly_set(self.MockFormValidator())
 | 
					        validator = FormValidator(self.MockFormView())
 | 
				
			||||||
 | 
					        self.validation_allows_extra_fields_if_explicitly_set(validator)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_validation_does_not_require_extra_fields_if_explicitly_set(self):
 | 
					    def test_validation_does_not_require_extra_fields_if_explicitly_set(self):
 | 
				
			||||||
        self.validation_does_not_require_extra_fields_if_explicitly_set(self.MockFormValidator())
 | 
					        validator = FormValidator(self.MockFormView())
 | 
				
			||||||
 | 
					        self.validation_does_not_require_extra_fields_if_explicitly_set(validator)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_validation_failed_due_to_no_content_returns_appropriate_message(self):
 | 
					    def test_validation_failed_due_to_no_content_returns_appropriate_message(self):
 | 
				
			||||||
        self.validation_failed_due_to_no_content_returns_appropriate_message(self.MockFormValidator())
 | 
					        validator = FormValidator(self.MockFormView())
 | 
				
			||||||
 | 
					        self.validation_failed_due_to_no_content_returns_appropriate_message(validator)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_validation_failed_due_to_field_error_returns_appropriate_message(self):
 | 
					    def test_validation_failed_due_to_field_error_returns_appropriate_message(self):
 | 
				
			||||||
        self.validation_failed_due_to_field_error_returns_appropriate_message(self.MockFormValidator())
 | 
					        validator = FormValidator(self.MockFormView())
 | 
				
			||||||
 | 
					        self.validation_failed_due_to_field_error_returns_appropriate_message(validator)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_validation_failed_due_to_invalid_field_returns_appropriate_message(self):
 | 
					    def test_validation_failed_due_to_invalid_field_returns_appropriate_message(self):
 | 
				
			||||||
        self.validation_failed_due_to_invalid_field_returns_appropriate_message(self.MockFormValidator())
 | 
					        validator = FormValidator(self.MockFormView())
 | 
				
			||||||
 | 
					        self.validation_failed_due_to_invalid_field_returns_appropriate_message(validator)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_validation_failed_due_to_multiple_errors_returns_appropriate_message(self):
 | 
					    def test_validation_failed_due_to_multiple_errors_returns_appropriate_message(self):
 | 
				
			||||||
        self.validation_failed_due_to_multiple_errors_returns_appropriate_message(self.MockFormValidator())
 | 
					        validator = FormValidator(self.MockFormView())
 | 
				
			||||||
 | 
					        self.validation_failed_due_to_multiple_errors_returns_appropriate_message(validator)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # Same tests on ModelFormValidtionMixin
 | 
					    # Same tests on ModelFormValidtionMixin
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_modelform_validation_returns_content_unchanged_if_already_valid_and_clean(self):
 | 
					    def test_modelform_validation_returns_content_unchanged_if_already_valid_and_clean(self):
 | 
				
			||||||
        self.validation_returns_content_unchanged_if_already_valid_and_clean(self.MockModelFormValidator())
 | 
					        validator = ModelFormValidator(self.MockModelFormView())
 | 
				
			||||||
 | 
					        self.validation_returns_content_unchanged_if_already_valid_and_clean(validator)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_modelform_validation_failure_raises_response_exception(self):
 | 
					    def test_modelform_validation_failure_raises_response_exception(self):
 | 
				
			||||||
        self.validation_failure_raises_response_exception(self.MockModelFormValidator())
 | 
					        validator = ModelFormValidator(self.MockModelFormView())
 | 
				
			||||||
 | 
					        self.validation_failure_raises_response_exception(validator)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_modelform_validation_does_not_allow_extra_fields_by_default(self):
 | 
					    def test_modelform_validation_does_not_allow_extra_fields_by_default(self):
 | 
				
			||||||
        self.validation_does_not_allow_extra_fields_by_default(self.MockModelFormValidator())
 | 
					        validator = ModelFormValidator(self.MockModelFormView())
 | 
				
			||||||
 | 
					        self.validation_does_not_allow_extra_fields_by_default(validator)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_modelform_validation_allows_extra_fields_if_explicitly_set(self):
 | 
					    def test_modelform_validation_allows_extra_fields_if_explicitly_set(self):
 | 
				
			||||||
        self.validation_allows_extra_fields_if_explicitly_set(self.MockModelFormValidator())
 | 
					        validator = ModelFormValidator(self.MockModelFormView())
 | 
				
			||||||
 | 
					        self.validation_allows_extra_fields_if_explicitly_set(validator)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_modelform_validation_does_not_require_extra_fields_if_explicitly_set(self):
 | 
					    def test_modelform_validation_does_not_require_extra_fields_if_explicitly_set(self):
 | 
				
			||||||
        self.validation_does_not_require_extra_fields_if_explicitly_set(self.MockModelFormValidator())
 | 
					        validator = ModelFormValidator(self.MockModelFormView())
 | 
				
			||||||
 | 
					        self.validation_does_not_require_extra_fields_if_explicitly_set(validator)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_modelform_validation_failed_due_to_no_content_returns_appropriate_message(self):
 | 
					    def test_modelform_validation_failed_due_to_no_content_returns_appropriate_message(self):
 | 
				
			||||||
        self.validation_failed_due_to_no_content_returns_appropriate_message(self.MockModelFormValidator())
 | 
					        validator = ModelFormValidator(self.MockModelFormView())
 | 
				
			||||||
 | 
					        self.validation_failed_due_to_no_content_returns_appropriate_message(validator)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_modelform_validation_failed_due_to_field_error_returns_appropriate_message(self):
 | 
					    def test_modelform_validation_failed_due_to_field_error_returns_appropriate_message(self):
 | 
				
			||||||
        self.validation_failed_due_to_field_error_returns_appropriate_message(self.MockModelFormValidator())
 | 
					        validator = ModelFormValidator(self.MockModelFormView())
 | 
				
			||||||
 | 
					        self.validation_failed_due_to_field_error_returns_appropriate_message(validator)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_modelform_validation_failed_due_to_invalid_field_returns_appropriate_message(self):
 | 
					    def test_modelform_validation_failed_due_to_invalid_field_returns_appropriate_message(self):
 | 
				
			||||||
        self.validation_failed_due_to_invalid_field_returns_appropriate_message(self.MockModelFormValidator())
 | 
					        validator = ModelFormValidator(self.MockModelFormView())
 | 
				
			||||||
 | 
					        self.validation_failed_due_to_invalid_field_returns_appropriate_message(validator)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_modelform_validation_failed_due_to_multiple_errors_returns_appropriate_message(self):
 | 
					    def test_modelform_validation_failed_due_to_multiple_errors_returns_appropriate_message(self):
 | 
				
			||||||
        self.validation_failed_due_to_multiple_errors_returns_appropriate_message(self.MockModelFormValidator())
 | 
					        validator = ModelFormValidator(self.MockModelFormView())
 | 
				
			||||||
 | 
					        self.validation_failed_due_to_multiple_errors_returns_appropriate_message(validator)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class TestModelFormValidator(TestCase):
 | 
					# class TestModelFormValidator(TestCase):
 | 
				
			||||||
    """Tests specific to ModelFormValidatorMixin"""
 | 
					#     """Tests specific to ModelFormValidatorMixin"""
 | 
				
			||||||
    
 | 
					#     
 | 
				
			||||||
    def setUp(self):
 | 
					#     def setUp(self):
 | 
				
			||||||
        """Create a validator for a model with two fields and a property."""    
 | 
					#         """Create a validator for a model with two fields and a property."""    
 | 
				
			||||||
        class MockModel(models.Model):
 | 
					#         class MockModel(models.Model):
 | 
				
			||||||
            qwerty = models.CharField(max_length=256)
 | 
					#             qwerty = models.CharField(max_length=256)
 | 
				
			||||||
            uiop = models.CharField(max_length=256, blank=True)
 | 
					#             uiop = models.CharField(max_length=256, blank=True)
 | 
				
			||||||
            
 | 
					#             
 | 
				
			||||||
            @property
 | 
					#             @property
 | 
				
			||||||
            def readonly(self):
 | 
					#             def readonly(self):
 | 
				
			||||||
                return 'read only'
 | 
					#                 return 'read only'
 | 
				
			||||||
            
 | 
					#             
 | 
				
			||||||
        class MockValidator(ModelFormValidatorMixin):
 | 
					#         class MockValidator(ModelFormValidatorMixin):
 | 
				
			||||||
            model = MockModel
 | 
					#             model = MockModel
 | 
				
			||||||
       
 | 
					#        
 | 
				
			||||||
        self.MockValidator = MockValidator
 | 
					#         self.MockValidator = MockValidator
 | 
				
			||||||
 | 
					# 
 | 
				
			||||||
 | 
					# 
 | 
				
			||||||
    def test_property_fields_are_allowed_on_model_forms(self):
 | 
					#     def test_property_fields_are_allowed_on_model_forms(self):
 | 
				
			||||||
        """Validation on ModelForms may include property fields that exist on the Model to be included in the input."""
 | 
					#         """Validation on ModelForms may include property fields that exist on the Model to be included in the input."""
 | 
				
			||||||
        content = {'qwerty':'example', 'uiop': 'example', 'readonly': 'read only'}
 | 
					#         content = {'qwerty':'example', 'uiop': 'example', 'readonly': 'read only'}
 | 
				
			||||||
        self.assertEqual(self.MockValidator().validate(content), content)
 | 
					#         self.assertEqual(self.MockValidator().validate(content), content)
 | 
				
			||||||
 | 
					# 
 | 
				
			||||||
    def test_property_fields_are_not_required_on_model_forms(self):
 | 
					#     def test_property_fields_are_not_required_on_model_forms(self):
 | 
				
			||||||
        """Validation on ModelForms does not require property fields that exist on the Model to be included in the input."""
 | 
					#         """Validation on ModelForms does not require property fields that exist on the Model to be included in the input."""
 | 
				
			||||||
        content = {'qwerty':'example', 'uiop': 'example'}
 | 
					#         content = {'qwerty':'example', 'uiop': 'example'}
 | 
				
			||||||
        self.assertEqual(self.MockValidator().validate(content), content)
 | 
					#         self.assertEqual(self.MockValidator().validate(content), content)
 | 
				
			||||||
 | 
					# 
 | 
				
			||||||
    def test_extra_fields_not_allowed_on_model_forms(self):
 | 
					#     def test_extra_fields_not_allowed_on_model_forms(self):
 | 
				
			||||||
        """If some (otherwise valid) content includes fields that are not in the form then validation should fail.
 | 
					#         """If some (otherwise valid) content includes fields that are not in the form then validation should fail.
 | 
				
			||||||
        It might be okay on normal form submission, but for Web APIs we oughta get strict, as it'll help show up
 | 
					#         It might be okay on normal form submission, but for Web APIs we oughta get strict, as it'll help show up
 | 
				
			||||||
        broken clients more easily (eg submitting content with a misnamed field)"""
 | 
					#         broken clients more easily (eg submitting content with a misnamed field)"""
 | 
				
			||||||
        content = {'qwerty': 'example', 'uiop':'example', 'readonly': 'read only', 'extra': 'extra'} 
 | 
					#         content = {'qwerty': 'example', 'uiop':'example', 'readonly': 'read only', 'extra': 'extra'} 
 | 
				
			||||||
        self.assertRaises(ResponseException, self.MockValidator().validate, content)
 | 
					#         self.assertRaises(ResponseException, self.MockValidator().validate, content)
 | 
				
			||||||
    
 | 
					#     
 | 
				
			||||||
    def test_validate_requires_fields_on_model_forms(self):
 | 
					#     def test_validate_requires_fields_on_model_forms(self):
 | 
				
			||||||
        """If some (otherwise valid) content includes fields that are not in the form then validation should fail.
 | 
					#         """If some (otherwise valid) content includes fields that are not in the form then validation should fail.
 | 
				
			||||||
        It might be okay on normal form submission, but for Web APIs we oughta get strict, as it'll help show up
 | 
					#         It might be okay on normal form submission, but for Web APIs we oughta get strict, as it'll help show up
 | 
				
			||||||
        broken clients more easily (eg submitting content with a misnamed field)"""
 | 
					#         broken clients more easily (eg submitting content with a misnamed field)"""
 | 
				
			||||||
        content = {'readonly': 'read only'} 
 | 
					#         content = {'readonly': 'read only'} 
 | 
				
			||||||
        self.assertRaises(ResponseException, self.MockValidator().validate, content)
 | 
					#         self.assertRaises(ResponseException, self.MockValidator().validate, content)
 | 
				
			||||||
    
 | 
					#     
 | 
				
			||||||
    def test_validate_does_not_require_blankable_fields_on_model_forms(self):
 | 
					#     def test_validate_does_not_require_blankable_fields_on_model_forms(self):
 | 
				
			||||||
        """Test standard ModelForm validation behaviour - fields with blank=True are not required."""
 | 
					#         """Test standard ModelForm validation behaviour - fields with blank=True are not required."""
 | 
				
			||||||
        content = {'qwerty':'example', 'readonly': 'read only'}
 | 
					#         content = {'qwerty':'example', 'readonly': 'read only'}
 | 
				
			||||||
        self.MockValidator().validate(content)
 | 
					#         self.MockValidator().validate(content)
 | 
				
			||||||
    
 | 
					#     
 | 
				
			||||||
    def test_model_form_validator_uses_model_forms(self):
 | 
					#     def test_model_form_validator_uses_model_forms(self):
 | 
				
			||||||
        self.assertTrue(isinstance(self.MockValidator().get_bound_form(), forms.ModelForm))
 | 
					#         self.assertTrue(isinstance(self.MockValidator().get_bound_form(), forms.ModelForm))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,25 +4,31 @@ from django.db import models
 | 
				
			||||||
from djangorestframework.response import ResponseException
 | 
					from djangorestframework.response import ResponseException
 | 
				
			||||||
from djangorestframework.utils import as_tuple
 | 
					from djangorestframework.utils import as_tuple
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ValidatorMixin(object):
 | 
					
 | 
				
			||||||
    """Base class for all ValidatorMixin classes, which simply defines the interface they provide."""
 | 
					class BaseValidator(object):
 | 
				
			||||||
 | 
					    """Base class for all Validator classes, which simply defines the interface they provide."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, view):
 | 
				
			||||||
 | 
					        self.view = view
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def validate(self, content):
 | 
					    def validate(self, content):
 | 
				
			||||||
        """Given some content as input return some cleaned, validated content.
 | 
					        """Given some content as input return some cleaned, validated content.
 | 
				
			||||||
        Raises a ResponseException with status code 400 (Bad Request) on failure.
 | 
					        Typically raises a ResponseException with status code 400 (Bad Request) on failure.
 | 
				
			||||||
        
 | 
					
 | 
				
			||||||
        Must be overridden to be implemented."""
 | 
					        Must be overridden to be implemented."""
 | 
				
			||||||
        raise NotImplementedError()
 | 
					        raise NotImplementedError()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class FormValidatorMixin(ValidatorMixin):
 | 
					class FormValidator(BaseValidator):
 | 
				
			||||||
    """Validator Mixin that uses forms for validation.
 | 
					    """Validator class that uses forms for validation.
 | 
				
			||||||
    Extends the ValidatorMixin interface to also provide a get_bound_form() method.
 | 
					    Also provides a get_bound_form() method which may be used by some renderers.
 | 
				
			||||||
    (Which may be used by some emitters.)"""
 | 
					 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    """The form class that should be used for validation, or None to turn off form validation."""
 | 
					    The view class should provide `.form` attribute which specifies the form classmethod
 | 
				
			||||||
    form = None
 | 
					    to be used for validation.
 | 
				
			||||||
    bound_form_instance = None
 | 
					    
 | 
				
			||||||
 | 
					    On calling validate() this validator may set a `.bound_form_instance` attribute on the
 | 
				
			||||||
 | 
					    view, which may be used by some renderers."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def validate(self, content):
 | 
					    def validate(self, content):
 | 
				
			||||||
        """Given some content as input return some cleaned, validated content.
 | 
					        """Given some content as input return some cleaned, validated content.
 | 
				
			||||||
| 
						 | 
					@ -44,7 +50,7 @@ class FormValidatorMixin(ValidatorMixin):
 | 
				
			||||||
        if bound_form is None:
 | 
					        if bound_form is None:
 | 
				
			||||||
            return content
 | 
					            return content
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        self.bound_form_instance = bound_form
 | 
					        self.view.bound_form_instance = bound_form
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        seen_fields_set = set(content.keys())
 | 
					        seen_fields_set = set(content.keys())
 | 
				
			||||||
        form_fields_set = set(bound_form.fields.keys())
 | 
					        form_fields_set = set(bound_form.fields.keys())
 | 
				
			||||||
| 
						 | 
					@ -78,7 +84,10 @@ class FormValidatorMixin(ValidatorMixin):
 | 
				
			||||||
                detail[u'errors'] = bound_form.non_field_errors()
 | 
					                detail[u'errors'] = bound_form.non_field_errors()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            # Add standard field errors
 | 
					            # Add standard field errors
 | 
				
			||||||
            field_errors = dict((key, map(unicode, val)) for (key, val) in bound_form.errors.iteritems() if not key.startswith('__'))
 | 
					            field_errors = dict((key, map(unicode, val))
 | 
				
			||||||
 | 
					                for (key, val)
 | 
				
			||||||
 | 
					                in bound_form.errors.iteritems()
 | 
				
			||||||
 | 
					                if not key.startswith('__'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            # Add any unknown field errors
 | 
					            # Add any unknown field errors
 | 
				
			||||||
            for key in unknown_fields:
 | 
					            for key in unknown_fields:
 | 
				
			||||||
| 
						 | 
					@ -94,20 +103,21 @@ class FormValidatorMixin(ValidatorMixin):
 | 
				
			||||||
    def get_bound_form(self, content=None):
 | 
					    def get_bound_form(self, content=None):
 | 
				
			||||||
        """Given some content return a Django form bound to that content.
 | 
					        """Given some content return a Django form bound to that content.
 | 
				
			||||||
        If form validation is turned off (form class attribute is None) then returns None."""
 | 
					        If form validation is turned off (form class attribute is None) then returns None."""
 | 
				
			||||||
        if not self.form:
 | 
					        form_cls = getattr(self.view, 'form', None)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if not form_cls:
 | 
				
			||||||
            return None
 | 
					            return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if not content is None:
 | 
					        if content is not None:
 | 
				
			||||||
            if hasattr(content, 'FILES'):
 | 
					            if hasattr(content, 'FILES'):
 | 
				
			||||||
                return self.form(content, content.FILES)
 | 
					                return form_cls(content, content.FILES)
 | 
				
			||||||
            return self.form(content)
 | 
					            return form_cls(content)
 | 
				
			||||||
        return self.form()
 | 
					        return form_cls()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ModelFormValidatorMixin(FormValidatorMixin):
 | 
					class ModelFormValidator(FormValidator):
 | 
				
			||||||
    """Validator Mixin that uses forms for validation and falls back to a model form if no form is set.
 | 
					    """Validator class that uses forms for validation and otherwise falls back to a model form if no form is set.
 | 
				
			||||||
    Extends the ValidatorMixin interface to also provide a get_bound_form() method.
 | 
					    Also provides a get_bound_form() method which may be used by some renderers."""
 | 
				
			||||||
    (Which may be used by some emitters.)"""
 | 
					 | 
				
			||||||
 
 | 
					 
 | 
				
			||||||
    """The form class that should be used for validation, or None to use model form validation."""   
 | 
					    """The form class that should be used for validation, or None to use model form validation."""   
 | 
				
			||||||
    form = None
 | 
					    form = None
 | 
				
			||||||
| 
						 | 
					@ -148,15 +158,18 @@ class ModelFormValidatorMixin(FormValidatorMixin):
 | 
				
			||||||
        If the form class attribute has been explicitly set then use that class to create a Form,
 | 
					        If the form class attribute has been explicitly set then use that class to create a Form,
 | 
				
			||||||
        otherwise if model is set use that class to create a ModelForm, otherwise return None."""
 | 
					        otherwise if model is set use that class to create a ModelForm, otherwise return None."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if self.form:
 | 
					        form_cls = getattr(self.view, 'form', None)
 | 
				
			||||||
            # Use explict Form
 | 
					        model_cls = getattr(self.view, 'model', None)
 | 
				
			||||||
            return super(ModelFormValidatorMixin, self).get_bound_form(content)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        elif self.model:
 | 
					        if form_cls:
 | 
				
			||||||
 | 
					            # Use explict Form
 | 
				
			||||||
 | 
					            return super(ModelFormValidator, self).get_bound_form(content)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        elif model_cls:
 | 
				
			||||||
            # Fall back to ModelForm which we create on the fly
 | 
					            # Fall back to ModelForm which we create on the fly
 | 
				
			||||||
            class OnTheFlyModelForm(forms.ModelForm):
 | 
					            class OnTheFlyModelForm(forms.ModelForm):
 | 
				
			||||||
                class Meta:
 | 
					                class Meta:
 | 
				
			||||||
                    model = self.model
 | 
					                    model = model_cls
 | 
				
			||||||
                    #fields = tuple(self._model_fields_set)
 | 
					                    #fields = tuple(self._model_fields_set)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            # Instantiate the ModelForm as appropriate
 | 
					            # Instantiate the ModelForm as appropriate
 | 
				
			||||||
| 
						 | 
					@ -176,24 +189,32 @@ class ModelFormValidatorMixin(FormValidatorMixin):
 | 
				
			||||||
    @property
 | 
					    @property
 | 
				
			||||||
    def _model_fields_set(self):
 | 
					    def _model_fields_set(self):
 | 
				
			||||||
        """Return a set containing the names of validated fields on the model."""
 | 
					        """Return a set containing the names of validated fields on the model."""
 | 
				
			||||||
        model_fields = set(field.name for field in self.model._meta.fields)
 | 
					        model = getattr(self.view, 'model', None)
 | 
				
			||||||
 | 
					        fields = getattr(self.view, 'fields', self.fields)
 | 
				
			||||||
 | 
					        exclude_fields = getattr(self.view, 'exclude_fields', self.exclude_fields)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if self.fields:
 | 
					        model_fields = set(field.name for field in model._meta.fields)
 | 
				
			||||||
            return model_fields & set(as_tuple(self.fields))
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return model_fields - set(as_tuple(self.exclude_fields))
 | 
					        if fields:
 | 
				
			||||||
 | 
					            return model_fields & set(as_tuple(fields))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return model_fields - set(as_tuple(exclude_fields))
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    @property
 | 
					    @property
 | 
				
			||||||
    def _property_fields_set(self):
 | 
					    def _property_fields_set(self):
 | 
				
			||||||
        """Returns a set containing the names of validated properties on the model."""
 | 
					        """Returns a set containing the names of validated properties on the model."""
 | 
				
			||||||
        property_fields = set(attr for attr in dir(self.model) if
 | 
					        model = getattr(self.view, 'model', None)
 | 
				
			||||||
                              isinstance(getattr(self.model, attr, None), property)
 | 
					        fields = getattr(self.view, 'fields', self.fields)
 | 
				
			||||||
 | 
					        exclude_fields = getattr(self.view, 'exclude_fields', self.exclude_fields)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        property_fields = set(attr for attr in dir(model) if
 | 
				
			||||||
 | 
					                              isinstance(getattr(model, attr, None), property)
 | 
				
			||||||
                              and not attr.startswith('_'))
 | 
					                              and not attr.startswith('_'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if self.fields:
 | 
					        if fields:
 | 
				
			||||||
            return property_fields & set(as_tuple(self.fields))
 | 
					            return property_fields & set(as_tuple(fields))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return property_fields - set(as_tuple(self.exclude_fields))
 | 
					        return property_fields - set(as_tuple(exclude_fields))
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user