mirror of
				https://github.com/encode/django-rest-framework.git
				synced 2025-11-04 09:57:55 +03:00 
			
		
		
		
	Allow related models to be fully serialized
This commit is contained in:
		
							parent
							
								
									412b5fc2d5
								
							
						
					
					
						commit
						7dcb851c7f
					
				| 
						 | 
					@ -466,7 +466,7 @@ class InstanceMixin(object):
 | 
				
			||||||
            # We do a little dance when we store the view callable...
 | 
					            # We do a little dance when we store the view callable...
 | 
				
			||||||
            # we need to store it wrapped in a 1-tuple, so that inspect will treat it
 | 
					            # we need to store it wrapped in a 1-tuple, so that inspect will treat it
 | 
				
			||||||
            # as a function when we later look it up (rather than turning it into a method).
 | 
					            # as a function when we later look it up (rather than turning it into a method).
 | 
				
			||||||
            # This makes sure our URL reversing works ok.      
 | 
					            # This makes sure our URL reversing works ok.
 | 
				
			||||||
            resource.view_callable = (view,)
 | 
					            resource.view_callable = (view,)
 | 
				
			||||||
        return view
 | 
					        return view
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -479,6 +479,7 @@ class ReadModelMixin(object):
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    def get(self, request, *args, **kwargs):
 | 
					    def get(self, request, *args, **kwargs):
 | 
				
			||||||
        model = self.resource.model
 | 
					        model = self.resource.model
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
            if args:
 | 
					            if args:
 | 
				
			||||||
                # If we have any none kwargs then assume the last represents the primrary key
 | 
					                # If we have any none kwargs then assume the last represents the primrary key
 | 
				
			||||||
| 
						 | 
					@ -498,6 +499,7 @@ class CreateModelMixin(object):
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    def post(self, request, *args, **kwargs):        
 | 
					    def post(self, request, *args, **kwargs):        
 | 
				
			||||||
        model = self.resource.model
 | 
					        model = self.resource.model
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # translated 'related_field' kwargs into 'related_field_id'
 | 
					        # translated 'related_field' kwargs into 'related_field_id'
 | 
				
			||||||
        for related_name in [field.name for field in model._meta.fields if isinstance(field, RelatedField)]:
 | 
					        for related_name in [field.name for field in model._meta.fields if isinstance(field, RelatedField)]:
 | 
				
			||||||
            if kwargs.has_key(related_name):
 | 
					            if kwargs.has_key(related_name):
 | 
				
			||||||
| 
						 | 
					@ -522,6 +524,7 @@ class UpdateModelMixin(object):
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    def put(self, request, *args, **kwargs):
 | 
					    def put(self, request, *args, **kwargs):
 | 
				
			||||||
        model = self.resource.model
 | 
					        model = self.resource.model
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
        # TODO: update on the url of a non-existing resource url doesn't work correctly at the moment - will end up with a new url 
 | 
					        # TODO: update on the url of a non-existing resource url doesn't work correctly at the moment - will end up with a new url 
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
            if args:
 | 
					            if args:
 | 
				
			||||||
| 
						 | 
					@ -547,6 +550,7 @@ class DeleteModelMixin(object):
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    def delete(self, request, *args, **kwargs):
 | 
					    def delete(self, request, *args, **kwargs):
 | 
				
			||||||
        model = self.resource.model
 | 
					        model = self.resource.model
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
            if args:
 | 
					            if args:
 | 
				
			||||||
                # If we have any none kwargs then assume the last represents the primrary key
 | 
					                # If we have any none kwargs then assume the last represents the primrary key
 | 
				
			||||||
