From 08c727add37790b5a556db3fff762f4a27a5c660 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Fri, 28 Nov 2014 15:55:02 +0000 Subject: @api_view defaults to allowing GET --- docs/api-guide/views.md | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'docs/api-guide') diff --git a/docs/api-guide/views.md b/docs/api-guide/views.md index 31c62682..291fe737 100644 --- a/docs/api-guide/views.md +++ b/docs/api-guide/views.md @@ -127,19 +127,26 @@ REST framework also allows you to work with regular function based views. It pr ## @api_view() -**Signature:** `@api_view(http_method_names)` +**Signature:** `@api_view(http_method_names=['GET'])` -The core of this functionality is the `api_view` decorator, which takes a list of HTTP methods that your view should respond to. For example, this is how you would write a very simple view that just manually returns some data: +The core of this functionality is the `api_view` decorator, which takes a list of HTTP methods that your view should respond to. For example, this is how you would write a very simple view that just manually returns some data: from rest_framework.decorators import api_view - @api_view(['GET']) + @api_view() def hello_world(request): return Response({"message": "Hello, world!"}) - This view will use the default renderers, parsers, authentication classes etc specified in the [settings]. +By default only `GET` methods will be accepted. Other methods will respond with "405 Method Not Allowed". To alter this behavior, specify which methods the view allows, like so: + + @api_view(['GET', 'POST']) + def hello_world(request): + if request.method == 'POST': + return Response({"message": "Got some data!", "data": request.data}) + return Response({"message": "Hello, world!"}) + ## API policy decorators To override the default settings, REST framework provides a set of additional decorators which can be added to your views. These must come *after* (below) the `@api_view` decorator. For example, to create a view that uses a [throttle][throttling] to ensure it can only be called once per day by a particular user, use the `@throttle_classes` decorator, passing a list of throttle classes: -- cgit v1.2.3 From 555c450497e96bf8fed82fc76e70adf907c5c409 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Mon, 1 Dec 2014 14:46:47 +0000 Subject: Add missing 'validators.py' link. Closes #2166. --- docs/api-guide/validators.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs/api-guide') diff --git a/docs/api-guide/validators.md b/docs/api-guide/validators.md index f087e191..8f5a8929 100644 --- a/docs/api-guide/validators.md +++ b/docs/api-guide/validators.md @@ -1,4 +1,4 @@ - +source: validators.py --- -- cgit v1.2.3 From f4fc4670ca491eabd5bcdfcef382d8373dd5e380 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Tue, 2 Dec 2014 08:53:36 +0000 Subject: Promote 'many_init' to public API. Closes #2152. --- docs/api-guide/serializers.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'docs/api-guide') diff --git a/docs/api-guide/serializers.md b/docs/api-guide/serializers.md index 0ee80d53..4c78473e 100644 --- a/docs/api-guide/serializers.md +++ b/docs/api-guide/serializers.md @@ -689,6 +689,21 @@ Here's an example of how you might choose to implement multiple updates: It is possible that a third party package may be included alongside the 3.1 release that provides some automatic support for multiple update operations, similar to the `allow_add_remove` behavior that was present in REST framework 2. +#### Customizing ListSerializer initialization + +When a serializer with `many=True` is instantiated, we need to determine which arguments and keyword arguments should be passed to the `.__init__()` method for both the child `Serializer` class, and for the parent `ListSerializer` class. + +The default implementation is to pass all arguments to both classes, except for `validators`, and any custom keyword arguments, both of which are assumed to be intended for the child serializer class. + +Occasionally you might need to explicitly specify how the child and parent classes should be instantiated when `many=True` is passed. You can do so by using the `many_init` class method. + + @classmethod + def many_init(cls, *args, **kwargs): + # Instantiate the child serializer. + kwargs['child'] = cls() + # Instantiate the parent list serializer. + return CustomListSerializer(*args, **kwargs) + --- # BaseSerializer -- cgit v1.2.3 From 6ac79b822325784ad145ff0ad064127750c4f7e0 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Tue, 2 Dec 2014 09:19:59 +0000 Subject: Document Field.fail(). Closes #2147. --- docs/api-guide/fields.md | 49 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) (limited to 'docs/api-guide') diff --git a/docs/api-guide/fields.md b/docs/api-guide/fields.md index 391a52e5..aa5cc84e 100644 --- a/docs/api-guide/fields.md +++ b/docs/api-guide/fields.md @@ -453,7 +453,7 @@ If you want to create a custom field, you'll need to subclass `Field` and then o The `.to_representation()` method is called to convert the initial datatype into a primitive, serializable datatype. -The `to_internal_value()` method is called to restore a primitive datatype into its internal python representation. +The `to_internal_value()` method is called to restore a primitive datatype into its internal python representation. This method should raise a `serializer.ValidationError` if the data is invalid. Note that the `WritableField` class that was present in version 2.x no longer exists. You should subclass `Field` and override `to_internal_value()` if the field supports data input. @@ -498,6 +498,53 @@ As an example, let's create a field that can be used represent the class name of """ return obj.__class__.__name__ +#### Raising validation errors + +Our `ColorField` class above currently does not perform any data validation. +To indicate invalid data, we should raise a `serializers.ValidationError`, like so: + + def to_internal_value(self, data): + if not isinstance(data, six.text_type): + msg = 'Incorrect type. Expected a string, but got %s' + raise ValidationError(msg % type(data).__name__) + + if not re.match(r'^rgb\([0-9]+,[0-9]+,[0-9]+\)$', data): + raise ValidationError('Incorrect format. Expected `rgb(#,#,#)`.') + + data = data.strip('rgb(').rstrip(')') + red, green, blue = [int(col) for col in data.split(',')] + + if any([col > 255 or col < 0 for col in (red, green, blue)]): + raise ValidationError('Value out of range. Must be between 0 and 255.') + + return Color(red, green, blue) + +The `.fail()` method is a shortcut for raising `ValidationError` that takes a message string from the `error_messages` dictionary. For example: + + default_error_messages = { + 'incorrect_type': 'Incorrect type. Expected a string, but got {input_type}', + 'incorrect_format': 'Incorrect format. Expected `rgb(#,#,#)`.', + 'out_of_range': 'Value out of range. Must be between 0 and 255.' + } + + def to_internal_value(self, data): + if not isinstance(data, six.text_type): + msg = 'Incorrect type. Expected a string, but got %s' + self.fail('incorrect_type', input_type=type(data).__name__) + + if not re.match(r'^rgb\([0-9]+,[0-9]+,[0-9]+\)$', data): + self.fail('incorrect_format') + + data = data.strip('rgb(').rstrip(')') + red, green, blue = [int(col) for col in data.split(',')] + + if any([col > 255 or col < 0 for col in (red, green, blue)]): + self.fail('out_of_range') + + return Color(red, green, blue) + +This style keeps you error messages more cleanly separated from your code, and should be preferred. + # Third party packages The following third party packages are also available. -- cgit v1.2.3 From 84cff98fbf72355cb5e8359aa1c9b5568c289cbf Mon Sep 17 00:00:00 2001 From: David Ray Date: Tue, 2 Dec 2014 09:46:43 -0500 Subject: fix typo --- docs/api-guide/serializers.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs/api-guide') diff --git a/docs/api-guide/serializers.md b/docs/api-guide/serializers.md index 4c78473e..a011bb52 100644 --- a/docs/api-guide/serializers.md +++ b/docs/api-guide/serializers.md @@ -96,7 +96,7 @@ If we want to be able to return complete object instances based on the validated If your object instances correspond to Django models you'll also want to ensure that these methods save the object to the database. For example, if `Comment` was a Django model, the methods might look like this: def create(self, validated_data): - return Comment.objcts.create(**validated_data) + return Comment.objects.create(**validated_data) def update(self, instance, validated_data): instance.email = validated_data.get('email', instance.email) -- cgit v1.2.3 From 5ad22aea605f888e06186d907674669c46a611ef Mon Sep 17 00:00:00 2001 From: Matías Lang Date: Tue, 2 Dec 2014 12:23:25 -0300 Subject: Updated serializers documentation There was an error in the docs: the field extra_field_kwargs of the serializer's Meta doesn't work. The field must be extra_kwargs instead.--- docs/api-guide/serializers.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'docs/api-guide') diff --git a/docs/api-guide/serializers.md b/docs/api-guide/serializers.md index a011bb52..1779c863 100644 --- a/docs/api-guide/serializers.md +++ b/docs/api-guide/serializers.md @@ -567,13 +567,13 @@ There needs to be a way of determining which views should be used for hyperlinki By default hyperlinks are expected to correspond to a view name that matches the style `'{model_name}-detail'`, and looks up the instance by a `pk` keyword argument. -You can override a URL field view name and lookup field by using either, or both of, the `view_name` and `lookup_field` options in the `extra_field_kwargs` setting, like so: +You can override a URL field view name and lookup field by using either, or both of, the `view_name` and `lookup_field` options in the `extra_kwargs` setting, like so: class AccountSerializer(serializers.HyperlinkedModelSerializer): class Meta: model = Account fields = ('account_url', 'account_name', 'users', 'created') - extra_field_kwargs = { + extra_kwargs = { 'url': {'view_name': 'accounts', 'lookup_field': 'account_name'} 'users': {'lookup_field': 'username'} } -- cgit v1.2.3 From 71e1a3942e7945fe4d8da4c44b4ba2100a2c67de Mon Sep 17 00:00:00 2001 From: Carlton Gibson Date: Thu, 4 Dec 2014 12:15:14 +0100 Subject: Initial link from Serializers to Validators --- docs/api-guide/serializers.md | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) (limited to 'docs/api-guide') diff --git a/docs/api-guide/serializers.md b/docs/api-guide/serializers.md index 1779c863..69fc1857 100644 --- a/docs/api-guide/serializers.md +++ b/docs/api-guide/serializers.md @@ -104,7 +104,7 @@ If your object instances correspond to Django models you'll also want to ensure instance.created = validated_data.get('created', instance.created) instance.save() return instance - + Now when deserializing data, we can call `.save()` to return an object instance, based on the validated data. comment = serializer.save() @@ -113,7 +113,7 @@ Calling `.save()` will either create a new instance, or update an existing insta # .save() will create a new instance. serializer = CommentSerializer(data=data) - + # .save() will update the existing `comment` instance. serializer = CommentSerializer(comment, data=data) @@ -140,7 +140,7 @@ For example: class ContactForm(serializers.Serializer): email = serializers.EmailField() message = serializers.CharField() - + def save(self): email = self.validated_data['email'] message = self.validated_data['message'] @@ -230,7 +230,7 @@ Serializer classes can also include reusable validators that are applied to the name = serializers.CharField() room_number = serializers.IntegerField(choices=[101, 102, 103, 201]) date = serializers.DateField() - + class Meta: # Each room only has one event per day. validators = UniqueTogetherValidator( @@ -448,7 +448,7 @@ To do so, open the Django shell, using `python manage.py shell`, then import the id = IntegerField(label='ID', read_only=True) name = CharField(allow_blank=True, max_length=100, required=False) owner = PrimaryKeyRelatedField(queryset=User.objects.all()) - + ## Specifying which fields should be included If you only want a subset of the default fields to be used in a model serializer, you can do so using `fields` or `exclude` options, just as you would with a `ModelForm`. @@ -505,6 +505,19 @@ This option should be a list or tuple of field names, and is declared as follows Model fields which have `editable=False` set, and `AutoField` fields will be set to read-only by default, and do not need to be added to the `read_only_fields` option. +--- + +**Note**: There is a special-case where a read-only field is part of a `unique_together` constraint at the model level. Here you **must** specify the field explicitly and provide a valid default value. + +A common example of this is a read-only relation to currently authenticated `User` which is `unique_together` with another identifier. In this case you would declare the user field like so: + + user = serializers.PrimaryKeyRelatedField(read_only=True, default=serializers.CurrentUserDefault()) + +Please review the [Validators Documentation](/api-guide/validators/) for details on the [UniqueTogetherValidator](/api-guide/validators/#uniquetogethervalidator) and [CurrentUserDefault](/api-guide/validators/#currentuserdefault) classes. + +--- + + ## Specifying additional keyword arguments for fields. There is also a shortcut allowing you to specify arbitrary additional keyword arguments on fields, using the `extra_kwargs` option. Similarly to `read_only_fields` this means you do not need to explicitly declare the field on the serializer. @@ -516,7 +529,7 @@ This option is a dictionary, mapping field names to a dictionary of keyword argu model = User fields = ('email', 'username', 'password') extra_kwargs = {'password': {'write_only': True}} - + def create(self, validated_data): user = User( email=validated_data['email'], @@ -656,7 +669,7 @@ To support multiple updates you'll need to do so explicitly. When writing your m * How do you determine which instance should be updated for each item in the list of data? * How should insertions be handled? Are they invalid, or do they create new objects? * How should removals be handled? Do they imply object deletion, or removing a relationship? Should they be silently ignored, or are they invalid? -* How should ordering be handled? Does changing the position of two items imply any state change or is it ignored? +* How should ordering be handled? Does changing the position of two items imply any state change or is it ignored? Here's an example of how you might choose to implement multiple updates: -- cgit v1.2.3 From 6ee361332b09f148f86149a7d9a6220bd61966e8 Mon Sep 17 00:00:00 2001 From: Carlton Gibson Date: Thu, 4 Dec 2014 14:15:01 +0100 Subject: Add missing definite article --- docs/api-guide/serializers.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs/api-guide') diff --git a/docs/api-guide/serializers.md b/docs/api-guide/serializers.md index 69fc1857..79db275f 100644 --- a/docs/api-guide/serializers.md +++ b/docs/api-guide/serializers.md @@ -509,7 +509,7 @@ Model fields which have `editable=False` set, and `AutoField` fields will be set **Note**: There is a special-case where a read-only field is part of a `unique_together` constraint at the model level. Here you **must** specify the field explicitly and provide a valid default value. -A common example of this is a read-only relation to currently authenticated `User` which is `unique_together` with another identifier. In this case you would declare the user field like so: +A common example of this is a read-only relation to the currently authenticated `User` which is `unique_together` with another identifier. In this case you would declare the user field like so: user = serializers.PrimaryKeyRelatedField(read_only=True, default=serializers.CurrentUserDefault()) -- cgit v1.2.3 From 9fb1b396db751234a531dabacb6758ac2645776c Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Fri, 5 Dec 2014 13:07:31 +0000 Subject: user in example should have been instance. Closees #2191. --- docs/api-guide/serializers.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'docs/api-guide') diff --git a/docs/api-guide/serializers.md b/docs/api-guide/serializers.md index 1779c863..ab44839f 100644 --- a/docs/api-guide/serializers.md +++ b/docs/api-guide/serializers.md @@ -326,9 +326,9 @@ Here's an example for an `update()` method on our previous `UserSerializer` clas # would need to be handled. profile = instance.profile - user.username = validated_data.get('username', instance.username) - user.email = validated_data.get('email', instance.email) - user.save() + instance.username = validated_data.get('username', instance.username) + instance.email = validated_data.get('email', instance.email) + instance.save() profile.is_premium_member = profile_data.get( 'is_premium_member', @@ -340,7 +340,7 @@ Here's an example for an `update()` method on our previous `UserSerializer` clas ) profile.save() - return user + return instance Because the behavior of nested creates and updates can be ambiguous, and may require complex dependancies between related models, REST framework 3 requires you to always write these methods explicitly. The default `ModelSerializer` `.create()` and `.update()` methods do not include support for writable nested representations. -- cgit v1.2.3 From 59b2ad542580eb93243c4403ded4c2b4dc8518c2 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Fri, 5 Dec 2014 13:23:14 +0000 Subject: Minor docs tweaks --- docs/api-guide/serializers.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'docs/api-guide') diff --git a/docs/api-guide/serializers.md b/docs/api-guide/serializers.md index 1f97614d..5fe6b4c2 100644 --- a/docs/api-guide/serializers.md +++ b/docs/api-guide/serializers.md @@ -507,9 +507,11 @@ Model fields which have `editable=False` set, and `AutoField` fields will be set --- -**Note**: There is a special-case where a read-only field is part of a `unique_together` constraint at the model level. Here you **must** specify the field explicitly and provide a valid default value. +**Note**: There is a special-case where a read-only field is part of a `unique_together` constraint at the model level. In this case the field is required by the serializer class in order to validate the constraint, but should also not be editable by the user. -A common example of this is a read-only relation to the currently authenticated `User` which is `unique_together` with another identifier. In this case you would declare the user field like so: +The right way to deal with this is to specify the field explicitly on the serializer, providing both the `read_only=True` and `default=…` keyword arguments. + +One example of this is a read-only relation to the currently authenticated `User` which is `unique_together` with another identifier. In this case you would declare the user field like so: user = serializers.PrimaryKeyRelatedField(read_only=True, default=serializers.CurrentUserDefault()) -- cgit v1.2.3 From 9b468fba60def77144949628211aac95c6316c70 Mon Sep 17 00:00:00 2001 From: Mark Henwood Date: Sun, 7 Dec 2014 11:57:07 +0000 Subject: Amend ViewSet docs to warn of potential problem I went through this exact problem and so thought the docs might benefit from a small hint at the appropriate point. --- docs/api-guide/viewsets.md | 3 +++ 1 file changed, 3 insertions(+) (limited to 'docs/api-guide') diff --git a/docs/api-guide/viewsets.md b/docs/api-guide/viewsets.md index 28186c64..3e37cef8 100644 --- a/docs/api-guide/viewsets.md +++ b/docs/api-guide/viewsets.md @@ -201,6 +201,8 @@ Note that you can use any of the standard attributes or method overrides provide def get_queryset(self): return self.request.user.accounts.all() +Note however that upon removal of the `queryset` property from your `ViewSet`, any associated [router][routers] will be unable to derive the base_name of your Model automatically, and so you you will have to specify the `base_name` kwarg as part of your [router registration][routers]. + Also note that although this class provides the complete set of create/list/retrieve/update/destroy actions by default, you can restrict the available operations by using the standard permission classes. ## ReadOnlyModelViewSet @@ -243,3 +245,4 @@ To create a base viewset class that provides `create`, `list` and `retrieve` ope By creating your own base `ViewSet` classes, you can provide common behavior that can be reused in multiple viewsets across your API. [cite]: http://guides.rubyonrails.org/routing.html +[routers]: routers.md -- cgit v1.2.3 From f5b783af617f507efbc0d5ede0d27bd6be903d63 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Tue, 9 Dec 2014 14:21:31 +0000 Subject: allow_blank in ChoiceField. Refs #2239. --- docs/api-guide/fields.md | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'docs/api-guide') diff --git a/docs/api-guide/fields.md b/docs/api-guide/fields.md index aa5cc84e..e4ef1d4a 100644 --- a/docs/api-guide/fields.md +++ b/docs/api-guide/fields.md @@ -310,6 +310,9 @@ Used by `ModelSerializer` to automatically generate fields if the corresponding **Signature:** `ChoiceField(choices)` - `choices` - A list of valid values, or a list of `(key, display_name)` tuples. +- `allow_blank` - If set to `True` then the empty string should be considered a valid value. If set to `False` then the empty string is considered invalid and will raise a validation error. Defaults to `False`. + +Both the `allow_blank` and `allow_null` are valid options on `ChoiceField`, although it is highly recommended that you only use one and not both. `allow_blank` should be preferred for textual choices, and `allow_null` should be preferred for numeric or other non-textual choices. ## MultipleChoiceField @@ -318,6 +321,9 @@ A field that can accept a set of zero, one or many values, chosen from a limited **Signature:** `MultipleChoiceField(choices)` - `choices` - A list of valid values, or a list of `(key, display_name)` tuples. +- `allow_blank` - If set to `True` then the empty string should be considered a valid value. If set to `False` then the empty string is considered invalid and will raise a validation error. Defaults to `False`. + +As with `ChoiceField`, both the `allow_blank` and `allow_null` options are valid, although it is highly recommended that you only use one and not both. `allow_blank` should be preferred for textual choices, and `allow_null` should be preferred for numeric or other non-textual choices. --- -- cgit v1.2.3