diff --git a/api-guide/fields.html b/api-guide/fields.html index 71de1d618..5b1b83335 100644 --- a/api-guide/fields.html +++ b/api-guide/fields.html @@ -126,6 +126,8 @@
  • IntegerField
  • FloatField
  • Relational Fields
  • +
  • RelatedField
  • +
  • ManyRelatedField
  • PrimaryKeyRelatedField
  • ManyPrimaryKeyRelatedField
  • HyperlinkedRelatedField
  • @@ -148,10 +150,39 @@

    Note: The serializer fields are declared in fields.py, but by convention you should import them using from rest_framework import serializers and refer to fields as serializers.<FieldName>.


    Generic Fields

    +

    These generic fields are used for representing arbitrary model fields or the output of model methods.

    Field

    -

    A generic, read-only field. You can use this field for any attribute that does not need to support write operations.

    +

    A generic, read-only field. You can use this field for any attribute that does not need to support write operations.

    +

    For example, using the following model.

    +
    class Account(models.Model):
    +    owner = models.ForeignKey('auth.user')
    +    name = models.CharField(max_length=100)
    +    created = models.DateTimeField(auto_now_add=True)
    +    payment_expiry = models.DateTimeField()
    +
    +    def has_expired(self):
    +        now = datetime.datetime.now()
    +        return now > self.payment_expiry
    +
    +

    A serializer definition that looked like this:

    +
    class AccountSerializer(serializers.HyperlinkedModelSerializer):
    +    expired = Field(source='has_expired')
    +
    +    class Meta:
    +        fields = ('url', 'owner', 'name', 'expired')
    +
    +

    Would produced output similar to:

    +
    {
    +    'url': 'http://example.com/api/accounts/3/',
    +    'owner': 'http://example.com/api/users/12/',
    +    'name': 'FooCorp business account', 
    +    'expired': True
    +}
    +
    +

    Be default, the Field class will perform a basic translation of the source value into primative datatypes, falling back to unicode representations of complex datatypes when neccesary.

    +

    You can customize this behaviour by overriding the .to_native(self, value) method.

    WritableField

    -

    A field that supports both read and

    +

    A field that supports both read and write operations. By itself WriteableField does not perform any translation of input values into a given type. You won't typically use this field directly, but you may want to override it and implement the .to_native(self, value) and .from_native(self, value) methods.

    ModelField

    A generic field that can be tied to any arbitrary model field. The ModelField class delegates the task of serialization/deserialization to it's associated model field. This field can be used to create serializer fields for custom model fields, without having to create a new custom serializer field.

    Signature: ModelField(model_field=<Django ModelField class>)

    @@ -168,8 +199,69 @@

    Relational Fields

    Relational fields are used to represent model relationships. They can be applied to ForeignKey, ManyToManyField and OneToOneField relationships, as well as to reverse relationships, and custom relationships such as GenericForeignKey.

    +

    RelatedField

    +

    This field can be applied to any of the following:

    + +

    By default RelatedField will represent the target of the field using it's __unicode__ method.

    +

    You can customise this behaviour by subclassing ManyRelatedField, and overriding the .to_native(self, value) method.

    +

    ManyRelatedField

    +

    This field can be applied to any of the following:

    + +

    By default ManyRelatedField will represent the targets of the field using their __unicode__ method.

    +

    For example, given the following models:

    +
    class TaggedItem(models.Model):
    +    """
    +    Tags arbitrary model instances using a generic relation.
    +
    +    See: https://docs.djangoproject.com/en/dev/ref/contrib/contenttypes/
    +    """
    +    tag = models.SlugField()
    +    content_type = models.ForeignKey(ContentType)
    +    object_id = models.PositiveIntegerField()
    +    content_object = GenericForeignKey('content_type', 'object_id')
    +
    +    def __unicode__(self):
    +        return self.tag
    +
    +class Bookmark(models.Model):
    +    """
    +    A bookmark consists of a URL, and 0 or more descriptive tags.
    +    """
    +    url = models.URLField()
    +    tags = GenericRelation(TaggedItem)
    +
    +

    And a model serializer defined like this:

    +
    class BookmarkSerializer(serializers.ModelSerializer):
    +    tags = serializers.ManyRelatedField(source='tags')
    +
    +    class Meta:
    +        model = Bookmark
    +        exclude = ('id',)
    +
    +

    The an example output format for a Bookmark instance would be:

    +
    {
    +    'tags': [u'django', u'python'],
    +    'url': u'https://www.djangoproject.com/'
    +}
    +

    PrimaryKeyRelatedField

    +

    As with RelatedField field can be applied to any "to-one" relationship, such as a ForeignKey field.

    +

    PrimaryKeyRelatedField will represent the target of the field using it's primary key.

    +

    Be default, PrimaryKeyRelatedField is read-write, although you can change this behaviour using the readonly flag.

    ManyPrimaryKeyRelatedField

    +

    As with RelatedField field can be applied to any "to-many" relationship, such as a ManyToManyField field, or a reverse ForeignKey relationship.

    +

    PrimaryKeyRelatedField will represent the target of the field using their primary key.

    +

    Be default, ManyPrimaryKeyRelatedField is read-write, although you can change this behaviour using the readonly flag.

    HyperlinkedRelatedField

    ManyHyperlinkedRelatedField

    HyperLinkedIdentityField

    diff --git a/api-guide/renderers.html b/api-guide/renderers.html index 08fd1c664..04ea19185 100644 --- a/api-guide/renderers.html +++ b/api-guide/renderers.html @@ -121,8 +121,8 @@
  • JSONPRenderer
  • YAMLRenderer
  • XMLRenderer
  • -
  • DocumentingHTMLRenderer
  • -
  • HTMLTemplateRenderer
  • +
  • HTMLRenderer
  • +
  • BrowsableAPIRenderer
  • Custom renderers
  • Advanced renderer usage
  • Varying behaviour by media type
  • @@ -149,7 +149,7 @@
    REST_FRAMEWORK = {
         'DEFAULT_RENDERERS': (
             'rest_framework.renderers.YAMLRenderer',
    -        'rest_framework.renderers.DocumentingHTMLRenderer',
    +        'rest_framework.renderers.BrowsableAPIRenderer',
         )
     }
     
    @@ -194,26 +194,51 @@ def user_count_view(request, format=None):

    XMLRenderer

    .media_type: application/xml

    .format: '.xml'

    -

    DocumentingHTMLRenderer

    -

    Renders data into HTML for the browseable API. This renderer will determine which other renderer would have been given highest priority, and use that to display an API style response within the HTML page.

    -

    .media_type: text/html

    -

    .format: '.api'

    -

    HTMLTemplateRenderer

    +

    HTMLRenderer

    Renders data to HTML, using Django's standard template rendering. Unlike other renderers, the data passed to the Response does not need to be serialized. Also, unlike other renderers, you may want to include a template_name argument when creating the Response.

    -

    The HTMLTemplateRenderer will create a RequestContext, using the response.data as the context dict, and determine a template name to use to render the context.

    +

    The HTMLRenderer will create a RequestContext, using the response.data as the context dict, and determine a template name to use to render the context.

    The template name is determined by (in order of preference):

    1. An explicit .template_name attribute set on the response.
    2. An explicit .template_name attribute set on this class.
    3. The return result of calling view.get_template_names().
    -

    You can use HTMLTemplateRenderer either to return regular HTML pages using REST framework, or to return both HTML and API responses from a single endpoint.

    -

    If you're building websites that use HTMLTemplateRenderer along with other renderer classes, you should consider listing HTMLTemplateRenderer as the first class in the renderer_classes list, so that it will be prioritised first even for browsers that send poorly formed ACCEPT headers.

    +

    An example of a view that uses HTMLRenderer:

    +
    class UserInstance(generics.RetrieveUserAPIView):
    +    """
    +    A view that returns a templated HTML representations of a given user.
    +    """
    +    model = Users
    +    renderer_classes = (HTMLRenderer,)
    +
    +    def get(self, request, *args, **kwargs)
    +        self.object = self.get_object()
    +        return Response(self.object, template_name='user_detail.html')
    +
    +

    You can use HTMLRenderer either to return regular HTML pages using REST framework, or to return both HTML and API responses from a single endpoint.

    +

    If you're building websites that use HTMLRenderer along with other renderer classes, you should consider listing HTMLRenderer as the first class in the renderer_classes list, so that it will be prioritised first even for browsers that send poorly formed ACCEPT: headers.

    .media_type: text/html

    .format: '.html'

    +

    BrowsableAPIRenderer

    +

    Renders data into HTML for the Browseable API. This renderer will determine which other renderer would have been given highest priority, and use that to display an API style response within the HTML page.

    +

    .media_type: text/html

    +

    .format: '.api'

    Custom renderers

    To implement a custom renderer, you should override BaseRenderer, set the .media_type and .format properties, and implement the .render(self, data, media_type) method.

    +

    For example:

    +
    from django.utils.encoding import smart_unicode
    +from rest_framework import renderers
    +
    +class PlainText(renderers.BaseRenderer):
    +    media_type = 'text/plain'
    +    format = 'txt'
    +
    +    def render(self, data, media_type):
    +        if isinstance(data, basestring):
    +            return data
    +        return smart_unicode(data)
    +

    Advanced renderer usage

    You can do some pretty flexible things using REST framework's renderers. Some examples...

    @@ -227,7 +252,7 @@ Unlike other renderers, the data passed to the Response does not ne

    In some cases you might want your view to use different serialization styles depending on the accepted media type. If you need to do this you can access request.accepted_renderer to determine the negotiated renderer that will be used for the response.

    For example:

    @api_view(('GET',))
    -@renderer_classes((TemplateHTMLRenderer, JSONRenderer))
    +@renderer_classes((HTMLRenderer, JSONRenderer))
     def list_users(request):
         """
         A view that can return JSON or HTML representations
    diff --git a/api-guide/responses.html b/api-guide/responses.html
    index dc68e5cf8..0fcd81747 100644
    --- a/api-guide/responses.html
    +++ b/api-guide/responses.html
    @@ -151,7 +151,7 @@
     
     

    .render()

    @@ -172,7 +172,7 @@ response['Cache-Control'] = 'no-cache'

    .content

    The rendered content of the response. The .render() method must have been called before .content can be accessed.

    .template_name

    -

    The template_name, if supplied. Only required if HTMLTemplateRenderer or some other custom template renderer is the accepted renderer for the reponse.

    +

    The template_name, if supplied. Only required if HTMLRenderer or some other custom template renderer is the accepted renderer for the reponse.

    .accepted_renderer

    The renderer instance that will be used to render the response.

    Set automatically by the APIView or @api_view immediately before the response is returned from the view.

    diff --git a/api-guide/reverse.html b/api-guide/reverse.html index 05e85bb63..d3ca448f6 100644 --- a/api-guide/reverse.html +++ b/api-guide/reverse.html @@ -138,8 +138,9 @@

    REST framework provides two utility functions to make it more simple to return absolute URIs from your Web API.

    There's no requirement for you to use them, but if you do then the self-describing API will be able to automatically hyperlink it's output for you, which makes browsing the API much easier.

    reverse

    -

    Signature: reverse(viewname, request, *args, **kwargs)

    +

    Signature: reverse(viewname, *args, **kwargs)

    Has the same behavior as django.core.urlresolvers.reverse, except that it returns a fully qualified URL, using the request to determine the host and port.

    +

    You should include the request as a keyword argument to the function, for example:

    import datetime
     from rest_framework.utils import reverse
     from rest_framework.views import APIView
    @@ -149,13 +150,16 @@ class APIRootView(APIView):
             year = datetime.datetime.now().year
             data = {
                 ...
    -            'year-summary-url': reverse('year-summary', request, args=[year])
    +            'year-summary-url': reverse('year-summary', args=[year], request=request)
             }
             return Response(data)
     

    reverse_lazy

    -

    Signature: reverse_lazy(viewname, request, *args, **kwargs)

    +

    Signature: reverse_lazy(viewname, *args, **kwargs)

    Has the same behavior as django.core.urlresolvers.reverse_lazy, except that it returns a fully qualified URL, using the request to determine the host and port.

    +

    As with the reverse function, you should include the request as a keyword argument to the function, for example:

    +
    api_root = reverse_lazy('api-root', request=request)
    +
    diff --git a/api-guide/settings.html b/api-guide/settings.html index 65114fba6..6d3aad32e 100644 --- a/api-guide/settings.html +++ b/api-guide/settings.html @@ -165,7 +165,7 @@ print api_settings.DEFAULT_AUTHENTICATION

    Default:

    (
         'rest_framework.renderers.JSONRenderer',
    -    'rest_framework.renderers.DocumentingHTMLRenderer'
    +    'rest_framework.renderers.BrowsableAPIRenderer'
         'rest_framework.renderers.TemplateHTMLRenderer'
     )
     
    diff --git a/topics/rest-hypermedia-hateoas.html b/topics/rest-hypermedia-hateoas.html index 752bf7125..d7f19cb8f 100644 --- a/topics/rest-hypermedia-hateoas.html +++ b/topics/rest-hypermedia-hateoas.html @@ -125,13 +125,13 @@

    You keep using that word "REST". I do not think it means what you think it means.

    — Mike Amundsen, REST fest 2012 keynote.

    -

    First off, the disclaimer. The name "Django REST framework" was choosen with a view to making sure the project would be easily found by developers. Throughout the documentation we try to use the more simple and technically correct terminology of "Web APIs".

    +

    First off, the disclaimer. The name "Django REST framework" was choosen simply to sure the project would be easily found by developers. Throughout the documentation we try to use the more simple and technically correct terminology of "Web APIs".

    If you are serious about designing a Hypermedia APIs, you should look to resources outside of this documentation to help inform your design choices.

    The following fall into the "required reading" category.