| 
						 | 
					@ -581,10 +585,12 @@ class ListModelMixin(object):
 | 
				
			||||||
    queryset = None
 | 
					    queryset = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get(self, request, *args, **kwargs):
 | 
					    def get(self, request, *args, **kwargs):
 | 
				
			||||||
        queryset = self.queryset if self.queryset else self.resource.model.objects.all()
 | 
					        model = self.resource.model
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        queryset = self.queryset if self.queryset else model.objects.all()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if hasattr(self, 'resource'):
 | 
					        if hasattr(self, 'resource'):
 | 
				
			||||||
            ordering = getattr(self.resource.Meta, 'ordering', None)
 | 
					            ordering = getattr(self.resource, 'ordering', None)
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            ordering = None
 | 
					            ordering = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -181,7 +181,7 @@ class DocumentingTemplateRenderer(BaseRenderer):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Get the form instance if we have one bound to the input
 | 
					        # Get the form instance if we have one bound to the input
 | 
				
			||||||
        form_instance = None
 | 
					        form_instance = None
 | 
				
			||||||
        if method == view.method.lower():
 | 
					        if method == getattr(view, 'method', view.request.method).lower():
 | 
				
			||||||
            form_instance = getattr(view, 'bound_form_instance', None)
 | 
					            form_instance = getattr(view, 'bound_form_instance', None)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if not form_instance and hasattr(view, 'get_bound_form'):
 | 
					        if not form_instance and hasattr(view, 'get_bound_form'):
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -20,12 +20,11 @@ class BaseResource(Serializer):
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    Base class for all Resource classes, which simply defines the interface they provide.
 | 
					    Base class for all Resource classes, which simply defines the interface they provide.
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    class Meta:
 | 
					    fields = None
 | 
				
			||||||
        fields = None
 | 
					    include = None
 | 
				
			||||||
        include = None
 | 
					    exclude = None
 | 
				
			||||||
        exclude = None
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __init__(self, view, depth=None, stack=[], **kwargs):
 | 
					    def __init__(self, view=None, depth=None, stack=[], **kwargs):
 | 
				
			||||||
        super(BaseResource, self).__init__(depth, stack, **kwargs)
 | 
					        super(BaseResource, self).__init__(depth, stack, **kwargs)
 | 
				
			||||||
        self.view = view
 | 
					        self.view = view
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -49,20 +48,19 @@ class Resource(BaseResource):
 | 
				
			||||||
    Objects that a resource can act on include plain Python object instances, Django Models, and Django QuerySets.
 | 
					    Objects that a resource can act on include plain Python object instances, Django Models, and Django QuerySets.
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    class Meta:
 | 
					    # 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
 | 
					    
 | 
				
			||||||
        
 | 
					    # By default the set of returned fields will be the set of:
 | 
				
			||||||
        # By default the set of returned fields will be the set of:
 | 
					    #
 | 
				
			||||||
        #
 | 
					    # 0. All the fields on the model, excluding 'id'.
 | 
				
			||||||
        # 0. All the fields on the model, excluding 'id'.
 | 
					    # 1. All the properties on the model.
 | 
				
			||||||
        # 1. All the properties on the model.
 | 
					    # 2. The absolute_url of the model, if a get_absolute_url method exists for the model.
 | 
				
			||||||
        # 2. The absolute_url of the model, if a get_absolute_url method exists for the model.
 | 
					    #
 | 
				
			||||||
        #
 | 
					    # If you wish to override this behaviour,
 | 
				
			||||||
        # If you wish to override this behaviour,
 | 
					    # you should explicitly set the fields attribute on your class.
 | 
				
			||||||
        # you should explicitly set the fields attribute on your class.
 | 
					    fields = None
 | 
				
			||||||
        fields = None
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class FormResource(Resource):
 | 
					class FormResource(Resource):
 | 
				
			||||||
| 
						 | 
					@ -74,12 +72,11 @@ class FormResource(Resource):
 | 
				
			||||||
    view, which may be used by some renderers.
 | 
					    view, which may be used by some renderers.
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    class Meta:
 | 
					    """
 | 
				
			||||||
        """
 | 
					    The :class:`Form` class that should be used for request validation.
 | 
				
			||||||
        The :class:`Form` class that should be used for request validation.
 | 
					    This can be overridden by a :attr:`form` attribute on the :class:`views.View`.
 | 
				
			||||||
        This can be overridden by a :attr:`form` attribute on the :class:`views.View`.
 | 
					    """
 | 
				
			||||||
        """
 | 
					    form = None
 | 
				
			||||||
        form = None
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def validate_request(self, data, files=None):
 | 
					    def validate_request(self, data, files=None):
 | 
				
			||||||
| 
						 | 
					@ -189,7 +186,7 @@ class FormResource(Resource):
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # A form on the view overrides a form on the resource.
 | 
					        # A form on the view overrides a form on the resource.
 | 
				
			||||||
        form = getattr(self.view, 'form', None) or self.Meta.form
 | 
					        form = getattr(self.view, 'form', None) or self.form
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Use the requested method or determine the request method
 | 
					        # Use the requested method or determine the request method
 | 
				
			||||||
        if method is None and hasattr(self.view, 'request') and hasattr(self.view, 'method'):
 | 
					        if method is None and hasattr(self.view, 'request') and hasattr(self.view, 'method'):
 | 
				
			||||||
