diff --git a/djangorestframework/mixins.py b/djangorestframework/mixins.py index e01de3fc4..64e2a2188 100644 --- a/djangorestframework/mixins.py +++ b/djangorestframework/mixins.py @@ -729,3 +729,18 @@ class PaginatorMixin(object): serialized_page_info['results'] = serialized_object_list return serialized_page_info + + +############## RequestFormMixin #################### + +class RequestFormMixin(object): + """ + If you add this mixin to a form class, the instantiated form will have the `set_request`-method + which will be set by any resource using standard form validation, allowing you to use `self.request` + in any form clean`-methods. + """ + + request = None + + def set_request(self, request): + self.request = request diff --git a/djangorestframework/resources.py b/djangorestframework/resources.py index 68b285b91..eaeedc3c1 100644 --- a/djangorestframework/resources.py +++ b/djangorestframework/resources.py @@ -205,6 +205,7 @@ class FormResource(Resource): """ Given some content return a Django form bound to that content. If form validation is turned off (:attr:`form` class attribute is :const:`None`) then returns :const:`None`. + If the form class uses the `RequestFormMixin` mixin, the request will be set on the form """ form = self.get_form_class(method) @@ -212,9 +213,15 @@ class FormResource(Resource): return None if data is not None or files is not None: - return form(data, files) + form_instance = form(data, files) + else: + form_instance = form() - return form() + try: + form_instance.set_request(self.view.request) + except AttributeError: + pass + return form_instance diff --git a/djangorestframework/tests/mixins.py b/djangorestframework/tests/mixins.py index 2913160d4..9a56ddaba 100644 --- a/djangorestframework/tests/mixins.py +++ b/djangorestframework/tests/mixins.py @@ -1,12 +1,15 @@ """Tests for the mixin module""" +from django import forms +from django.core.exceptions import ValidationError +from django.conf.urls.defaults import patterns, url from django.test import TestCase from django.utils import simplejson as json from djangorestframework import status from djangorestframework.compat import RequestFactory from django.contrib.auth.models import Group, User -from djangorestframework.mixins import CreateModelMixin, PaginatorMixin +from djangorestframework.mixins import CreateModelMixin, PaginatorMixin, RequestFormMixin from djangorestframework.resources import ModelResource -from djangorestframework.response import Response +from djangorestframework.response import Response, ErrorResponse from djangorestframework.tests.models import CustomUser from djangorestframework.tests.testcases import TestModelsTestCase from djangorestframework.views import View @@ -248,3 +251,33 @@ class TestPagination(TestCase): self.assertTrue('foo=bar' in content['next']) self.assertTrue('another=something' in content['next']) self.assertTrue('page=2' in content['next']) + + +class RequestFormMockView(View): + """This is a request form mock view""" + + class MockForm(forms.Form, RequestFormMixin): + foo = forms.BooleanField(required=False) + bar = forms.IntegerField(help_text='Must be an integer.') + baz = forms.CharField(max_length=32) + + def clean(self): + if not hasattr(self, "request"): + raise ValidationError("Request Not Set") + return super(MockForm, self).clean() + + form = MockForm + + +urlpatterns = patterns('', + url(r'^requestformmock/$', RequestFormMockView.as_view()), +) + +class TestRequestFormMixin(TestCase): + """Tests the RequestFormMixin""" + urls = 'djangorestframework.tests.mixins' + + def test_options_method_simple_view(self): + response = self.client.options('/requestformmock/') + self.assertEqual(response.status_code, status.OK) +