mirror of
				https://github.com/encode/django-rest-framework.git
				synced 2025-11-01 00:17:40 +03:00 
			
		
		
		
	Sample example working
This commit is contained in:
		
							parent
							
								
									95ac2396d6
								
							
						
					
					
						commit
						42825e44e1
					
				|  | @ -18,7 +18,7 @@ class TemplatedEmitter(BaseEmitter): | ||||||
|     template = None |     template = None | ||||||
| 
 | 
 | ||||||
|     def emit(self, output): |     def emit(self, output): | ||||||
|         content = json.dumps(output, indent=4) |         content = json.dumps(output, indent=4, sort_keys=True) | ||||||
|         template = loader.get_template(self.template) |         template = loader.get_template(self.template) | ||||||
|         context = RequestContext(self.request, { |         context = RequestContext(self.request, { | ||||||
|             'content': content, |             'content': content, | ||||||
|  |  | ||||||
|  | @ -137,15 +137,20 @@ class Resource(object): | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|     def determine_form(self, data=None): |     def determine_form(self, input_data=None, return_data=None): | ||||||
|         """Optionally return a Django Form instance, which may be used for validation |         """Optionally return a Django Form instance, which may be used for validation | ||||||
|         and/or rendered by an HTML/XHTML emitter. |         and/or rendered by an HTML/XHTML emitter. | ||||||
|          |          | ||||||
|         The data argument will be non Null if the form is required to be bound to some deserialized |         The input_data or return_data arguments can be used to bind the form either to the deserialized input, | ||||||
|         input data, or Null if the form is required to be unbound.  |         or to a return object.  | ||||||
|         """ |         """ | ||||||
|         if self.form: |         if self.form: | ||||||
|             return self.form(data) |             if input_data: | ||||||
|  |                 return self.form(input_data) | ||||||
|  |             elif return_data: | ||||||
|  |                 return self.form(return_data) | ||||||
|  |             else: | ||||||
|  |                 return self.form() | ||||||
|         return None |         return None | ||||||
|    |    | ||||||
|    |    | ||||||
|  | @ -259,12 +264,13 @@ class Resource(object): | ||||||
|             if method in ('PUT', 'POST'): |             if method in ('PUT', 'POST'): | ||||||
|                 parser = self.determine_parser(request) |                 parser = self.determine_parser(request) | ||||||
|                 data = parser(self, request).parse(request.raw_post_data) |                 data = parser(self, request).parse(request.raw_post_data) | ||||||
|                 form = self.determine_form(data) |                 form = self.determine_form(input_data=data) | ||||||
|                 data = self.cleanup_request(data, form) |                 data = self.cleanup_request(data, form) | ||||||
|                 (status, ret, headers) = func(data, request.META, *args, **kwargs) |                 (status, ret, headers) = func(data, request.META, *args, **kwargs) | ||||||
| 
 | 
 | ||||||
|             else: |             else: | ||||||
|                 (status, ret, headers) = func(request.META, *args, **kwargs) |                 (status, ret, headers) = func(request.META, *args, **kwargs) | ||||||
|  |                 form = self.determine_form(return_data=ret) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|         except ResourceException, exc: |         except ResourceException, exc: | ||||||
|  | @ -274,7 +280,7 @@ class Resource(object): | ||||||
|         if emitter is None: |         if emitter is None: | ||||||
|             mimetype, emitter = self.emitters[0] |             mimetype, emitter = self.emitters[0] | ||||||
|          |          | ||||||
|         # Use a form unbound to any data if one has not yet been created |         # Create an unbound form if one has not yet been created | ||||||
|         if form is None: |         if form is None: | ||||||
|             form = self.determine_form() |             form = self.determine_form() | ||||||
|          |          | ||||||
|  | @ -284,7 +290,6 @@ class Resource(object): | ||||||
|         # Serialize the response content |         # Serialize the response content | ||||||
|         ret = self.cleanup_response(ret) |         ret = self.cleanup_response(ret) | ||||||
|         content = emitter(self, request, status, headers, form).emit(ret) |         content = emitter(self, request, status, headers, form).emit(ret) | ||||||
|         print content |  | ||||||
| 
 | 
 | ||||||
|         # Build the HTTP Response |         # Build the HTTP Response | ||||||
|         resp = HttpResponse(content, mimetype=mimetype, status=status) |         resp = HttpResponse(content, mimetype=mimetype, status=status) | ||||||
|  | @ -308,7 +313,7 @@ class ModelResource(Resource): | ||||||
|     fields = None |     fields = None | ||||||
|     form_fields = None |     form_fields = None | ||||||
| 
 | 
 | ||||||
|     def determine_form(self, data=None): |     def determine_form(self, input_data=None, return_data=None): | ||||||
|         """Return a form that may be used in validation and/or rendering an html emitter""" |         """Return a form that may be used in validation and/or rendering an html emitter""" | ||||||
|         if self.form: |         if self.form: | ||||||
|             return self.form |             return self.form | ||||||
|  | @ -317,12 +322,14 @@ class ModelResource(Resource): | ||||||
|             class NewModelForm(ModelForm): |             class NewModelForm(ModelForm): | ||||||
|                 class Meta: |                 class Meta: | ||||||
|                     model = self.model |                     model = self.model | ||||||
|                     fields = self.form_fields if self.form_fields else self.fields |                     fields = self.form_fields if self.form_fields else None #self.fields | ||||||
|                      |                      | ||||||
|             if data is None: |             if input_data: | ||||||
|                 return NewModelForm() |                 return NewModelForm(input_data) | ||||||
|  |             elif return_data: | ||||||
|  |                 return NewModelForm(instance=return_data) | ||||||
|             else: |             else: | ||||||
|                 return NewModelForm(data) |                 return NewModelForm() | ||||||
|          |          | ||||||
|         else: |         else: | ||||||
|             return None |             return None | ||||||
|  | @ -359,6 +366,12 @@ class ModelResource(Resource): | ||||||
|                 ret = _list(thing) |                 ret = _list(thing) | ||||||
|             elif isinstance(thing, dict): |             elif isinstance(thing, dict): | ||||||
|                 ret = _dict(thing) |                 ret = _dict(thing) | ||||||
|  |             elif isinstance(thing, int): | ||||||
|  |                 ret = thing | ||||||
|  |             elif isinstance(thing, bool): | ||||||
|  |                 ret = thing | ||||||
|  |             elif isinstance(thing, type(None)): | ||||||
|  |                 ret = thing | ||||||
|             elif isinstance(thing, decimal.Decimal): |             elif isinstance(thing, decimal.Decimal): | ||||||
|                 ret = str(thing) |                 ret = str(thing) | ||||||
|             elif isinstance(thing, Model): |             elif isinstance(thing, Model): | ||||||
|  | @ -417,7 +430,7 @@ class ModelResource(Resource): | ||||||
|             ret = { } |             ret = { } | ||||||
|             #handler = self.in_typemapper(type(data), self.anonymous)  # TRC |             #handler = self.in_typemapper(type(data), self.anonymous)  # TRC | ||||||
|             handler = None                                             # TRC |             handler = None                                             # TRC | ||||||
|             get_absolute_uri = False |             get_absolute_url = False | ||||||
|              |              | ||||||
|             if handler or fields: |             if handler or fields: | ||||||
|                 v = lambda f: getattr(data, f.attname) |                 v = lambda f: getattr(data, f.attname) | ||||||
|  | @ -445,11 +458,12 @@ class ModelResource(Resource): | ||||||
|                                 if exclude.match(field): |                                 if exclude.match(field): | ||||||
|                                     get_fields.discard(field) |                                     get_fields.discard(field) | ||||||
|                      |                      | ||||||
|  |                     get_absolute_url = True | ||||||
|  | 
 | ||||||
|                 else: |                 else: | ||||||
|                     get_fields = set(fields) |                     get_fields = set(fields) | ||||||
| 
 |                     if 'absolute_url' in get_fields:   # MOVED (TRC) | ||||||
|                 if 'absolute_uri' in get_fields:   # MOVED (TRC) |                         get_absolute_url = True | ||||||
|                     get_absolute_uri = True |  | ||||||
| 
 | 
 | ||||||
|                 met_fields = _method_fields(handler, get_fields)  # TRC |                 met_fields = _method_fields(handler, get_fields)  # TRC | ||||||
| 
 | 
 | ||||||
|  | @ -508,14 +522,37 @@ class ModelResource(Resource): | ||||||
|                             #    ret[maybe_field] = _any(handler_f(data)) |                             #    ret[maybe_field] = _any(handler_f(data)) | ||||||
| 
 | 
 | ||||||
|             else: |             else: | ||||||
|  |                 # Add absolute_url if it exists | ||||||
|  |                 get_absolute_url = True | ||||||
|  |                  | ||||||
|  |                 # Add all the fields | ||||||
|                 for f in data._meta.fields: |                 for f in data._meta.fields: | ||||||
|  |                     if f.attname != 'id': | ||||||
|                         ret[f.attname] = _any(getattr(data, f.attname)) |                         ret[f.attname] = _any(getattr(data, f.attname)) | ||||||
|                  |                  | ||||||
|                 fields = dir(data.__class__) + ret.keys() |                 # Add all the propertiess | ||||||
|                 add_ons = [k for k in dir(data) if k not in fields] |                 klass = data.__class__ | ||||||
|  |                 for attr in dir(klass): | ||||||
|  |                     if not attr.startswith('_') and not attr in ('pk','id') and isinstance(getattr(klass, attr, None), property): | ||||||
|  |                         #if attr.endswith('_url') or attr.endswith('_uri'): | ||||||
|  |                         #    ret[attr] = self.make_absolute(_any(getattr(data, attr))) | ||||||
|  |                         #else: | ||||||
|  |                         ret[attr] = _any(getattr(data, attr)) | ||||||
|  |                 #fields = dir(data.__class__) + ret.keys() | ||||||
|  |                 #add_ons = [k for k in dir(data) if k not in fields and not k.startswith('_')] | ||||||
|  |                 #print add_ons | ||||||
|  |                 ###print dir(data.__class__) | ||||||
|  |                 #from django.db.models import Model | ||||||
|  |                 #model_fields = dir(Model) | ||||||
| 
 | 
 | ||||||
|                 for k in add_ons: |                 #for attr in dir(data): | ||||||
|                     ret[k] = _any(getattr(data, k)) |                 ##    #if attr.startswith('_'): | ||||||
|  |                 ##    #    continue | ||||||
|  |                 #    if (attr in fields) and not (attr in model_fields) and not attr.startswith('_'): | ||||||
|  |                 #        print attr, type(getattr(data, attr, None)), attr in fields, attr in model_fields | ||||||
|  |                  | ||||||
|  |                 #for k in add_ons: | ||||||
|  |                 #    ret[k] = _any(getattr(data, k)) | ||||||
|              |              | ||||||
|             # TRC |             # TRC | ||||||
|             # resouce uri |             # resouce uri | ||||||
|  | @ -532,10 +569,14 @@ class ModelResource(Resource): | ||||||
|             #    except: pass |             #    except: pass | ||||||
|              |              | ||||||
|             # absolute uri |             # absolute uri | ||||||
|             if hasattr(data, 'get_absolute_url') and get_absolute_uri: |             if hasattr(data, 'get_absolute_url') and get_absolute_url: | ||||||
|                 try: ret['absolute_uri'] = self.make_absolute(data.get_absolute_url()) |                 try: ret['absolute_url'] = self.make_absolute(data.get_absolute_url()) | ||||||
|                 except: pass |                 except: pass | ||||||
|              |              | ||||||
|  |             for key, val in ret.items(): | ||||||
|  |                 if key.endswith('_url') or key.endswith('_uri'): | ||||||
|  |                     ret[key] = self.make_absolute(val) | ||||||
|  | 
 | ||||||
|             return ret |             return ret | ||||||
|          |          | ||||||
|         def _qs(data, fields=()): |         def _qs(data, fields=()): | ||||||
|  | @ -560,8 +601,9 @@ class ModelResource(Resource): | ||||||
|         return _any(data, self.fields) |         return _any(data, self.fields) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|     def create(self, data, headers={}): |     def create(self, data, headers={}, *args, **kwargs): | ||||||
|         instance = self.model(**data) |         all_kw_args = dict(data.items() + kwargs.items()) | ||||||
|  |         instance = self.model(**all_kw_args) | ||||||
|         instance.save() |         instance.save() | ||||||
|         headers = {} |         headers = {} | ||||||
|         if hasattr(instance, 'get_absolute_url'): |         if hasattr(instance, 'get_absolute_url'): | ||||||
|  | @ -569,13 +611,22 @@ class ModelResource(Resource): | ||||||
|         return (201, instance, headers) |         return (201, instance, headers) | ||||||
| 
 | 
 | ||||||
|     def read(self, headers={}, *args, **kwargs): |     def read(self, headers={}, *args, **kwargs): | ||||||
|  |         try: | ||||||
|             instance = self.model.objects.get(**kwargs) |             instance = self.model.objects.get(**kwargs) | ||||||
|  |         except self.model.DoesNotExist: | ||||||
|  |             return (404, '', {}) | ||||||
|  | 
 | ||||||
|         return (200, instance, {}) |         return (200, instance, {}) | ||||||
| 
 | 
 | ||||||
|     def update(self, data, headers={}, *args, **kwargs): |     def update(self, data, headers={}, *args, **kwargs): | ||||||
|  |         try: | ||||||
|             instance = self.model.objects.get(**kwargs)     |             instance = self.model.objects.get(**kwargs)     | ||||||
|             for (key, val) in data.items(): |             for (key, val) in data.items(): | ||||||
|                 setattr(instance, key, val) |                 setattr(instance, key, val) | ||||||
|  |         except self.model.DoesNotExist: | ||||||
|  |             instance = self.model(**data) | ||||||
|  |             instance.save() | ||||||
|  | 
 | ||||||
|         instance.save() |         instance.save() | ||||||
|         return (200, instance, {}) |         return (200, instance, {}) | ||||||
| 
 | 
 | ||||||
|  | @ -583,3 +634,14 @@ class ModelResource(Resource): | ||||||
|         instance = self.model.objects.get(**kwargs) |         instance = self.model.objects.get(**kwargs) | ||||||
|         instance.delete() |         instance.delete() | ||||||
|         return (204, '', {}) |         return (204, '', {}) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class QueryModelResource(ModelResource): | ||||||
|  |     allowed_methods = ('read',) | ||||||
|  | 
 | ||||||
|  |     def determine_form(self, input_data=None, return_data=None): | ||||||
|  |         return None | ||||||
|  | 
 | ||||||
|  |     def read(self, headers={}, *args, **kwargs): | ||||||
|  |         query = self.model.objects.all() | ||||||
|  |         return (200, query, {}) | ||||||
|  |  | ||||||
|  | @ -11,10 +11,10 @@ | ||||||
|   <body> |   <body> | ||||||
|     <h1>{{ resource_name }}</h1> |     <h1>{{ resource_name }}</h1> | ||||||
|     <p>{{ resource_doc }}</p> |     <p>{{ resource_doc }}</p> | ||||||
|     <pre>{% autoescape off %}<b>{{ status }} {{ reason }}</b> |     <pre><b>{{ status }} {{ reason }}</b>{% autoescape off %} | ||||||
| {% for key, val in headers.items %}<b>{{ key }}:</b> {{ val|urlize_quoted_links }} | {% for key, val in headers.items %}<b>{{ key }}:</b> {{ val|urlize_quoted_links }} | ||||||
| {% endfor %} | {% endfor %} | ||||||
| {{ content|urlize_quoted_links }}{% endautoescape %}    </pre> | {{ content|urlize_quoted_links }}    </pre>{% endautoescape %} | ||||||
| 
 | 
 | ||||||
| {% if 'read' in resource.allowed_operations %} | {% if 'read' in resource.allowed_operations %} | ||||||
| 	<div class='action'> | 	<div class='action'> | ||||||
|  |  | ||||||
|  | @ -33,7 +33,7 @@ html_gunk_re = re.compile(r'(?:<br clear="all">|<i><\/i>|<b><\/b>|<em><\/em>|<st | ||||||
| hard_coded_bullets_re = re.compile(r'((?:<p>(?:%s).*?[a-zA-Z].*?</p>\s*)+)' % '|'.join([re.escape(x) for x in DOTS]), re.DOTALL) | hard_coded_bullets_re = re.compile(r'((?:<p>(?:%s).*?[a-zA-Z].*?</p>\s*)+)' % '|'.join([re.escape(x) for x in DOTS]), re.DOTALL) | ||||||
| trailing_empty_content_re = re.compile(r'(?:<p>(?: |\s|<br \/>)*?</p>\s*)+\Z') | trailing_empty_content_re = re.compile(r'(?:<p>(?: |\s|<br \/>)*?</p>\s*)+\Z') | ||||||
| 
 | 
 | ||||||
| def urlize_quoted_links(text, trim_url_limit=None, nofollow=False, autoescape=False): | def urlize_quoted_links(text, trim_url_limit=None, nofollow=False, autoescape=True): | ||||||
|     """ |     """ | ||||||
|     Converts any URLs in text into clickable links. |     Converts any URLs in text into clickable links. | ||||||
| 
 | 
 | ||||||
|  | @ -90,6 +90,10 @@ def urlize_quoted_links(text, trim_url_limit=None, nofollow=False, autoescape=Fa | ||||||
|             words[i] = escape(word) |             words[i] = escape(word) | ||||||
|     return u''.join(words) |     return u''.join(words) | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|  | #urlize_quoted_links.needs_autoescape = True | ||||||
|  | urlize_quoted_links.is_safe = True | ||||||
|  | 
 | ||||||
| # Register urlize_quoted_links as a custom filter | # Register urlize_quoted_links as a custom filter | ||||||
| # http://docs.djangoproject.com/en/dev/howto/custom-template-tags/ | # http://docs.djangoproject.com/en/dev/howto/custom-template-tags/ | ||||||
| register = template.Library() | register = template.Library() | ||||||
|  |  | ||||||
										
											Binary file not shown.
										
									
								
							|  | @ -1,63 +1,90 @@ | ||||||
| from django.db import models | from django.db import models | ||||||
| from django.template.defaultfilters import slugify | from django.template.defaultfilters import slugify | ||||||
| from datetime import datetime |  | ||||||
| import uuid | import uuid | ||||||
| 
 | 
 | ||||||
| def uuid_str(): | def uuid_str(): | ||||||
|     return str(uuid.uuid1()) |     return str(uuid.uuid1()) | ||||||
| 
 | 
 | ||||||
| class ExampleModel(models.Model): | #class ExampleModel(models.Model): | ||||||
|     num = models.IntegerField(default=2, choices=((1,'one'), (2, 'two'))) | #    num = models.IntegerField(default=2, choices=((1,'one'), (2, 'two'))) | ||||||
|     hidden_num = models.IntegerField(verbose_name='Something', help_text='HELP') | #    hidden_num = models.IntegerField(verbose_name='Something', help_text='HELP') | ||||||
|     text = models.TextField(blank=False) | #    text = models.TextField(blank=False) | ||||||
|     another = models.CharField(max_length=10) | #    another = models.CharField(max_length=10) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class ExampleContainer(models.Model): | #class ExampleContainer(models.Model): | ||||||
|     """Container.  Has a key, a name, and some internal data, and contains a set of items.""" | #    """Container.  Has a key, a name, and some internal data, and contains a set of items.""" | ||||||
|     key = models.CharField(primary_key=True, default=uuid_str, max_length=36, editable=False) | #    key = models.CharField(primary_key=True, default=uuid_str, max_length=36, editable=False) | ||||||
|     name = models.CharField(max_length=256) | #    name = models.CharField(max_length=256) | ||||||
|     internal = models.IntegerField(default=0) | #    internal = models.IntegerField(default=0) | ||||||
| 
 | 
 | ||||||
|     @models.permalink | #    @models.permalink | ||||||
|     def get_absolute_url(self): | #    def get_absolute_url(self): | ||||||
|         return ('testapp.views.ContainerInstance', [self.key]) | #        return ('testapp.views.ContainerInstance', [self.key]) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class ExampleItem(models.Model): | #class ExampleItem(models.Model): | ||||||
|     """Item.  Belongs to a container and has an index number and a note. | #    """Item.  Belongs to a container and has an index number and a note. | ||||||
|     Items are uniquely identified by their container and index number.""" | #    Items are uniquely identified by their container and index number.""" | ||||||
|     container = models.ForeignKey(ExampleContainer, related_name='items') | #    container = models.ForeignKey(ExampleContainer, related_name='items') | ||||||
|     index = models.IntegerField() | #    index = models.IntegerField() | ||||||
|     note = models.CharField(max_length=1024) | #    note = models.CharField(max_length=1024) | ||||||
|     unique_together = (container, index) | #    unique_together = (container, index) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | RATING_CHOICES = ((0, 'Awful'), | ||||||
|  |                   (1, 'Poor'), | ||||||
|  |                   (2, 'OK'), | ||||||
|  |                   (3, 'Good'), | ||||||
|  |                   (4, 'Excellent')) | ||||||
|  | 
 | ||||||
| class BlogPost(models.Model): | class BlogPost(models.Model): | ||||||
|     slug = models.SlugField(editable=False, primary_key=True, default='blah') |     key = models.CharField(primary_key=True, max_length=64, default=uuid_str, editable=False) | ||||||
|     title = models.CharField(max_length=128) |     title = models.CharField(max_length=128, help_text='The article title (Required)') | ||||||
|     content = models.TextField() |     content = models.TextField(help_text='The article body (Required)') | ||||||
|     when = models.DateTimeField(editable=False) |     created = models.DateTimeField(auto_now_add=True) | ||||||
|  |     slug = models.SlugField(editable=False, default='') | ||||||
|  | 
 | ||||||
|  |     class Meta: | ||||||
|  |         ordering = ('created',) | ||||||
| 
 | 
 | ||||||
|     @models.permalink |     @models.permalink | ||||||
|     def get_absolute_url(self): |     def get_absolute_url(self): | ||||||
|         return ('testapp.views.BlogPostInstance', (self.slug,)) |         return ('testapp.views.BlogPostInstance', (self.key,)) | ||||||
|  | 
 | ||||||
|  |     @property | ||||||
|  |     @models.permalink | ||||||
|  |     def comments_url(self): | ||||||
|  |         """Link to a resource which lists all comments for this blog post.""" | ||||||
|  |         return ('testapp.views.CommentList', (self.key,)) | ||||||
|  | 
 | ||||||
|  |     @property | ||||||
|  |     @models.permalink | ||||||
|  |     def comment_url(self): | ||||||
|  |         """Link to a resource which can create a comment for this blog post.""" | ||||||
|  |         return ('testapp.views.CommentCreator', (self.key,)) | ||||||
|  | 
 | ||||||
|  |     def __unicode__(self): | ||||||
|  |         return self.title | ||||||
| 
 | 
 | ||||||
|     def save(self, *args, **kwargs): |     def save(self, *args, **kwargs): | ||||||
|         self.slug = slugify(self.title) |         self.slug = slugify(self.title) | ||||||
|         self.when = datetime.now() |  | ||||||
|         super(self.__class__, self).save(*args, **kwargs) |         super(self.__class__, self).save(*args, **kwargs) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class Comment(models.Model): | class Comment(models.Model): | ||||||
|     blogpost = models.ForeignKey(BlogPost, related_name='comments') |     blogpost = models.ForeignKey(BlogPost, editable=False, related_name='comments') | ||||||
|     name = models.CharField(max_length=128) |     username = models.CharField(max_length=128, help_text='Please enter a username (Required)') | ||||||
|     content = models.TextField() |     comment = models.TextField(help_text='Enter your comment here (Required)') | ||||||
|     when = models.DateTimeField(auto_now_add=True) |     rating = models.IntegerField(blank=True, null=True, choices=RATING_CHOICES, help_text='Please rate the blog post (Optional)') | ||||||
|  |     created = models.DateTimeField(auto_now_add=True) | ||||||
| 
 | 
 | ||||||
|     @models.permalink |     @models.permalink | ||||||
|     def get_absolute_url(self): |     def get_absolute_url(self): | ||||||
|         return ('testapp.views.CommentInstance', (self.blogpost.slug, self.id)) |         return ('testapp.views.CommentInstance', (self.blogpost.key, self.id)) | ||||||
|  |      | ||||||
|  |     @property | ||||||
|  |     @models.permalink | ||||||
|  |     def blogpost_url(self): | ||||||
|  |         return ('testapp.views.BlogPostInstance', (self.blogpost.key,)) | ||||||
|          |          | ||||||
|     def save(self): |  | ||||||
|         self.index = self.blogpost.comments.count() |  | ||||||
|  | @ -1,8 +1,4 @@ | ||||||
| """ | """Test a range of REST API usage of the example application. | ||||||
| This file demonstrates two different styles of tests (one doctest and one |  | ||||||
| unittest). These will both pass when you run "manage.py test". |  | ||||||
| 
 |  | ||||||
| Replace these with more appropriate tests for your application. |  | ||||||
| """ | """ | ||||||
| 
 | 
 | ||||||
| from django.test import TestCase | from django.test import TestCase | ||||||
|  | @ -13,134 +9,154 @@ import json | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class AcceptHeaderTests(TestCase): | class AcceptHeaderTests(TestCase): | ||||||
|     def assert_accept_mimetype(self, mimetype, expect=None, expect_match=True): |     """Test correct behaviour of the Accept header as specified by RFC 2616: | ||||||
|         """ | 
 | ||||||
|         Assert that a request with given mimetype in the accept header, |     http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1""" | ||||||
|         gives a response with the appropriate content-type. | 
 | ||||||
|         """ |     def assert_accept_mimetype(self, mimetype, expect=None): | ||||||
|  |         """Assert that a request with given mimetype in the accept header, | ||||||
|  |         gives a response with the appropriate content-type.""" | ||||||
|         if expect is None: |         if expect is None: | ||||||
|             expect = mimetype |             expect = mimetype | ||||||
| 
 | 
 | ||||||
|         resp = self.client.get(reverse(views.ReadOnlyResource), HTTP_ACCEPT=mimetype) |         resp = self.client.get(reverse(views.RootResource), HTTP_ACCEPT=mimetype) | ||||||
| 
 | 
 | ||||||
|         if expect_match: |  | ||||||
|         self.assertEquals(resp['content-type'], expect) |         self.assertEquals(resp['content-type'], expect) | ||||||
|         else: |  | ||||||
|             self.assertNotEquals(resp['content-type'], expect) |  | ||||||
| 
 | 
 | ||||||
|     def test_accept_xml(self): |  | ||||||
|         self.assert_accept_mimetype('application/xml') |  | ||||||
| 
 | 
 | ||||||
|     def test_accept_json(self): |     def test_accept_json(self): | ||||||
|  |         """Ensure server responds with Content-Type of JSON when requested.""" | ||||||
|         self.assert_accept_mimetype('application/json') |         self.assert_accept_mimetype('application/json') | ||||||
| 
 | 
 | ||||||
|     def test_accept_xml_prefered_to_json(self): |     def test_accept_xml(self): | ||||||
|         self.assert_accept_mimetype('application/xml,q=0.9;application/json,q=0.1', expect='application/xml') |         """Ensure server responds with Content-Type of XML when requested.""" | ||||||
|  |         self.assert_accept_mimetype('application/xml') | ||||||
| 
 | 
 | ||||||
|     def test_accept_json_prefered_to_xml(self): |     def test_accept_json_when_prefered_to_xml(self): | ||||||
|  |         """Ensure server responds with Content-Type of JSON when it is the client's prefered choice.""" | ||||||
|         self.assert_accept_mimetype('application/json,q=0.9;application/xml,q=0.1', expect='application/json') |         self.assert_accept_mimetype('application/json,q=0.9;application/xml,q=0.1', expect='application/json') | ||||||
| 
 | 
 | ||||||
|     def test_dont_accept_invalid(self): |     def test_accept_xml_when_prefered_to_json(self): | ||||||
|         self.assert_accept_mimetype('application/invalid', expect_match=False) |         """Ensure server responds with Content-Type of XML when it is the client's prefered choice.""" | ||||||
|  |         self.assert_accept_mimetype('application/xml,q=0.9;application/json,q=0.1', expect='application/xml') | ||||||
|  | 
 | ||||||
|  |     def test_default_json_prefered(self): | ||||||
|  |         """Ensure server responds with JSON in preference to XML.""" | ||||||
|  |         self.assert_accept_mimetype('application/json;application/xml', expect='application/json') | ||||||
|  | 
 | ||||||
|  |     def test_accept_generic_subtype_format(self): | ||||||
|  |         """Ensure server responds with an appropriate type, when the subtype is left generic.""" | ||||||
|  |         self.assert_accept_mimetype('text/*', expect='text/html') | ||||||
|  | 
 | ||||||
|  |     def test_accept_generic_type_format(self): | ||||||
|  |         """Ensure server responds with an appropriate type, when the type and subtype are left generic.""" | ||||||
|  |         self.assert_accept_mimetype('*/*', expect='application/json') | ||||||
| 
 | 
 | ||||||
|     def test_invalid_accept_header_returns_406(self): |     def test_invalid_accept_header_returns_406(self): | ||||||
|         resp = self.client.get(reverse(views.ReadOnlyResource), HTTP_ACCEPT='invalid/invalid') |         """Ensure server returns a 406 (not acceptable) response if we set the Accept header to junk.""" | ||||||
|  |         resp = self.client.get(reverse(views.RootResource), HTTP_ACCEPT='invalid/invalid') | ||||||
|  |         self.assertNotEquals(resp['content-type'], 'invalid/invalid') | ||||||
|         self.assertEquals(resp.status_code, 406) |         self.assertEquals(resp.status_code, 406) | ||||||
|      |      | ||||||
|     def test_prefer_specific(self): |     def test_prefer_specific_over_generic(self):   # This test is broken right now | ||||||
|         self.fail("Test not implemented") |         """More specific accept types have precedence over less specific types.""" | ||||||
|  |         self.assert_accept_mimetype('application/xml;*/*', expect='application/xml') | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class AllowedMethodsTests(TestCase): | class AllowedMethodsTests(TestCase): | ||||||
|     def test_reading_read_only_allowed(self): |     """Basic tests to check that only allowed operations may be performed on a Resource""" | ||||||
|         resp = self.client.get(reverse(views.ReadOnlyResource)) | 
 | ||||||
|  |     def test_reading_a_read_only_resource_is_allowed(self): | ||||||
|  |         """GET requests on a read only resource should default to a 200 (OK) response""" | ||||||
|  |         resp = self.client.get(reverse(views.RootResource)) | ||||||
|         self.assertEquals(resp.status_code, 200) |         self.assertEquals(resp.status_code, 200) | ||||||
|          |          | ||||||
|     def test_writing_read_only_not_allowed(self): |     def test_writing_to_read_only_resource_is_not_allowed(self): | ||||||
|         resp = self.client.put(reverse(views.ReadOnlyResource), {}) |         """PUT requests on a read only resource should default to a 405 (method not allowed) response""" | ||||||
|  |         resp = self.client.put(reverse(views.RootResource), {}) | ||||||
|         self.assertEquals(resp.status_code, 405) |         self.assertEquals(resp.status_code, 405) | ||||||
| 
 | # | ||||||
|     def test_reading_write_only_not_allowed(self): | #    def test_reading_write_only_not_allowed(self): | ||||||
|         resp = self.client.get(reverse(views.WriteOnlyResource)) | #        resp = self.client.get(reverse(views.WriteOnlyResource)) | ||||||
|         self.assertEquals(resp.status_code, 405) | #        self.assertEquals(resp.status_code, 405) | ||||||
| 
 | # | ||||||
|     def test_writing_write_only_allowed(self): | #    def test_writing_write_only_allowed(self): | ||||||
|         resp = self.client.put(reverse(views.WriteOnlyResource), {}) | #        resp = self.client.put(reverse(views.WriteOnlyResource), {}) | ||||||
|         self.assertEquals(resp.status_code, 200) | #        self.assertEquals(resp.status_code, 200) | ||||||
| 
 | # | ||||||
| 
 | # | ||||||
| class EncodeDecodeTests(TestCase): | #class EncodeDecodeTests(TestCase): | ||||||
|     def setUp(self): | #    def setUp(self): | ||||||
|         super(self.__class__, self).setUp() | #        super(self.__class__, self).setUp() | ||||||
|         self.input = {'a': 1, 'b': 'example'} | #        self.input = {'a': 1, 'b': 'example'} | ||||||
| 
 | # | ||||||
|     def test_encode_form_decode_json(self): | #    def test_encode_form_decode_json(self): | ||||||
|         content = self.input | #        content = self.input | ||||||
|         resp = self.client.put(reverse(views.WriteOnlyResource), content) | #        resp = self.client.put(reverse(views.WriteOnlyResource), content) | ||||||
|         output = json.loads(resp.content) |  | ||||||
|         self.assertEquals(self.input, output) |  | ||||||
| 
 |  | ||||||
|     def test_encode_json_decode_json(self): |  | ||||||
|         content = json.dumps(self.input) |  | ||||||
|         resp = self.client.put(reverse(views.WriteOnlyResource), content, 'application/json') |  | ||||||
|         output = json.loads(resp.content) |  | ||||||
|         self.assertEquals(self.input, output) |  | ||||||
| 
 |  | ||||||
|     #def test_encode_xml_decode_json(self): |  | ||||||
|     #    content = dict2xml(self.input) |  | ||||||
|     #    resp = self.client.put(reverse(views.WriteOnlyResource), content, 'application/json', HTTP_ACCEPT='application/json') |  | ||||||
| #        output = json.loads(resp.content) | #        output = json.loads(resp.content) | ||||||
| #        self.assertEquals(self.input, output) | #        self.assertEquals(self.input, output) | ||||||
| 
 | # | ||||||
|     #def test_encode_form_decode_xml(self): | #    def test_encode_json_decode_json(self): | ||||||
|     #    content = self.input |  | ||||||
|     #    resp = self.client.put(reverse(views.WriteOnlyResource), content, HTTP_ACCEPT='application/xml') |  | ||||||
|     #    output = xml2dict(resp.content) |  | ||||||
|     #    self.assertEquals(self.input, output) |  | ||||||
| 
 |  | ||||||
|     #def test_encode_json_decode_xml(self): |  | ||||||
| #        content = json.dumps(self.input) | #        content = json.dumps(self.input) | ||||||
|     #    resp = self.client.put(reverse(views.WriteOnlyResource), content, 'application/json', HTTP_ACCEPT='application/xml') | #        resp = self.client.put(reverse(views.WriteOnlyResource), content, 'application/json') | ||||||
|     #    output = xml2dict(resp.content) | #        output = json.loads(resp.content) | ||||||
| #        self.assertEquals(self.input, output) | #        self.assertEquals(self.input, output) | ||||||
| 
 | # | ||||||
|     #def test_encode_xml_decode_xml(self): | #    #def test_encode_xml_decode_json(self): | ||||||
|     #    content = dict2xml(self.input) | #    #    content = dict2xml(self.input) | ||||||
|     #    resp = self.client.put(reverse(views.WriteOnlyResource), content, 'application/json', HTTP_ACCEPT='application/xml') | #    #    resp = self.client.put(reverse(views.WriteOnlyResource), content, 'application/json', HTTP_ACCEPT='application/json') | ||||||
|     #    output = xml2dict(resp.content) | #    #    output = json.loads(resp.content) | ||||||
|     #    self.assertEquals(self.input, output) | #    #    self.assertEquals(self.input, output) | ||||||
| 
 | # | ||||||
| class ModelTests(TestCase): | #    #def test_encode_form_decode_xml(self): | ||||||
|     def test_create_container(self): | #    #    content = self.input | ||||||
|         content = json.dumps({'name': 'example'}) | #    #    resp = self.client.put(reverse(views.WriteOnlyResource), content, HTTP_ACCEPT='application/xml') | ||||||
|         resp = self.client.post(reverse(views.ContainerFactory), content, 'application/json') | #    #    output = xml2dict(resp.content) | ||||||
|         output = json.loads(resp.content) | #    #    self.assertEquals(self.input, output) | ||||||
|         self.assertEquals(resp.status_code, 201) | # | ||||||
|         self.assertEquals(output['name'], 'example') | #    #def test_encode_json_decode_xml(self): | ||||||
|         self.assertEquals(set(output.keys()), set(('absolute_uri', 'name', 'key'))) | #    #    content = json.dumps(self.input) | ||||||
| 
 | #    #    resp = self.client.put(reverse(views.WriteOnlyResource), content, 'application/json', HTTP_ACCEPT='application/xml') | ||||||
| class CreatedModelTests(TestCase): | #    #    output = xml2dict(resp.content) | ||||||
|     def setUp(self): | #    #    self.assertEquals(self.input, output) | ||||||
|         content = json.dumps({'name': 'example'}) | # | ||||||
|         resp = self.client.post(reverse(views.ContainerFactory), content, 'application/json', HTTP_ACCEPT='application/json') | #    #def test_encode_xml_decode_xml(self): | ||||||
|         self.container = json.loads(resp.content) | #    #    content = dict2xml(self.input) | ||||||
| 
 | #    #    resp = self.client.put(reverse(views.WriteOnlyResource), content, 'application/json', HTTP_ACCEPT='application/xml') | ||||||
|     def test_read_container(self): | #    #    output = xml2dict(resp.content) | ||||||
|         resp = self.client.get(self.container["absolute_uri"]) | #    #    self.assertEquals(self.input, output) | ||||||
|         self.assertEquals(resp.status_code, 200) | # | ||||||
|         container = json.loads(resp.content) | #class ModelTests(TestCase): | ||||||
|         self.assertEquals(container, self.container) | #    def test_create_container(self): | ||||||
| 
 | #        content = json.dumps({'name': 'example'}) | ||||||
|     def test_delete_container(self): | #        resp = self.client.post(reverse(views.ContainerFactory), content, 'application/json') | ||||||
|         resp = self.client.delete(self.container["absolute_uri"]) | #        output = json.loads(resp.content) | ||||||
|         self.assertEquals(resp.status_code, 204) | #        self.assertEquals(resp.status_code, 201) | ||||||
|         self.assertEquals(resp.content, '') | #        self.assertEquals(output['name'], 'example') | ||||||
| 
 | #        self.assertEquals(set(output.keys()), set(('absolute_uri', 'name', 'key'))) | ||||||
|     def test_update_container(self): | # | ||||||
|         self.container['name'] = 'new' | #class CreatedModelTests(TestCase): | ||||||
|         content = json.dumps(self.container) | #    def setUp(self): | ||||||
|         resp = self.client.put(self.container["absolute_uri"], content, 'application/json') | #        content = json.dumps({'name': 'example'}) | ||||||
|         self.assertEquals(resp.status_code, 200) | #        resp = self.client.post(reverse(views.ContainerFactory), content, 'application/json', HTTP_ACCEPT='application/json') | ||||||
|         container = json.loads(resp.content) | #        self.container = json.loads(resp.content) | ||||||
|         self.assertEquals(container, self.container) | # | ||||||
|  | #    def test_read_container(self): | ||||||
|  | #        resp = self.client.get(self.container["absolute_uri"]) | ||||||
|  | #        self.assertEquals(resp.status_code, 200) | ||||||
|  | #        container = json.loads(resp.content) | ||||||
|  | #        self.assertEquals(container, self.container) | ||||||
|  | # | ||||||
|  | #    def test_delete_container(self): | ||||||
|  | #        resp = self.client.delete(self.container["absolute_uri"]) | ||||||
|  | #        self.assertEquals(resp.status_code, 204) | ||||||
|  | #        self.assertEquals(resp.content, '') | ||||||
|  | # | ||||||
|  | #    def test_update_container(self): | ||||||
|  | #        self.container['name'] = 'new' | ||||||
|  | #        content = json.dumps(self.container) | ||||||
|  | #        resp = self.client.put(self.container["absolute_uri"], content, 'application/json') | ||||||
|  | #        self.assertEquals(resp.status_code, 200) | ||||||
|  | #        container = json.loads(resp.content) | ||||||
|  | #        self.assertEquals(container, self.container) | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -2,13 +2,18 @@ from django.conf.urls.defaults import patterns | ||||||
| 
 | 
 | ||||||
| urlpatterns = patterns('testapp.views', | urlpatterns = patterns('testapp.views', | ||||||
|     (r'^$', 'RootResource'), |     (r'^$', 'RootResource'), | ||||||
|     (r'^read-only$', 'ReadOnlyResource'), |     #(r'^read-only$', 'ReadOnlyResource'), | ||||||
|     (r'^write-only$', 'WriteOnlyResource'), |     #(r'^write-only$', 'WriteOnlyResource'), | ||||||
|     (r'^read-write$', 'ReadWriteResource'), |     #(r'^read-write$', 'ReadWriteResource'), | ||||||
|     (r'^model$', 'ModelFormResource'), |     #(r'^model$', 'ModelFormResource'), | ||||||
|     (r'^container$', 'ContainerFactory'), |     #(r'^container$', 'ContainerFactory'), | ||||||
|     (r'^container/((?P<key>[^/]+))$', 'ContainerInstance'), |     #(r'^container/((?P<key>[^/]+))$', 'ContainerInstance'), | ||||||
|      |      | ||||||
|     (r'^blogpost/create$', 'BlogPostCreator'), |     (r'^blog-posts/$', 'BlogPostList'), | ||||||
|     (r'^blogposts/(?P<slug>[^/]+)', 'BlogPostInstance'), |     (r'^blog-post/$', 'BlogPostCreator'), | ||||||
|  |     (r'^blog-post/(?P<key>[^/]+)/$', 'BlogPostInstance'), | ||||||
|  | 
 | ||||||
|  |     (r'^blog-post/(?P<blogpost_id>[^/]+)/comments/$', 'CommentList'), | ||||||
|  |     (r'^blog-post/(?P<blogpost_id>[^/]+)/comment/$', 'CommentCreator'), | ||||||
|  |     (r'^blog-post/(?P<blogpost>[^/]+)/comments/(?P<id>[^/]+)/$', 'CommentInstance'), | ||||||
| ) | ) | ||||||
|  |  | ||||||
|  | @ -1,78 +1,111 @@ | ||||||
| from rest.resource import Resource, ModelResource | from rest.resource import Resource, ModelResource, QueryModelResource | ||||||
| from testapp.forms import ExampleForm | from testapp.models import BlogPost, Comment | ||||||
| from testapp.models import ExampleModel, ExampleContainer, BlogPost, Comment |  | ||||||
|   |   | ||||||
| class RootResource(Resource): | class RootResource(Resource): | ||||||
|     """This is my docstring |     """This is the top level resource for the API. | ||||||
|     """ |     All the sub-resources are discoverable from here.""" | ||||||
|     allowed_operations = ('read',) |     allowed_operations = ('read',) | ||||||
| 
 | 
 | ||||||
|     def read(self, headers={}, *args, **kwargs): |     def read(self, headers={}, *args, **kwargs): | ||||||
|         return (200, {'read-only-api': self.reverse(ReadOnlyResource), |         return (200, {'blog-posts': self.reverse(BlogPostList), | ||||||
|                       'write-only-api': self.reverse(WriteOnlyResource), |                       'blog-post': self.reverse(BlogPostCreator)}, {}) | ||||||
|                       'read-write-api': self.reverse(ReadWriteResource), |  | ||||||
|                       'model-api': self.reverse(ModelFormResource), |  | ||||||
|                       'create-container': self.reverse(ContainerFactory), |  | ||||||
|                       'blog-post-creator': self.reverse(BlogPostCreator)}, {}) |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class ReadOnlyResource(Resource): | # Blog Post Resources | ||||||
|     """This is my docstring | 
 | ||||||
|     """ | class BlogPostList(QueryModelResource): | ||||||
|  |     """A resource which lists all existing blog posts.""" | ||||||
|     allowed_operations = ('read', ) |     allowed_operations = ('read', ) | ||||||
| 
 |     model = BlogPost | ||||||
|     def read(self, headers={}, *args, **kwargs): |  | ||||||
|         return (200, {'ExampleString': 'Example', |  | ||||||
|                       'ExampleInt': 1, |  | ||||||
|                       'ExampleDecimal': 1.0}, {}) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class WriteOnlyResource(Resource): |  | ||||||
|     """This is my docstring |  | ||||||
|     """ |  | ||||||
|     allowed_operations = ('update',) |  | ||||||
| 
 |  | ||||||
|     def update(self, data, headers={}, *args, **kwargs): |  | ||||||
|         return (200, data, {}) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class ReadWriteResource(Resource): |  | ||||||
|     allowed_operations = ('read', 'update', 'delete') |  | ||||||
|     create_form = ExampleForm |  | ||||||
|     update_form = ExampleForm |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class ModelFormResource(ModelResource): |  | ||||||
|     allowed_operations = ('read', 'update', 'delete') |  | ||||||
|     model = ExampleModel |  | ||||||
| 
 |  | ||||||
| # Nice things: form validation is applied to any input type |  | ||||||
| #              html forms for output |  | ||||||
| #              output always serialized nicely |  | ||||||
| class ContainerFactory(ModelResource): |  | ||||||
|     allowed_operations = ('create',) |  | ||||||
|     model = ExampleContainer |  | ||||||
|     fields = ('absolute_uri', 'name', 'key') |  | ||||||
|     form_fields = ('name',) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class ContainerInstance(ModelResource): |  | ||||||
|     allowed_operations = ('read', 'update', 'delete') |  | ||||||
|     model = ExampleContainer |  | ||||||
|     fields = ('absolute_uri', 'name', 'key') |  | ||||||
|     form_fields = ('name',) |  | ||||||
| 
 |  | ||||||
| ####################### |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class BlogPostCreator(ModelResource): | class BlogPostCreator(ModelResource): | ||||||
|     """A Resource with which blog posts may be created. |     """A resource with which blog posts may be created.""" | ||||||
|     This is distinct from blog post instance so that it is discoverable by the client. |  | ||||||
|     (ie the client doens't need to know how to form a blog post url in order to create a blog post)""" |  | ||||||
|     allowed_operations = ('create',) |     allowed_operations = ('create',) | ||||||
|     model = BlogPost |     model = BlogPost | ||||||
|  |     fields = ('created', 'title', 'slug', 'content', 'absolute_url', 'comment_url', 'comments_url') | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| class BlogPostInstance(ModelResource): | class BlogPostInstance(ModelResource): | ||||||
|     """Represents a single Blog Post.""" |     """A resource which represents a single blog post.""" | ||||||
|     allowed_operations = ('read', 'update', 'delete') |     allowed_operations = ('read', 'update', 'delete') | ||||||
|     model = BlogPost |     model = BlogPost | ||||||
|  |     fields = ('created', 'title', 'slug', 'content', 'absolute_url', 'comment_url', 'comments_url') | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | # Comment Resources | ||||||
|  | 
 | ||||||
|  | class CommentList(QueryModelResource): | ||||||
|  |     """A resource which lists all existing comments for a given blog post.""" | ||||||
|  |     allowed_operations = ('read', ) | ||||||
|  |     model = Comment | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class CommentCreator(ModelResource): | ||||||
|  |     """A resource with which blog comments may be created for a given blog post.""" | ||||||
|  |     allowed_operations = ('create',) | ||||||
|  |     model = Comment | ||||||
|  |     fields = ('username', 'comment', 'created', 'rating', 'absolute_url', 'blogpost_url') | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class CommentInstance(ModelResource): | ||||||
|  |     """A resource which represents a single comment.""" | ||||||
|  |     allowed_operations = ('read', 'update', 'delete') | ||||||
|  |     model = Comment | ||||||
|  |     fields = ('username', 'comment', 'created', 'rating', 'absolute_url', 'blogpost_url') | ||||||
|  |      | ||||||
|  | # | ||||||
|  | #'read-only-api': self.reverse(ReadOnlyResource), | ||||||
|  | #                      'write-only-api': self.reverse(WriteOnlyResource), | ||||||
|  | #                      'read-write-api': self.reverse(ReadWriteResource), | ||||||
|  | #                      'model-api': self.reverse(ModelFormResource), | ||||||
|  | #                      'create-container': self.reverse(ContainerFactory), | ||||||
|  | # | ||||||
|  | #class ReadOnlyResource(Resource): | ||||||
|  | #    """This is my docstring | ||||||
|  | #    """ | ||||||
|  | #    allowed_operations = ('read',) | ||||||
|  | # | ||||||
|  | #    def read(self, headers={}, *args, **kwargs): | ||||||
|  | #        return (200, {'ExampleString': 'Example', | ||||||
|  | #                      'ExampleInt': 1, | ||||||
|  | #                      'ExampleDecimal': 1.0}, {}) | ||||||
|  | # | ||||||
|  | # | ||||||
|  | #class WriteOnlyResource(Resource): | ||||||
|  | #    """This is my docstring | ||||||
|  | #    """ | ||||||
|  | #    allowed_operations = ('update',) | ||||||
|  | # | ||||||
|  | #    def update(self, data, headers={}, *args, **kwargs): | ||||||
|  | #        return (200, data, {}) | ||||||
|  | # | ||||||
|  | # | ||||||
|  | #class ReadWriteResource(Resource): | ||||||
|  | #    allowed_operations = ('read', 'update', 'delete') | ||||||
|  | #    create_form = ExampleForm | ||||||
|  | #    update_form = ExampleForm | ||||||
|  | # | ||||||
|  | # | ||||||
|  | #class ModelFormResource(ModelResource): | ||||||
|  | #    allowed_operations = ('read', 'update', 'delete') | ||||||
|  | #    model = ExampleModel | ||||||
|  | # | ||||||
|  | ## Nice things: form validation is applied to any input type | ||||||
|  | ##              html forms for output | ||||||
|  | ##              output always serialized nicely | ||||||
|  | #class ContainerFactory(ModelResource): | ||||||
|  | #    allowed_operations = ('create',) | ||||||
|  | #    model = ExampleContainer | ||||||
|  | #    fields = ('absolute_uri', 'name', 'key') | ||||||
|  | #    form_fields = ('name',) | ||||||
|  | # | ||||||
|  | # | ||||||
|  | #class ContainerInstance(ModelResource): | ||||||
|  | #    allowed_operations = ('read', 'update', 'delete') | ||||||
|  | #    model = ExampleContainer | ||||||
|  | #    fields = ('absolute_uri', 'name', 'key') | ||||||
|  | #    form_fields = ('name',) | ||||||
|  | 
 | ||||||
|  | ####################### | ||||||
|  | 
 | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user