| 
						 | 
					@ -235,44 +232,43 @@ class ModelResource(FormResource):
 | 
				
			||||||
    # Auto-register new ModelResource classes into _model_to_resource 
 | 
					    # Auto-register new ModelResource classes into _model_to_resource 
 | 
				
			||||||
    #__metaclass__ = _RegisterModelResource
 | 
					    #__metaclass__ = _RegisterModelResource
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    class Meta:
 | 
					    """
 | 
				
			||||||
        """
 | 
					    The form class that should be used for request validation.
 | 
				
			||||||
        The form class that should be used for request validation.
 | 
					    If set to :const:`None` then the default model form validation will be used.
 | 
				
			||||||
        If set to :const:`None` then the default model form validation will be used.
 | 
					
 | 
				
			||||||
 | 
					    This can be overridden by a :attr:`form` attribute on the :class:`views.View`.
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    form = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    The model class which this resource maps to.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    This can be overridden by a :attr:`model` attribute on the :class:`views.View`.
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    model = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    The list of fields to use on the output.
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
        This can be overridden by a :attr:`form` attribute on the :class:`views.View`.
 | 
					    May be any of:
 | 
				
			||||||
        """
 | 
					 | 
				
			||||||
        form = None
 | 
					 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
        """
 | 
					    The name of a model field.
 | 
				
			||||||
        The model class which this resource maps to.
 | 
					    The name of an attribute on the model.
 | 
				
			||||||
 | 
					    The name of an attribute on the resource.
 | 
				
			||||||
 | 
					    The name of a method on the model, with a signature like ``func(self)``.
 | 
				
			||||||
 | 
					    The name of a method on the resource, with a signature like ``func(self, instance)``.
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    fields = None
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
        This can be overridden by a :attr:`model` attribute on the :class:`views.View`.
 | 
					    """
 | 
				
			||||||
        """
 | 
					    The list of fields to exclude.  This is only used if :attr:`fields` is not set.
 | 
				
			||||||
        model = None
 | 
					    """
 | 
				
			||||||
 | 
					    exclude = ('id', 'pk')
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
        """
 | 
					    """
 | 
				
			||||||
        The list of fields to use on the output.
 | 
					    The list of extra fields to include.  This is only used if :attr:`fields` is not set.
 | 
				
			||||||
        
 | 
					    """
 | 
				
			||||||
        May be any of:
 | 
					    include = ('url',)
 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        The name of a model field.
 | 
					 | 
				
			||||||
        The name of an attribute on the model.
 | 
					 | 
				
			||||||
        The name of an attribute on the resource.
 | 
					 | 
				
			||||||
        The name of a method on the model, with a signature like ``func(self)``.
 | 
					 | 
				
			||||||
        The name of a method on the resource, with a signature like ``func(self, instance)``.
 | 
					 | 
				
			||||||
        """
 | 
					 | 
				
			||||||
        fields = None
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        """
 | 
					 | 
				
			||||||
        The list of fields to exclude.  This is only used if :attr:`fields` is not set.
 | 
					 | 
				
			||||||
        """
 | 
					 | 
				
			||||||
        exclude = ('id', 'pk')
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        """
 | 
					 | 
				
			||||||
        The list of extra fields to include.  This is only used if :attr:`fields` is not set.
 | 
					 | 
				
			||||||
        """
 | 
					 | 
				
			||||||
        include = ('url',)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __init__(self, view):
 | 
					    def __init__(self, view):
 | 
				
			||||||
| 
						 | 
					@ -283,7 +279,7 @@ class ModelResource(FormResource):
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        super(ModelResource, self).__init__(view)
 | 
					        super(ModelResource, self).__init__(view)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.model = getattr(view, 'model', None) or self.Meta.model
 | 
					        self.model = getattr(view, 'model', None) or self.model
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def validate_request(self, data, files=None):
 | 
					    def validate_request(self, data, files=None):
 | 
				
			||||||
| 
						 | 
					@ -369,7 +365,7 @@ class ModelResource(FormResource):
 | 
				
			||||||
                    if isinstance(attr, models.Model):
 | 
					                    if isinstance(attr, models.Model):
 | 
				
			||||||
                        instance_attrs[param] = attr.pk
 | 
					                        instance_attrs[param] = attr.pk
 | 
				
			||||||
                    else:
 | 
					                    else:
 | 
				
			||||||
                        instance_attrs[param] = attr    
 | 
					                        instance_attrs[param] = attr
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                try:
 | 
					                try:
 | 
				
			||||||
                    return reverse(self.view_callable[0], kwargs=instance_attrs)
 | 
					                    return reverse(self.view_callable[0], kwargs=instance_attrs)
 | 
				
			||||||
| 
						 | 
					@ -399,7 +395,7 @@ class ModelResource(FormResource):
 | 
				
			||||||
                              isinstance(getattr(self.model, attr, None), property)
 | 
					                              isinstance(getattr(self.model, attr, None), property)
 | 
				
			||||||
                              and not attr.startswith('_'))
 | 
					                              and not attr.startswith('_'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if self.Meta.fields:
 | 
					        if self.fields:
 | 
				
			||||||
            return property_fields & set(as_tuple(self.Meta.fields))
 | 
					            return property_fields & set(as_tuple(self.fields))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return property_fields.union(set(as_tuple(self.Meta.include))) - set(as_tuple(self.Meta.exclude))
 | 
					        return property_fields.union(set(as_tuple(self.include))) - set(as_tuple(self.exclude))
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -46,30 +46,14 @@ class _SkipField(Exception):
 | 
				
			||||||
    pass
 | 
					    pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class _BuildInnerMeta(type):
 | 
					class _RegisterSerializer(type):
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    Some magic so that an inner Meta class gets inheriting behavior.
 | 
					    Metaclass to register serializers.
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    def __new__(cls, name, bases, attrs):
 | 
					    def __new__(cls, name, bases, attrs):
 | 
				
			||||||
        # Get a list of all the inner Metas, from the bases upwards.
 | 
					 | 
				
			||||||
        inner_metas = [getattr(base, 'Meta', object) for base in bases]
 | 
					 | 
				
			||||||
        inner_metas.append(attrs.get('Meta', object))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # Build up the attributes on the inner Meta.
 | 
					 | 
				
			||||||
        meta_attrs = {}
 | 
					 | 
				
			||||||
        [meta_attrs.update(inner_meta.__dict__) for inner_meta in inner_metas]
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        # Drop private attributes.
 | 
					 | 
				
			||||||
        meta_attrs = dict([ (key, val) for (key, val) in meta_attrs.items()
 | 
					 | 
				
			||||||
                            if not key.startswith('_') ])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # Lovely, now we can create our inner Meta class.
 | 
					 | 
				
			||||||
        attrs['Meta'] = type('Meta', (object,), meta_attrs)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # Build the class and register it.
 | 
					        # Build the class and register it.
 | 
				
			||||||
        ret = super(_BuildInnerMeta, cls).__new__(cls, name, bases, attrs) 
 | 
					        ret = super(_RegisterSerializer, cls).__new__(cls, name, bases, attrs) 
 | 
				
			||||||
        _serializers[name] = ret
 | 
					        _serializers[name] = ret
 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        return ret
 | 
					        return ret
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -78,8 +62,8 @@ class Serializer(object):
 | 
				
			||||||
    Converts python objects into plain old native types suitable for
 | 
					    Converts python objects into plain old native types suitable for
 | 
				
			||||||
    serialization.  In particular it handles models and querysets.
 | 
					    serialization.  In particular it handles models and querysets.
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    The output format is specified by setting a number of attributes on the
 | 
					    The output format is specified by setting a number of attributes
 | 
				
			||||||
    inner `Meta` class.
 | 
					    on the class.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    You may also override any of the serialization methods, to provide
 | 
					    You may also override any of the serialization methods, to provide
 | 
				
			||||||
    for more flexible behavior.
 | 
					    for more flexible behavior.
 | 
				
			||||||
| 
						 | 
					@ -87,75 +71,61 @@ class Serializer(object):
 | 
				
			||||||
    Valid output types include anything that may be directly rendered into
 | 
					    Valid output types include anything that may be directly rendered into
 | 
				
			||||||
    json, xml etc...
 | 
					    json, xml etc...
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    __metaclass__ = _BuildInnerMeta
 | 
					    __metaclass__ = _RegisterSerializer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    class Meta:
 | 
					    fields = () 
 | 
				
			||||||
        """
 | 
					    """
 | 
				
			||||||
        Information on how to serialize the data.
 | 
					    Specify the fields to be serialized on a model or dict.
 | 
				
			||||||
        """
 | 
					    Overrides `include` and `exclude`.
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        fields = () 
 | 
					    include = ()
 | 
				
			||||||
        """
 | 
					    """
 | 
				
			||||||
        Specify the fields to be serialized on a model or dict.
 | 
					    Fields to add to the default set to be serialized on a model/dict.
 | 
				
			||||||
        Overrides `include` and `exclude`.
 | 
					    """
 | 
				
			||||||
        """
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        include = ()
 | 
					    exclude = ()
 | 
				
			||||||
        """
 | 
					    """
 | 
				
			||||||
        Fields to add to the default set to be serialized on a model/dict.
 | 
					    Fields to remove from the default set to be serialized on a model/dict.
 | 
				
			||||||
        """
 | 
					    """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        exclude = ()
 | 
					    rename = {}
 | 
				
			||||||
        """
 | 
					    """
 | 
				
			||||||
        Fields to remove from the default set to be serialized on a model/dict.
 | 
					    A dict of key->name to use for the field keys.
 | 
				
			||||||
        """
 | 
					    """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        rename = {}
 | 
					    related_serializer = None
 | 
				
			||||||
        """
 | 
					    """
 | 
				
			||||||
        A dict of key->name to use for the field keys.
 | 
					    The default serializer class to use for any related models.
 | 
				
			||||||
        """
 | 
					    """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        related_serializer = None
 | 
					    depth = None
 | 
				
			||||||
        """
 | 
					    """
 | 
				
			||||||
        The default serializer class to use for any related models.
 | 
					    The maximum depth to serialize to, or `None`.
 | 
				
			||||||
        """
 | 
					    """
 | 
				
			||||||
 | 
					 | 
				
			||||||
        depth = None
 | 
					 | 
				
			||||||
        """
 | 
					 | 
				
			||||||
        The maximum depth to serialize to, or `None`.
 | 
					 | 
				
			||||||
        """
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __init__(self, depth=None, stack=[], **kwargs):
 | 
					    def __init__(self, depth=None, stack=[], **kwargs):
 | 
				
			||||||
        """
 | 
					        self.depth = depth or self.depth
 | 
				
			||||||
        Allow `Meta` items to be set on init.
 | 
					 | 
				
			||||||
        """
 | 
					 | 
				
			||||||
        self.depth = depth
 | 
					 | 
				
			||||||
        self.stack = stack
 | 
					        self.stack = stack
 | 
				
			||||||
 | 
					 | 
				
			||||||
        if self.depth is None:
 | 
					 | 
				
			||||||
            self.depth = self.Meta.depth
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        for (key, val) in kwargs.items():
 | 
					 | 
				
			||||||
            setattr(self.Meta, key, val)
 | 
					 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_fields(self, obj):
 | 
					    def get_fields(self, obj):
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        Return the set of field names/keys to use for a model instance/dict.
 | 
					        Return the set of field names/keys to use for a model instance/dict.
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        fields = self.Meta.fields
 | 
					        fields = self.fields
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # If Meta.fields is not set, we use the default fields and modify
 | 
					        # If `fields` is not set, we use the default fields and modify
 | 
				
			||||||
        # them with Meta.include and Meta.exclude
 | 
					        # them with `include` and `exclude`
 | 
				
			||||||
        if not fields:
 | 
					        if not fields:
 | 
				
			||||||
            default = self.get_default_fields(obj)
 | 
					            default = self.get_default_fields(obj)
 | 
				
			||||||
            include = self.Meta.include or ()
 | 
					            include = self.include or ()
 | 
				
			||||||
            exclude = self.Meta.exclude or ()
 | 
					            exclude = self.exclude or ()
 | 
				
			||||||
            fields = set(default + list(include)) - set(exclude)
 | 
					            fields = set(default + list(include)) - set(exclude)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            fields = _fields_to_list(self.Meta.fields)
 | 
					            fields = _fields_to_list(self.fields)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return fields
 | 
					        return fields
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -163,7 +133,7 @@ class Serializer(object):
 | 
				
			||||||
    def get_default_fields(self, obj):
 | 
					    def get_default_fields(self, obj):
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        Return the default list of field names/keys for a model instance/dict.
 | 
					        Return the default list of field names/keys for a model instance/dict.
 | 
				
			||||||
        These are used if `Meta.fields` is not given.
 | 
					        These are used if `fields` is not given.
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        if isinstance(obj, models.Model):
 | 
					        if isinstance(obj, models.Model):
 | 
				
			||||||
            opts = obj._meta
 | 
					            opts = obj._meta
 | 
				
			||||||
