diff options
| author | tom christie tom@tomchristie.com | 2011-01-26 21:06:40 +0000 |
|---|---|---|
| committer | tom christie tom@tomchristie.com | 2011-01-26 21:06:40 +0000 |
| commit | 9adb965126366bfe4b364357f565baabd819c982 (patch) | |
| tree | f924a64d0c4c8ff023f92fd9ef035060c825f647 /flywheel/emitters.py | |
| parent | 6807cf014cb0fde611f63c64bc352038206176cc (diff) | |
| parent | 8b89d7416cf4e2396deac4ba41c23cdcdc8b9704 (diff) | |
| download | django-rest-framework-9adb965126366bfe4b364357f565baabd819c982.tar.bz2 | |
content type tunneling
Diffstat (limited to 'flywheel/emitters.py')
| -rw-r--r-- | flywheel/emitters.py | 69 |
1 files changed, 57 insertions, 12 deletions
diff --git a/flywheel/emitters.py b/flywheel/emitters.py index 33375200..408a65eb 100644 --- a/flywheel/emitters.py +++ b/flywheel/emitters.py @@ -1,8 +1,10 @@ from django.template import RequestContext, loader +from django import forms from flywheel.response import NoContent from utils import dict2xml +import string try: import json except ImportError: @@ -33,25 +35,31 @@ class TemplateEmitter(BaseEmitter): return self.template.render(Context(output)) -from django import forms -class JSONForm(forms.Form): - _contenttype = forms.CharField(max_length=256, initial='application/json', label='Content Type') - _content = forms.CharField(label='Content', widget=forms.Textarea) + class DocumentingTemplateEmitter(BaseEmitter): """Emitter used to self-document the API""" template = None - def emit(self, output=NoContent): - resource = self.resource + def _get_content(self, resource, output): + """Get the content as if it had been emitted by a non-documenting emitter. + + (Typically this will be the content as it would have been if the Resource had been + requested with an 'Accept: */*' header, although with verbose style formatting if appropriate.)""" - # Find the first valid emitter and emit the content. (Don't another documenting emitter.) + # Find the first valid emitter and emit the content. (Don't use another documenting emitter.) emitters = [emitter for emitter in resource.emitters if not isinstance(emitter, DocumentingTemplateEmitter)] if not emitters: - content = 'No emitters were found' - else: - content = emitters[0](resource).emit(output, verbose=True) - + return '[No emitters were found]' + + content = emitters[0](resource).emit(output, verbose=True) + if not all(char in string.printable for char in content): + return '[%d bytes of binary content]' + + return content + + + def _get_form_instance(self, resource): # Get the form instance if we have one bound to the input form_instance = resource.form_instance @@ -70,8 +78,45 @@ class DocumentingTemplateEmitter(BaseEmitter): except: pass + # 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: - form_instance = JSONForm() + form_instance = self._get_generic_content_form(resource) + + return form_instance + + + def _get_generic_content_form(self, resource): + """Returns a form that allows for arbitrary content types to be tunneled via standard HTML forms + (Which are typically application/x-www-form-urlencoded)""" + + # NB. http://jacobian.org/writing/dynamic-form-generation/ + class GenericContentForm(forms.Form): + def __init__(self, resource): + """We don't know the names of the fields we want to set until the point the form is instantiated, + as they are determined by the Resource the form is being created against. + Add the fields dynamically.""" + super(GenericContentForm, self).__init__() + + contenttype_choices = [(media_type, media_type) for media_type in resource.parsed_media_types] + initial_contenttype = resource.default_parser.media_type + + self.fields[resource.CONTENTTYPE_PARAM] = forms.ChoiceField(label='Content Type', + choices=contenttype_choices, + initial=initial_contenttype) + self.fields[resource.CONTENT_PARAM] = forms.CharField(label='Content', + widget=forms.Textarea) + + # If either of these reserved parameters are turned off then content tunneling is not possible + if self.resource.CONTENTTYPE_PARAM is None or self.resource.CONTENT_PARAM is None: + return None + + # Okey doke, let's do it + return GenericContentForm(resource) + + + def emit(self, output=NoContent): + content = self._get_content(self.resource, output) + form_instance = self._get_form_instance(self.resource) template = loader.get_template(self.template) context = RequestContext(self.resource.request, { |