| 
						 | 
					@ -173,15 +143,14 @@ class Serializer(object):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_related_serializer(self, key):
 | 
					    def get_related_serializer(self, key):
 | 
				
			||||||
        info = _fields_to_dict(self.Meta.fields).get(key, None)
 | 
					        info = _fields_to_dict(self.fields).get(key, None)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # If an element in `fields` is a 2-tuple of (str, tuple)
 | 
					        # If an element in `fields` is a 2-tuple of (str, tuple)
 | 
				
			||||||
        # then the second element of the tuple is the fields to
 | 
					        # then the second element of the tuple is the fields to
 | 
				
			||||||
        # set on the related serializer
 | 
					        # set on the related serializer
 | 
				
			||||||
        if isinstance(info, (list, tuple)):
 | 
					        if isinstance(info, (list, tuple)):
 | 
				
			||||||
            class OnTheFlySerializer(Serializer):
 | 
					            class OnTheFlySerializer(Serializer):
 | 
				
			||||||
                class Meta:
 | 
					                fields = info
 | 
				
			||||||
                    fields = info
 | 
					 | 
				
			||||||
            return OnTheFlySerializer
 | 
					            return OnTheFlySerializer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # If an element in `fields` is a 2-tuple of (str, Serializer)
 | 
					        # If an element in `fields` is a 2-tuple of (str, Serializer)
 | 
				
			||||||
| 
						 | 
					@ -200,15 +169,15 @@ class Serializer(object):
 | 
				
			||||||
            return _serializers[info]
 | 
					            return _serializers[info]
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        # Otherwise use `related_serializer` or fall back to `Serializer`
 | 
					        # Otherwise use `related_serializer` or fall back to `Serializer`
 | 
				
			||||||
        return getattr(self.Meta, 'related_serializer') or Serializer
 | 
					        return getattr(self, 'related_serializer') or Serializer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def serialize_key(self, key):
 | 
					    def serialize_key(self, key):
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        Keys serialize to their string value,
 | 
					        Keys serialize to their string value,
 | 
				
			||||||
        unless they exist in the `Meta.rename` dict.
 | 
					        unless they exist in the `rename` dict.
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        return getattr(self.Meta.rename, key, key)
 | 
					        return getattr(self.rename, key, key)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def serialize_val(self, key, obj):
 | 
					    def serialize_val(self, key, obj):
 | 
				
			||||||
| 
						 | 
					@ -251,8 +220,7 @@ class Serializer(object):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def serialize_model(self, instance):
 | 
					    def serialize_model(self, instance):
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        Given a model instance or dict, serialize it to a dict, using
 | 
					        Given a model instance or dict, serialize it to a dict..
 | 
				
			||||||
        the given behavior given on Meta.
 | 
					 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        data = {}
 | 
					        data = {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -69,12 +69,10 @@ class TestFieldNesting(TestCase):
 | 
				
			||||||
        Test tuple nesting on `fields` attr
 | 
					        Test tuple nesting on `fields` attr
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        class SerializerM2(Serializer):
 | 
					        class SerializerM2(Serializer):
 | 
				
			||||||
            class Meta:
 | 
					            fields = (('field', ('field1',)),)
 | 
				
			||||||
                fields = (('field', ('field1',)),)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        class SerializerM3(Serializer):
 | 
					        class SerializerM3(Serializer):
 | 
				
			||||||
            class Meta:
 | 
					            fields = (('field', ('field2',)),)
 | 
				
			||||||
                fields = (('field', ('field2',)),)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.assertEqual(SerializerM2().serialize(self.m2), {'field': {'field1': u'foo'}})
 | 
					        self.assertEqual(SerializerM2().serialize(self.m2), {'field': {'field1': u'foo'}})
 | 
				
			||||||
        self.assertEqual(SerializerM3().serialize(self.m3), {'field': {'field2': u'bar'}})
 | 
					        self.assertEqual(SerializerM3().serialize(self.m3), {'field': {'field2': u'bar'}})
 | 
				
			||||||
| 
						 | 
					@ -85,20 +83,16 @@ class TestFieldNesting(TestCase):
 | 
				
			||||||
        Test related model serialization
 | 
					        Test related model serialization
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        class NestedM2(Serializer):
 | 
					        class NestedM2(Serializer):
 | 
				
			||||||
            class Meta:
 | 
					            fields = ('field1', )
 | 
				
			||||||
                fields = ('field1', )
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        class NestedM3(Serializer):
 | 
					        class NestedM3(Serializer):
 | 
				
			||||||
            class Meta:
 | 
					            fields = ('field2', )
 | 
				
			||||||
                fields = ('field2', )
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        class SerializerM2(Serializer):
 | 
					        class SerializerM2(Serializer):
 | 
				
			||||||
            class Meta:
 | 
					            fields = [('field', NestedM2)]
 | 
				
			||||||
                fields = [('field', NestedM2)]
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        class SerializerM3(Serializer):
 | 
					        class SerializerM3(Serializer):
 | 
				
			||||||
            class Meta:
 | 
					            fields = [('field', NestedM3)]
 | 
				
			||||||
                fields = [('field', NestedM3)]
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.assertEqual(SerializerM2().serialize(self.m2), {'field': {'field1': u'foo'}})
 | 
					        self.assertEqual(SerializerM2().serialize(self.m2), {'field': {'field1': u'foo'}})
 | 
				
			||||||
        self.assertEqual(SerializerM3().serialize(self.m3), {'field': {'field2': u'bar'}})
 | 
					        self.assertEqual(SerializerM3().serialize(self.m3), {'field': {'field2': u'bar'}})
 | 
				
			||||||
| 
						 | 
					@ -108,20 +102,16 @@ class TestFieldNesting(TestCase):
 | 
				
			||||||
        Test related model serialization
 | 
					        Test related model serialization
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        class SerializerM2(Serializer):
 | 
					        class SerializerM2(Serializer):
 | 
				
			||||||
            class Meta:
 | 
					            fields = [('field', 'NestedM2')]
 | 
				
			||||||
                fields = [('field', 'NestedM2')]
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        class SerializerM3(Serializer):
 | 
					        class SerializerM3(Serializer):
 | 
				
			||||||
            class Meta:
 | 
					            fields = [('field', 'NestedM3')]
 | 
				
			||||||
                fields = [('field', 'NestedM3')]
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        class NestedM2(Serializer):
 | 
					        class NestedM2(Serializer):
 | 
				
			||||||
            class Meta:
 | 
					            fields = ('field1', )
 | 
				
			||||||
                fields = ('field1', )
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        class NestedM3(Serializer):
 | 
					        class NestedM3(Serializer):
 | 
				
			||||||
            class Meta:
 | 
					            fields = ('field2', )
 | 
				
			||||||
                fields = ('field2', )
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.assertEqual(SerializerM2().serialize(self.m2), {'field': {'field1': u'foo'}})
 | 
					        self.assertEqual(SerializerM2().serialize(self.m2), {'field': {'field1': u'foo'}})
 | 
				
			||||||
        self.assertEqual(SerializerM3().serialize(self.m3), {'field': {'field2': u'bar'}})
 | 
					        self.assertEqual(SerializerM3().serialize(self.m3), {'field': {'field2': u'bar'}})
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -75,8 +75,7 @@ class TestNonFieldErrors(TestCase):
 | 
				
			||||||
                return self.cleaned_data  #pragma: no cover
 | 
					                return self.cleaned_data  #pragma: no cover
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        class MockResource(FormResource):
 | 
					        class MockResource(FormResource):
 | 
				
			||||||
            class Meta:
 | 
					            form = MockForm
 | 
				
			||||||
                form = MockForm
 | 
					 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        class MockView(View):
 | 
					        class MockView(View):
 | 
				
			||||||
            pass
 | 
					            pass
 | 
				
			||||||
| 
						 | 
					@ -100,12 +99,10 @@ class TestFormValidation(TestCase):
 | 
				
			||||||
            qwerty = forms.CharField(required=True)
 | 
					            qwerty = forms.CharField(required=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        class MockFormResource(FormResource):
 | 
					        class MockFormResource(FormResource):
 | 
				
			||||||
            class Meta:
 | 
					            form = MockForm
 | 
				
			||||||
                form = MockForm
 | 
					 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        class MockModelResource(ModelResource):
 | 
					        class MockModelResource(ModelResource):
 | 
				
			||||||
            class Meta:
 | 
					            form = MockForm
 | 
				
			||||||
                form = MockForm
 | 
					 | 
				
			||||||
 
 | 
					 
 | 
				
			||||||
        class MockFormView(View):
 | 
					        class MockFormView(View):
 | 
				
			||||||
            resource = MockFormResource
 | 
					            resource = MockFormResource
 | 
				
			||||||
| 
						 | 
					@ -278,8 +275,7 @@ class TestModelFormValidator(TestCase):
 | 
				
			||||||
                return 'read only'
 | 
					                return 'read only'
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        class MockResource(ModelResource):
 | 
					        class MockResource(ModelResource):
 | 
				
			||||||
            class Meta:
 | 
					            model = MockModel
 | 
				
			||||||
                model = MockModel
 | 
					 | 
				
			||||||
 
 | 
					 
 | 
				
			||||||
        class MockView(View):
 | 
					        class MockView(View):
 | 
				
			||||||
            resource = MockResource
 | 
					            resource = MockResource
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -18,9 +18,19 @@ In this example we're working from two related models:
 | 
				
			||||||
Creating the resources
 | 
					Creating the resources
 | 
				
			||||||
----------------------
 | 
					----------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Once we have some existing models there's very little we need to do to create the API.
 | 
					We need to create two resources that we map to our two existing models, in order to describe how the models should be serialized.
 | 
				
			||||||
Firstly create a resource for each model that defines which fields we want to expose on the model.
 | 
					Our resource descriptions will typically go into a module called something like 'resources.py'
 | 
				
			||||||
Secondly we map a base view and an instance view for each resource.
 | 
					
 | 
				
			||||||
 | 
					``resources.py``
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. include:: ../../examples/blogpost/resources.py
 | 
				
			||||||
 | 
					    :literal:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Creating views for our resources
 | 
				
			||||||
 | 
					--------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Once we've created the resources there's very little we need to do to create the API.
 | 
				
			||||||
 | 
					For each resource we'll create a base view, and an instance view.
 | 
				
			||||||
The generic views :class:`.ListOrCreateModelView` and :class:`.InstanceModelView` provide default operations for listing, creating and updating our models via the API, and also automatically provide input validation using default ModelForms for each model.
 | 
					The generic views :class:`.ListOrCreateModelView` and :class:`.InstanceModelView` provide default operations for listing, creating and updating our models via the API, and also automatically provide input validation using default ModelForms for each model.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
``urls.py``
 | 
					``urls.py``
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -25,7 +25,14 @@ Here's the model we're working from in this example:
 | 
				
			||||||
.. include:: ../../examples/modelresourceexample/models.py
 | 
					.. include:: ../../examples/modelresourceexample/models.py
 | 
				
			||||||
    :literal:
 | 
					    :literal:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
To add an API for the model, all we need to do is create a Resource for the model, and map a couple of views to it in our urlconf.
 | 
					To add an API for the model, first we need to create a Resource for the model.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					``resources.py``
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. include:: ../../examples/modelresourceexample/resources.py
 | 
				
			||||||
 | 
					    :literal:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Then we simply map a couple of views to the Resource in our urlconf.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
``urls.py``
 | 
					``urls.py``
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,35 @@
 | 
				
			||||||
Alternative Frameworks
 | 
					Alternative frameworks & Why Django REST framework
 | 
				
			||||||
======================
 | 
					==================================================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#. `django-piston <https://bitbucket.org/jespern/django-piston/wiki/Home>`_ is excellent, and has a great community behind it.  This project is based on piston code in parts.
 | 
					Alternative frameworks
 | 
				
			||||||
 | 
					----------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#. `django-tasypie <https://github.com/toastdriven/django-tastypie>`_ is also well worth looking at.
 | 
					There are a number of alternative REST frameworks for Django:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* `django-piston <https://bitbucket.org/jespern/django-piston/wiki/Home>`_ is very mature, and has a large community behind it.  This project was originally based on piston code in parts.
 | 
				
			||||||
 | 
					* `django-tasypie <https://github.com/toastdriven/django-tastypie>`_ is also very good, and has a very active and helpful developer community and maintainers.
 | 
				
			||||||
 | 
					* Other interesting projects include `dagny <https://github.com/zacharyvoase/dagny>`_ and `dj-webmachine <http://benoitc.github.com/dj-webmachine/>`_
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Why use Django REST framework?
 | 
				
			||||||
 | 
					------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The big benefits of using Django REST framework come down to:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					1. It's based on Django's class based views, which makes it simple, modular, and future-proof.
 | 
				
			||||||
 | 
					2. It stays as close as possible to Django idioms and language throughout.
 | 
				
			||||||
 | 
					3. The browse-able API makes working with the APIs extremely quick and easy.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Why was this project created?
 | 
				
			||||||
 | 
					-----------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					For me the browse-able API is the most important aspect of Django REST framework.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					I wanted to show that Web APIs could easily be made Web browse-able,
 | 
				
			||||||
 | 
					and demonstrate how much better browse-able Web APIs are to work with.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Being able to navigate and use a Web API directly in the browser is a huge win over only having command line and programmatic
 | 
				
			||||||
 | 
					access to the API.  It enables the API to be properly self-describing, and it makes it much much quicker and easier to work with.
 | 
				
			||||||
 | 
					There's no fundamental reason why the Web APIs we're creating shouldn't be able to render to HTML as well as JSON/XML/whatever,
 | 
				
			||||||
 | 
					and I really think that more Web API frameworks *in whatever language* ought to be taking a similar approach.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -80,8 +80,7 @@ Using Django REST framework can be as simple as adding a few lines to your urlco
 | 
				
			||||||
    from myapp.models import MyModel
 | 
					    from myapp.models import MyModel
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    class MyResource(ModelResource):
 | 
					    class MyResource(ModelResource):
 | 
				
			||||||
        class Meta:
 | 
					        model = MyModel
 | 
				
			||||||
            model = MyModel
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    urlpatterns = patterns('',
 | 
					    urlpatterns = patterns('',
 | 
				
			||||||
        url(r'^$', ListOrCreateModelView.as_view(resource=MyResource)),
 | 
					        url(r'^$', ListOrCreateModelView.as_view(resource=MyResource)),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,10 +1,5 @@
 | 
				
			||||||
:mod:`serializer` 
 | 
					:mod:`serializer` 
 | 
				
			||||||
=================
 | 
					=================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. module:: serializer
 | 
					.. automodule:: serializer
 | 
				
			||||||
 | 
					 | 
				
			||||||
.. autoclass:: serializer::Serializer.Meta
 | 
					 | 
				
			||||||
   :members:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.. autoclass:: serializer::Serializer
 | 
					 | 
				
			||||||
   :members:
 | 
					   :members:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -22,6 +22,9 @@ class BlogPost(models.Model):
 | 
				
			||||||
    slug = models.SlugField(editable=False, default='')
 | 
					    slug = models.SlugField(editable=False, default='')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def save(self, *args, **kwargs):
 | 
					    def save(self, *args, **kwargs):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        For the purposes of the sandbox, limit the maximum number of stored models.
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
        self.slug = slugify(self.title)
 | 
					        self.slug = slugify(self.title)
 | 
				
			||||||
        super(self.__class__, self).save(*args, **kwargs)
 | 
					        super(self.__class__, self).save(*args, **kwargs)
 | 
				
			||||||
        for obj in self.__class__.objects.order_by('-created')[MAX_POSTS:]:
 | 
					        for obj in self.__class__.objects.order_by('-created')[MAX_POSTS:]:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,38 +1,11 @@
 | 
				
			||||||
from django.conf.urls.defaults import patterns, url
 | 
					from django.conf.urls.defaults import patterns, url
 | 
				
			||||||
from django.core.urlresolvers import reverse
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from djangorestframework.views import ListOrCreateModelView, InstanceModelView
 | 
					from djangorestframework.views import ListOrCreateModelView, InstanceModelView
 | 
				
			||||||
from djangorestframework.resources import ModelResource
 | 
					from blogpost.resources import BlogPostResource, CommentResource
 | 
				
			||||||
 | 
					 | 
				
			||||||
from blogpost.models import BlogPost, Comment
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class BlogPostResource(ModelResource):
 | 
					 | 
				
			||||||
    """
 | 
					 | 
				
			||||||
    A Blog Post has a *title* and *content*, and can be associated with zero or more comments.
 | 
					 | 
				
			||||||
    """
 | 
					 | 
				
			||||||
    class Meta:
 | 
					 | 
				
			||||||
        model = BlogPost
 | 
					 | 
				
			||||||
        fields = ('created', 'title', 'slug', 'content', 'url', 'comments')
 | 
					 | 
				
			||||||
        ordering = ('-created',)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def comments(self, instance):
 | 
					 | 
				
			||||||
        return reverse('comments', kwargs={'blogpost': instance.key}) 
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class CommentResource(ModelResource):
 | 
					 | 
				
			||||||
    """
 | 
					 | 
				
			||||||
    A Comment is associated with a given Blog Post and has a *username* and *comment*, and optionally a *rating*. 
 | 
					 | 
				
			||||||
    """
 | 
					 | 
				
			||||||
    class Meta:
 | 
					 | 
				
			||||||
        model = Comment
 | 
					 | 
				
			||||||
        fields = ('username', 'comment', 'created', 'rating', 'url', 'blogpost')
 | 
					 | 
				
			||||||
        ordering = ('-created',)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
urlpatterns = patterns('',
 | 
					urlpatterns = patterns('',
 | 
				
			||||||
    url(r'^$', ListOrCreateModelView.as_view(resource=BlogPostResource), name='blog-posts-root'),
 | 
					    url(r'^$', ListOrCreateModelView.as_view(resource=BlogPostResource), name='blog-posts-root'),
 | 
				
			||||||
    url(r'^(?P<key>[^/]+)/$', InstanceModelView.as_view(resource=BlogPostResource)),
 | 
					    url(r'^(?P<key>[^/]+)/$', InstanceModelView.as_view(resource=BlogPostResource), name='blog-post'),
 | 
				
			||||||
    url(r'^(?P<blogpost>[^/]+)/comments/$', ListOrCreateModelView.as_view(resource=CommentResource), name='comments'),
 | 
					    url(r'^(?P<blogpost>[^/]+)/comments/$', ListOrCreateModelView.as_view(resource=CommentResource), name='comments'),
 | 
				
			||||||
    url(r'^(?P<blogpost>[^/]+)/comments/(?P<id>[^/]+)/$', InstanceModelView.as_view(resource=CommentResource)),
 | 
					    url(r'^(?P<blogpost>[^/]+)/comments/(?P<id>[^/]+)/$', InstanceModelView.as_view(resource=CommentResource)),
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,15 +1,8 @@
 | 
				
			||||||
from django.conf.urls.defaults import patterns, url
 | 
					from django.conf.urls.defaults import patterns, url
 | 
				
			||||||
from djangorestframework.views import ListOrCreateModelView, InstanceModelView
 | 
					from djangorestframework.views import ListOrCreateModelView, InstanceModelView
 | 
				
			||||||
from djangorestframework.resources import ModelResource
 | 
					from modelresourceexample.resources import MyModelResource
 | 
				
			||||||
from modelresourceexample.models import MyModel
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class MyModelResource(ModelResource):
 | 
					 | 
				
			||||||
    class Meta:
 | 
					 | 
				
			||||||
        model = MyModel
 | 
					 | 
				
			||||||
        fields = ('foo', 'bar', 'baz', 'url')
 | 
					 | 
				
			||||||
        ordering = ('created',)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
urlpatterns = patterns('',
 | 
					urlpatterns = patterns('',
 | 
				
			||||||
    url(r'^$',          ListOrCreateModelView.as_view(resource=MyModelResource), name='model-resource-root'),
 | 
					    url(r'^$',          ListOrCreateModelView.as_view(resource=MyModelResource), name='model-resource-root'),
 | 
				
			||||||
    url(r'^([0-9]+)/$', InstanceModelView.as_view(resource=MyModelResource)),
 | 
					    url(r'^(?P<pk>[0-9]+)/$', InstanceModelView.as_view(resource=MyModelResource)),
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -46,19 +46,12 @@ class HTMLRenderer(BaseRenderer):
 | 
				
			||||||
    media_type = 'text/html'
 | 
					    media_type = 'text/html'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
class PygmentsFormResource(FormResource):
 | 
					 | 
				
			||||||
    """
 | 
					 | 
				
			||||||
    """
 | 
					 | 
				
			||||||
    form = PygmentsForm
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class PygmentsRoot(View):
 | 
					class PygmentsRoot(View):
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    This example demonstrates a simple RESTful Web API aound the awesome pygments library.
 | 
					    This example demonstrates a simple RESTful Web API around the awesome pygments library.
 | 
				
			||||||
    This top level resource is used to create highlighted code snippets, and to list all the existing code snippets.
 | 
					    This top level resource is used to create highlighted code snippets, and to list all the existing code snippets.
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    resource = PygmentsFormResource
 | 
					    form = PygmentsForm
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get(self, request):
 | 
					    def get(self, request):
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user