Merge tag '3.3.2'

version 3.3.2
This commit is contained in:
Thomas NOËL 2016-03-04 17:27:18 +01:00
commit e349f3db43
312 changed files with 18026 additions and 5237 deletions

1
.gitignore vendored
View File

@ -14,3 +14,4 @@ MANIFEST
!.gitignore
!.travis.yml
!.isort.cfg

7
.isort.cfg Normal file
View File

@ -0,0 +1,7 @@
[settings]
skip=.tox
atomic=true
multi_line_output=5
known_standard_library=types
known_third_party=pytest,django
known_first_party=rest_framework

View File

@ -3,8 +3,11 @@ language: python
sudo: false
env:
- TOX_ENV=py27-flake8
- TOX_ENV=py27-lint
- TOX_ENV=py27-docs
- TOX_ENV=py35-django19
- TOX_ENV=py34-django19
- TOX_ENV=py27-django19
- TOX_ENV=py34-django18
- TOX_ENV=py33-django18
- TOX_ENV=py32-django18
@ -13,33 +16,19 @@ env:
- TOX_ENV=py33-django17
- TOX_ENV=py32-django17
- TOX_ENV=py27-django17
- TOX_ENV=py34-django16
- TOX_ENV=py33-django16
- TOX_ENV=py32-django16
- TOX_ENV=py27-django16
- TOX_ENV=py26-django16
- TOX_ENV=py34-django15
- TOX_ENV=py33-django15
- TOX_ENV=py32-django15
- TOX_ENV=py27-django15
- TOX_ENV=py26-django15
- TOX_ENV=py27-django14
- TOX_ENV=py26-django14
- TOX_ENV=py27-djangomaster
- TOX_ENV=py32-djangomaster
- TOX_ENV=py33-djangomaster
- TOX_ENV=py34-djangomaster
matrix:
# Python 3.5 not yet available on travis, watch this to see when it is.
fast_finish: true
allow_failures:
- env: TOX_ENV=py27-djangomaster
- env: TOX_ENV=py32-djangomaster
- env: TOX_ENV=py33-djangomaster
- env: TOX_ENV=py34-djangomaster
- env: TOX_ENV=py35-django19
install:
- pip install tox
script:
- tox -e $TOX_ENV
after_success:
- pip install codecov
- codecov -e TOX_ENV

View File

@ -38,7 +38,7 @@ Some tips on good issue reporting:
## Triaging issues
Getting involved in triaging incoming issues is a good way to start contributing. Every single ticket that comes into the ticket tracker needs to be reviewed in order to determine what the next steps should be. Anyone can help out with this, you just need to be willing to
Getting involved in triaging incoming issues is a good way to start contributing. Every single ticket that comes into the ticket tracker needs to be reviewed in order to determine what the next steps should be. Anyone can help out with this, you just need to be willing to:
* Read through the ticket - does it make sense, is it missing any context that would help explain it better?
* Is the ticket reported in the correct place, would it be better suited as a discussion on the discussion group?

View File

@ -1,6 +1,7 @@
# [Django REST framework][docs]
[![build-status-image]][travis]
[![coverage-status-image]][codecov]
[![pypi-version]][pypi]
**Awesome web-browsable Web APIs.**
@ -9,9 +10,9 @@ Full documentation for the project is available at [http://www.django-rest-frame
---
**Note**: We have now released Django REST framework 3.1. For older codebases you may want to refer to the version 2.4.4 [source code](https://github.com/tomchristie/django-rest-framework/tree/version-2.4.x), and [documentation](http://tomchristie.github.io/rest-framework-2-docs/).
**Note**: We have now released Django REST framework 3.3. For older codebases you may want to refer to the version 2.4.4 [source code][2.4-code], and [documentation][2.4-docs].
For more details see the [3.1 release notes][3.1-announcement]
For more details see the 3.3 [announcement][3.3-announcement] and [release notes][3.3-release-notes].
---
@ -35,8 +36,8 @@ There is a live example API for testing purposes, [available here][sandbox].
# Requirements
* Python (2.6.5+, 2.7, 3.2, 3.3, 3.4)
* Django (1.4.11+, 1.5.6+, 1.6.3+, 1.7, 1.8)
* Python (2.7, 3.2, 3.3, 3.4, 3.5)
* Django (1.7, 1.8, 1.9)
# Installation
@ -156,9 +157,10 @@ If you believe youve found something in Django REST framework which has secur
Send a description of the issue via email to [rest-framework-security@googlegroups.com][security-mail]. The project maintainers will then work with you to resolve any issues where required, prior to any public disclosure.
[build-status-image]: https://secure.travis-ci.org/tomchristie/django-rest-framework.svg?branch=master
[travis]: http://travis-ci.org/tomchristie/django-rest-framework?branch=master
[coverage-status-image]: https://img.shields.io/codecov/c/github/tomchristie/django-rest-framework/master.svg
[codecov]: http://codecov.io/github/tomchristie/django-rest-framework?branch=master
[pypi-version]: https://img.shields.io/pypi/v/djangorestframework.svg
[pypi]: https://pypi.python.org/pypi/djangorestframework
[twitter]: https://twitter.com/_tomchristie
@ -179,4 +181,7 @@ Send a description of the issue via email to [rest-framework-security@googlegrou
[docs]: http://www.django-rest-framework.org/
[security-mail]: mailto:rest-framework-security@googlegroups.com
[3.1-announcement]: http://www.django-rest-framework.org/topics/3.1-announcement/
[2.4-code]: https://github.com/tomchristie/django-rest-framework/tree/version-2.4.x
[2.4-docs]: http://tomchristie.github.io/rest-framework-2-docs/
[3.3-announcement]: http://www.django-rest-framework.org/topics/3.3-announcement/
[3.3-release-notes]: http://www.django-rest-framework.org/topics/release-notes/#33x-series

View File

@ -360,6 +360,14 @@ HTTP Signature (currently a [IETF draft][http-signature-ietf-draft]) provides a
[Django-rest-auth][django-rest-auth] library provides a set of REST API endpoints for registration, authentication (including social media authentication), password reset, retrieve and update user details, etc. By having these API endpoints, your client apps such as AngularJS, iOS, Android, and others can communicate to your Django backend site independently via REST APIs for user management.
## django-rest-framework-social-oauth2
[Django-rest-framework-social-oauth2][django-rest-framework-social-oauth2] library provides an easy way to integrate social plugins (facebook, twitter, google, etc.) to your authentication system and an easy oauth2 setup. With this library, you will be able to authenticate users based on external tokens (e.g. facebook access token), convert these tokens to "in-house" oauth2 tokens and use and generate oauth2 tokens to authenticate your users.
## django-rest-knox
[Django-rest-knox][django-rest-knox] library provides models and views to handle token based authentication in a more secure and extensible way than the built-in TokenAuthentication scheme - with Single Page Applications and Mobile clients in mind. It provides per-client tokens, and views to generate them when provided some other authentication (usually basic authentication), to delete the token (providing a server enforced logout) and to delete all tokens (logs out all clients that a user is logged into).
[cite]: http://jacobian.org/writing/rest-worst-practices/
[http401]: http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.2
[http403]: http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.4
@ -400,3 +408,5 @@ HTTP Signature (currently a [IETF draft][http-signature-ietf-draft]) provides a
[mac]: http://tools.ietf.org/html/draft-hammer-oauth-v2-mac-token-05
[djoser]: https://github.com/sunscrapers/djoser
[django-rest-auth]: https://github.com/Tivix/django-rest-auth
[django-rest-framework-social-oauth2]: https://github.com/PhilipGarnero/django-rest-framework-social-oauth2
[django-rest-knox]: https://github.com/James1345/django-rest-knox

View File

@ -20,6 +20,8 @@ Each serializer field class constructor takes at least these arguments. Some Fi
### `read_only`
Read-only fields are included in the API output, but should not be included in the input during create or update operations. Any 'read_only' fields that are incorrectly included in the serializer input will be ignored.
Set this to `True` to ensure that the field is used when serializing a representation, but is not used when creating or updating an instance during deserialization.
Defaults to `False`
@ -49,13 +51,13 @@ Defaults to `False`
If set, this gives the default value that will be used for the field if no input value is supplied. If not set the default behavior is to not populate the attribute at all.
May be set to a function or other callable, in which case the value will be evaluated each time it is used.
May be set to a function or other callable, in which case the value will be evaluated each time it is used. When called, it will receive no arguments. If the callable has a `set_context` method, that will be called each time before getting the value with the field instance as only argument. This works the same way as for [validators](validators.md#using-set_context).
Note that setting a `default` value implies that the field is not required. Including both the `default` and `required` keyword arguments is invalid and will raise an error.
### `source`
The name of the attribute that will be used to populate the field. May be a method that only takes a `self` argument, such as `URLField('get_absolute_url')`, or may use dotted notation to traverse attributes, such as `EmailField(source='user.email')`.
The name of the attribute that will be used to populate the field. May be a method that only takes a `self` argument, such as `URLField(source='get_absolute_url')`, or may use dotted notation to traverse attributes, such as `EmailField(source='user.email')`.
The value `source='*'` has a special meaning, and is used to indicate that the entire object should be passed through to the field. This can be useful for creating nested representations, or for fields which require access to the complete object in order to determine the output representation.
@ -83,9 +85,9 @@ A value that should be used for pre-populating the value of HTML form fields.
### `style`
A dictionary of key-value pairs that can be used to control how renderers should render the field. The API for this should still be considered experimental, and will be formalized with the 3.1 release.
A dictionary of key-value pairs that can be used to control how renderers should render the field.
Two options are currently used in HTML form generation, `'input_type'` and `'base_template'`.
Two examples here are `'input_type'` and `'base_template'`:
# Use <input type="password"> for the input.
password = serializers.CharField(
@ -98,7 +100,7 @@ Two options are currently used in HTML form generation, `'input_type'` and `'bas
style = {'base_template': 'radio.html'}
}
**Note**: The `style` argument replaces the old-style version 2.x `widget` keyword argument. Because REST framework 3 now uses templated HTML form generation, the `widget` option that was used to support Django built-in widgets can no longer be supported. Version 3.1 is planned to include public API support for customizing HTML form generation.
For more details see the [HTML & Forms][html-and-forms] documentation.
---
@ -192,6 +194,20 @@ A field that ensures the input is a valid UUID string. The `to_internal_value` m
- `'urn'` - RFC 4122 URN representation of the UUID: `"urn:uuid:5ce0e9a5-5ffa-654b-cee0-1238041fb31a"`
Changing the `format` parameters only affects representation values. All formats are accepted by `to_internal_value`
## FilePathField
A field whose choices are limited to the filenames in a certain directory on the filesystem
Corresponds to `django.forms.fields.FilePathField`.
**Signature:** `FilePathField(path, match=None, recursive=False, allow_files=True, allow_folders=False, required=None, **kwargs)`
- `path` - The absolute filesystem path to a directory from which this FilePathField should get its choice.
- `match` - A regular expression, as a string, that FilePathField will use to filter filenames.
- `recursive` - Specifies whether all subdirectories of path should be included. Default is `False`.
- `allow_files` - Specifies whether files in the specified location should be included. Default is `True`. Either this or `allow_folders` must be `True`.
- `allow_folders` - Specifies whether folders in the specified location should be included. Default is `False`. Either this or `allow_files` must be `True`.
## IPAddressField
A field that ensures the input is a valid IPv4 or IPv6 string.
@ -348,6 +364,8 @@ Used by `ModelSerializer` to automatically generate fields if the corresponding
- `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`.
- `html_cutoff` - If set this will be the maximum number of choices that will be displayed by a HTML select drop down. Can be used to ensure that automatically generated ChoiceFields with very large possible selections do not prevent a template from rendering. Defaults to `None`.
- `html_cutoff_text` - If set this will display a textual indicator if the maximum number of items have been cutoff in an HTML select drop down. Defaults to `"More than {count} items…"`
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.
@ -359,6 +377,8 @@ A field that can accept a set of zero, one or many values, chosen from a limited
- `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`.
- `html_cutoff` - If set this will be the maximum number of choices that will be displayed by a HTML select drop down. Can be used to ensure that automatically generated ChoiceFields with very large possible selections do not prevent a template from rendering. Defaults to `None`.
- `html_cutoff_text` - If set this will display a textual indicator if the maximum number of items have been cutoff in an HTML select drop down. Defaults to `"More than {count} items…"`
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.
@ -439,6 +459,14 @@ You can also use the declarative style, as with `ListField`. For example:
class DocumentField(DictField):
child = CharField()
## JSONField
A field class that validates that the incoming data structure consists of valid JSON primitives. In its alternate binary mode, it will represent and validate JSON-encoded binary strings.
**Signature**: `JSONField(binary)`
- `binary` - If set to `True` then the field will output and validate a JSON encoded string, rather than a primitive data structure. Defaults to `False`.
---
# Miscellaneous fields
@ -544,7 +572,7 @@ Let's look at an example of serializing a class that represents an RGB color val
By default field values are treated as mapping to an attribute on the object. If you need to customize how the field value is accessed and set you need to override `.get_attribute()` and/or `.get_value()`.
As an example, let's create a field that can be used represent the class name of the object being serialized:
As an example, let's create a field that can be used to represent the class name of the object being serialized:
class ClassNameField(serializers.Field):
def get_attribute(self, obj):
@ -630,6 +658,7 @@ The [django-rest-framework-gis][django-rest-framework-gis] package provides geog
The [django-rest-framework-hstore][django-rest-framework-hstore] package provides an `HStoreField` to support [django-hstore][django-hstore] `DictionaryField` model field.
[cite]: https://docs.djangoproject.com/en/dev/ref/forms/api/#django.forms.Form.cleaned_data
[html-and-forms]: ../topics/html-and-forms.md
[FILE_UPLOAD_HANDLERS]: https://docs.djangoproject.com/en/dev/ref/settings/#std:setting-FILE_UPLOAD_HANDLERS
[ecma262]: http://ecma-international.org/ecma-262/5.1/#sec-15.9.1.15
[strftime]: http://docs.python.org/2/library/datetime.html#strftime-and-strptime-behavior

View File

@ -83,6 +83,10 @@ We can override `.get_queryset()` to deal with URLs such as `http://example.com/
As well as being able to override the default queryset, REST framework also includes support for generic filtering backends that allow you to easily construct complex searches and filters.
Generic filters can also present themselves as HTML controls in the browsable API and admin API.
![Filter Example](../img/filter-controls.png)
## Setting filter backends
The default filter backends may be set globally, using the `DEFAULT_FILTER_BACKENDS` setting. For example.
@ -95,9 +99,9 @@ You can also set the filter backends on a per-view, or per-viewset basis,
using the `GenericAPIView` class based views.
from django.contrib.auth.models import User
from myapp.serializers import UserSerializer
from myapp.serializers import UserSerializer
from rest_framework import filters
from rest_framework import generics
from rest_framework import generics
class UserListView(generics.ListAPIView):
queryset = User.objects.all()
@ -141,6 +145,13 @@ To use REST framework's `DjangoFilterBackend`, first install `django-filter`.
pip install django-filter
If you are using the browsable API or admin API you may also want to install `django-crispy-forms`, which will enhance the presentation of the filter forms in HTML views, by allowing them to render Bootstrap 3 HTML.
pip install django-crispy-forms
With crispy forms installed and added to Django's `INSTALLED_APPS`, the browsable API will present a filtering control for `DjangoFilterBackend`, like so:
![Django Filter](../img/django-filter.png)
#### Specifying filter fields
@ -149,6 +160,7 @@ If all you need is simple equality-based filtering, you can set a `filter_fields
class ProductList(generics.ListAPIView):
queryset = Product.objects.all()
serializer_class = ProductSerializer
filter_backends = (filters.DjangoFilterBackend,)
filter_fields = ('category', 'in_stock')
This will automatically create a `FilterSet` class for the given fields, and will allow you to make requests such as:
@ -162,6 +174,7 @@ For more advanced filtering requirements you can specify a `FilterSet` class tha
import django_filters
from myapp.models import Product
from myapp.serializers import ProductSerializer
from rest_framework import filters
from rest_framework import generics
class ProductFilter(django_filters.FilterSet):
@ -174,6 +187,7 @@ For more advanced filtering requirements you can specify a `FilterSet` class tha
class ProductList(generics.ListAPIView):
queryset = Product.objects.all()
serializer_class = ProductSerializer
filter_backends = (filters.DjangoFilterBackend,)
filter_class = ProductFilter
@ -234,6 +248,10 @@ For more details on using filter sets see the [django-filter documentation][djan
The `SearchFilter` class supports simple single query parameter based searching, and is based on the [Django admin's search functionality][search-django-admin].
When in use, the browsable API will include a `SearchFilter` control:
![Search Filter](../img/search-filter.png)
The `SearchFilter` class will only be applied if the view has a `search_fields` attribute set. The `search_fields` attribute should be a list of names of text type fields on the model, such as `CharField` or `TextField`.
class UserListView(generics.ListAPIView):
@ -257,6 +275,7 @@ The search behavior may be restricted by prepending various characters to the `s
* '^' Starts-with search.
* '=' Exact matches.
* '@' Full-text search. (Currently only supported Django's MySQL backend.)
* '$' Regex search.
For example:
@ -270,7 +289,11 @@ For more details, see the [Django documentation][search-django-admin].
## OrderingFilter
The `OrderingFilter` class supports simple query parameter controlled ordering of results. By default, the query parameter is named `'ordering'`, but this may by overridden with the `ORDERING_PARAM` setting.
The `OrderingFilter` class supports simple query parameter controlled ordering of results.
![Ordering Filter](../img/ordering-filter.png)
By default, the query parameter is named `'ordering'`, but this may by overridden with the `ORDERING_PARAM` setting.
For example, to order users by username:
@ -327,8 +350,6 @@ The `ordering` attribute may be either a string or a list/tuple of strings.
The `DjangoObjectPermissionsFilter` is intended to be used together with the [`django-guardian`][guardian] package, with custom `'view'` permissions added. The filter will ensure that querysets only returns objects for which the user has the appropriate view permission.
This filter class must be used with views that provide either a `queryset` or a `model` attribute.
If you're using `DjangoObjectPermissionsFilter`, you'll probably also want to add an appropriate object permissions class, to ensure that users can only operate on instances if they have the appropriate object permissions. The easiest way to do this is to subclass `DjangoObjectPermissions` and add `'view'` permissions to the `perms_map` attribute.
A complete example using both `DjangoObjectPermissionsFilter` and `DjangoObjectPermissions` might look something like this.
@ -387,6 +408,14 @@ For example, you might need to restrict users to only being able to see objects
We could achieve the same behavior by overriding `get_queryset()` on the views, but using a filter backend allows you to more easily add this restriction to multiple views, or to apply it across the entire API.
## Customizing the interface
Generic filters may also present an interface in the browsable API. To do so you should implement a `to_html()` method which returns a rendered HTML representation of the filter. This method should have the following signature:
`to_html(self, request, queryset, view)`
The method should return a rendered HTML string.
# Third party packages
The following third party packages provide additional filter implementations.
@ -399,6 +428,10 @@ The [django-rest-framework-filters package][django-rest-framework-filters] works
The [djangorestframework-word-filter][django-rest-framework-word-search-filter] developed as alternative to `filters.SearchFilter` which will search full word in text, or exact match.
## Django URL Filter
[django-url-filter][django-url-filter] provides a safe way to filter data via human-friendly URLs. It works very similar to DRF serializers and fields in a sense that they can be nested except they are called filtersets and filters. That provides easy way to filter related data. Also this library is generic-purpose so it can be used to filter other sources of data and not only Django `QuerySet`s.
[cite]: https://docs.djangoproject.com/en/dev/topics/db/queries/#retrieving-specific-objects-with-filters
[django-filter]: https://github.com/alex/django-filter
[django-filter-docs]: https://django-filter.readthedocs.org/en/latest/index.html
@ -409,3 +442,4 @@ The [djangorestframework-word-filter][django-rest-framework-word-search-filter]
[search-django-admin]: https://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.search_fields
[django-rest-framework-filters]: https://github.com/philipn/django-rest-framework-filters
[django-rest-framework-word-search-filter]: https://github.com/trollknurr/django-rest-framework-word-search-filter
[django-url-filter]: https://github.com/miki725/django-url-filter

View File

@ -69,6 +69,16 @@ If using the `i18n_patterns` function provided by Django, as well as `format_suf
---
## Query parameter formats
An alternative to the format suffixes is to include the requested format in a query parameter. REST framework provides this option by default, and it is used in the browsable API to switch between differing available representations.
To select a representation using its short format, use the `format` query parameter. For example: `http://example.com/organizations/?format=csv`.
The name of this query parameter can be modified using the `URL_FORMAT_OVERRIDE` setting. Set the value to `None` to disable this behavior.
---
## Accept headers vs. format suffixes
There seems to be a view among some of the Web community that filename extensions are not a RESTful pattern, and that `HTTP Accept` headers should always be used instead.

View File

@ -35,14 +35,6 @@ For more complex cases you might also want to override various methods on the vi
serializer_class = UserSerializer
permission_classes = (IsAdminUser,)
def get_paginate_by(self):
"""
Use smaller pagination for HTML representations.
"""
if self.request.accepted_renderer.format == 'html':
return 20
return 100
def list(self, request):
# Note the use of `get_queryset()` instead of `self.queryset`
queryset = self.get_queryset()
@ -124,21 +116,24 @@ For example:
Note that if your API doesn't include any object level permissions, you may optionally exclude the `self.check_object_permissions`, and simply return the object from the `get_object_or_404` lookup.
#### `get_filter_backends(self)`
#### `filter_queryset(self, queryset)`
Returns the classes that should be used to filter the queryset. Defaults to returning the `filter_backends` attribute.
Given a queryset, filter it with whichever filter backends are in use, returning a new queryset.
May be overridden to provide more complex behavior with filters, such as using different (or even exclusive) lists of filter_backends depending on different criteria.
For example:
For example:
def filter_queryset(self, queryset):
filter_backends = (CategoryFilter,)
def get_filter_backends(self):
if "geo_route" in self.request.query_params:
return (GeoRouteFilter, CategoryFilter)
elif "geo_point" in self.request.query_params:
return (GeoPointFilter, CategoryFilter)
if 'geo_route' in self.request.query_params:
filter_backends = (GeoRouteFilter, CategoryFilter)
elif 'geo_point' in self.request.query_params:
filter_backends = (GeoPointFilter, CategoryFilter)
return (CategoryFilter,)
for backend in list(filter_backends):
queryset = backend().filter_queryset(self.request, queryset, view=self)
return queryset
#### `get_serializer_class(self)`
@ -153,19 +148,6 @@ For example:
return FullAccountSerializer
return BasicAccountSerializer
#### `get_paginate_by(self)`
Returns the page size to use with pagination. By default this uses the `paginate_by` attribute, and may be overridden by the client if the `paginate_by_param` attribute is set.
You may want to override this method to provide more complex behavior, such as modifying page sizes based on the media type of the response.
For example:
def get_paginate_by(self):
if self.request.accepted_renderer.format == 'html':
return 20
return 100
**Save and deletion hooks**:
The following methods are provided by the mixin classes, and provide easy overriding of the object save or deletion behavior.
@ -185,6 +167,14 @@ These override points are also particularly useful for adding behavior that occu
instance = serializer.save()
send_email_confirmation(user=self.request.user, modified=instance)
You can also use these hooks to provide additional validation, by raising a `ValidationError()`. This can be useful if you need some validation logic to apply at the point of database save. For example:
def perform_create(self, serializer):
queryset = SignupRequest.objects.filter(user=self.request.user)
if queryset.exists():
raise ValidationError('You have already signed up')
serializer.save(user=self.request.user)
**Note**: These methods replace the old-style version 2.x `pre_save`, `post_save`, `pre_delete` and `post_delete` methods, which are no longer available.
**Other methods**:
@ -192,7 +182,7 @@ These override points are also particularly useful for adding behavior that occu
You won't typically need to override the following methods, although you might need to call into them if you're writing custom views using `GenericAPIView`.
* `get_serializer_context(self)` - Returns a dictionary containing any extra context that should be supplied to the serializer. Defaults to including `'request'`, `'view'` and `'format'` keys.
* `get_serializer(self, instance=None, data=None, files=None, many=False, partial=False, allow_add_remove=False)` - Returns a serializer instance.
* `get_serializer(self, instance=None, data=None, many=False, partial=False)` - Returns a serializer instance.
* `get_paginated_response(self, data)` - Returns a paginated style `Response` object.
* `paginate_queryset(self, queryset)` - Paginate a queryset if required, either returning a page object, or `None` if pagination is not configured for this view.
* `filter_queryset(self, queryset)` - Given a queryset, filter it with whichever filter backends are in use, returning a new queryset.
@ -391,6 +381,10 @@ The following third party packages provide additional generic view implementatio
The [django-rest-framework-bulk package][django-rest-framework-bulk] implements generic view mixins as well as some common concrete generic views to allow to apply bulk operations via API requests.
## Django Rest Multiple Models
[Django Rest Multiple Models][django-rest-multiple-models] provides a generic view (and mixin) for sending multiple serialized models and/or querysets via a single API request.
[cite]: https://docs.djangoproject.com/en/dev/ref/class-based-views/#base-vs-generic-views
[GenericAPIView]: #genericapiview
@ -400,3 +394,4 @@ The [django-rest-framework-bulk package][django-rest-framework-bulk] implements
[UpdateModelMixin]: #updatemodelmixin
[DestroyModelMixin]: #destroymodelmixin
[django-rest-framework-bulk]: https://github.com/miki725/django-rest-framework-bulk
[django-rest-multiple-models]: https://github.com/Axiologue/DjangoRestMultipleModels

View File

@ -98,6 +98,12 @@ The following class could be used to limit the information that is returned to `
'description': view.get_view_description()
}
Then configure your settings to use this custom class:
REST_FRAMEWORK = {
'DEFAULT_METADATA_CLASS': 'myproject.apps.core.MinimalMetadata'
}
[cite]: http://tools.ietf.org/html/rfc7231#section-4.3.7
[no-options]: https://www.mnot.net/blog/2012/10/29/NO_OPTIONS
[json-schema]: http://json-schema.org/

View File

@ -15,7 +15,9 @@ The pagination API can support either:
The built-in styles currently all use links included as part of the content of the response. This style is more accessible when using the browsable API.
Pagination is only performed automatically if you're using the generic views or viewsets. If you're using a regular `APIView`, you'll need to call into the pagination API yourself to ensure you return a paginated response. See the source code for the `mixins.ListMixin` and `generics.GenericAPIView` classes for an example.
Pagination is only performed automatically if you're using the generic views or viewsets. If you're using a regular `APIView`, you'll need to call into the pagination API yourself to ensure you return a paginated response. See the source code for the `mixins.ListModelMixin` and `generics.GenericAPIView` classes for an example.
Pagination can be turned off by setting the pagination class to `None`.
## Setting the pagination style
@ -95,6 +97,7 @@ The `PageNumberPagination` class includes a number of attributes that may be ove
To set these attributes you should override the `PageNumberPagination` class, and then enable your custom pagination class as above.
* `django_paginator_class` - The Django Paginator class to use. Default is `django.core.paginator.Paginator`, which should be fine for most usecases.
* `page_size` - A numeric value indicating the page size. If set, this overrides the `PAGE_SIZE` setting. Defaults to the same value as the `PAGE_SIZE` settings key.
* `page_query_param` - A string value indicating the name of the query parameter to use for the pagination control.
* `page_size_query_param` - If set, this is a string value indicating the name of a query parameter that allows the client to set the page size on a per-request basis. Defaults to `None`, indicating that the client may not control the requested page size.
@ -246,11 +249,11 @@ Let's modify the built-in `PageNumberPagination` style, so that instead of inclu
previous_url = self.get_previous_link()
if next_url is not None and previous_url is not None:
link = '<{next_url}; rel="next">, <{previous_url}; rel="prev">'
link = '<{next_url}>; rel="next", <{previous_url}>; rel="prev"'
elif next_url is not None:
link = '<{next_url}; rel="next">'
link = '<{next_url}>; rel="next"'
elif previous_url is not None:
link = '<{previous_url}; rel="prev">'
link = '<{previous_url}>; rel="prev"'
else:
link = ''

View File

@ -51,6 +51,9 @@ using the `APIView` class based views.
return Response({'received data': request.data})
Or, if you're using the `@api_view` decorator with function based views.
from rest_framework.decorators import api_view
from rest_framework.decorators import parser_classes
@api_view(['POST'])
@parser_classes((JSONParser,))
@ -144,17 +147,16 @@ By default this will include the following keys: `view`, `request`, `args`, `kwa
The following is an example plaintext parser that will populate the `request.data` property with a string representing the body of the request.
class PlainTextParser(BaseParser):
"""
Plain text parser.
"""
media_type = 'text/plain'
def parse(self, stream, media_type=None, parser_context=None):
"""
Simply return a string representing the body of the request.
Plain text parser.
"""
return stream.read()
media_type = 'text/plain'
def parse(self, stream, media_type=None, parser_context=None):
"""
Simply return a string representing the body of the request.
"""
return stream.read()
---

View File

@ -74,8 +74,8 @@ You can also set the authentication policy on a per-view, or per-viewset basis,
using the `APIView` class based views.
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.views import APIView
class ExampleView(APIView):
permission_classes = (IsAuthenticated,)
@ -88,6 +88,10 @@ using the `APIView` class based views.
Or, if you're using the `@api_view` decorator with function based views.
from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
@api_view('GET')
@permission_classes((IsAuthenticated, ))
def example_view(request, format=None):
@ -190,6 +194,16 @@ If you need to test if a request is a read operation or a write operation, you s
---
Custom permissions will raise a `PermissionDenied` exception if the test fails. To change the error message associated with the exception, implement a `message` attribute directly on your custom permission. Otherwise the `default_detail` attribute from `PermissionDenied` will be used.
from rest_framework import permissions
class CustomerAccessPermission(permissions.BasePermission):
message = 'Adding customers not allowed.'
def has_permission(self, request, view):
...
## Examples
The following is an example of a permission class that checks the incoming request's IP address against a blacklist, and denies the request if the IP has been blacklisted.
@ -241,6 +255,10 @@ The [Composed Permissions][composed-permissions] package provides a simple way t
The [REST Condition][rest-condition] package is another extension for building complex permissions in a simple and convenient way. The extension allows you to combine permissions with logical operators.
## DRY Rest Permissions
The [DRY Rest Permissions][dry-rest-permissions] package provides the ability to define different permissions for individual default and custom actions. This package is made for apps with permissions that are derived from relationships defined in the app's data model. It also supports permission checks being returned to a client app through the API's serializer. Additionally it supports adding permissions to the default and custom list actions to restrict the data they retrive per user.
[cite]: https://developer.apple.com/library/mac/#documentation/security/Conceptual/AuthenticationAndAuthorizationGuide/Authorization/Authorization.html
[authentication]: authentication.md
[throttling]: throttling.md
@ -254,3 +272,4 @@ The [REST Condition][rest-condition] package is another extension for building c
[drf-any-permissions]: https://github.com/kevin-brown/drf-any-permissions
[composed-permissions]: https://github.com/niwibe/djangorestframework-composed-permissions
[rest-condition]: https://github.com/caxap/rest_condition
[dry-rest-permissions]: https://github.com/Helioscene/dry-rest-permissions

View File

@ -16,7 +16,7 @@ Relational fields are used to represent model relationships. They can be applie
---
#### Inspecting automatically generated relationships.
#### Inspecting relationships.
When using the `ModelSerializer` class, serializer fields and relationships will be automatically generated for you. Inspecting these automatically generated fields can be a useful tool for determining how to customize the relationship style.
@ -116,6 +116,8 @@ By default this field is read-write, although you can change this behavior using
* `queryset` - The queryset used for model instance lookups when validating the field input. Relationships must either set a queryset explicitly, or set `read_only=True`.
* `many` - If applied to a to-many relationship, you should set this argument to `True`.
* `allow_null` - If set to `True`, the field will accept values of `None` or the empty string for nullable relationships. Defaults to `False`.
* `pk_field` - Set to a field to control serialization/deserialization of the primary key's value. For example, `pk_field=UUIDField(format='hex')` would serialize a UUID primary key into its compact hex representation.
## HyperlinkedRelatedField
@ -149,6 +151,16 @@ Would serialize to a representation like this:
By default this field is read-write, although you can change this behavior using the `read_only` flag.
---
**Note**: This field is designed for objects that map to a URL that accepts a single URL keyword argument, as set using the `lookup_field` and `lookup_url_kwarg` arguments.
This is suitable for URLs that contain a single primary key or slug argument as part of the URL.
If you require more complex hyperlinked representation you'll need to customize the field, as described in the [custom hyperlinked fields](#custom-hyperlinked-fields) section, below.
---
**Arguments**:
* `view_name` - The view name that should be used as the target of the relationship. If you're using [the standard router classes][routers] this will be a string with the format `<modelname>-detail`. **required**.
@ -243,7 +255,7 @@ For example, the following serializer:
class TrackSerializer(serializers.ModelSerializer):
class Meta:
model = Track
fields = ('order', 'title')
fields = ('order', 'title', 'duration')
class AlbumSerializer(serializers.ModelSerializer):
tracks = TrackSerializer(many=True, read_only=True)
@ -254,17 +266,64 @@ For example, the following serializer:
Would serialize to a nested representation like this:
>>> album = Album.objects.create(album_name="The Grey Album", artist='Danger Mouse')
>>> Track.objects.create(album=album, order=1, title='Public Service Announcement', duration=245)
<Track: Track object>
>>> Track.objects.create(album=album, order=2, title='What More Can I Say', duration=264)
<Track: Track object>
>>> Track.objects.create(album=album, order=3, title='Encore', duration=159)
<Track: Track object>
>>> serializer = AlbumSerializer(instance=album)
>>> serializer.data
{
'album_name': 'The Grey Album',
'artist': 'Danger Mouse',
'tracks': [
{'order': 1, 'title': 'Public Service Announcement'},
{'order': 2, 'title': 'What More Can I Say'},
{'order': 3, 'title': 'Encore'},
{'order': 1, 'title': 'Public Service Announcement', 'duration': 245},
{'order': 2, 'title': 'What More Can I Say', 'duration': 264},
{'order': 3, 'title': 'Encore', 'duration': 159},
...
],
}
# Writable nested serializers
By default nested serializers are read-only. If you want to support write-operations to a nested serializer field you'll need to create `create()` and/or `update()` methods in order to explicitly specify how the child relationships should be saved.
class TrackSerializer(serializers.ModelSerializer):
class Meta:
model = Track
fields = ('order', 'title', 'duration')
class AlbumSerializer(serializers.ModelSerializer):
tracks = TrackSerializer(many=True)
class Meta:
model = Album
fields = ('album_name', 'artist', 'tracks')
def create(self, validated_data):
tracks_data = validated_data.pop('tracks')
album = Album.objects.create(**validated_data)
for track_data in tracks_data:
Track.objects.create(album=album, **track_data)
return album
>>> data = {
'album_name': 'The Grey Album',
'artist': 'Danger Mouse',
'tracks': [
{'order': 1, 'title': 'Public Service Announcement', 'duration': 245},
{'order': 2, 'title': 'What More Can I Say', 'duration': 264},
{'order': 3, 'title': 'Encore', 'duration': 159},
],
}
>>> serializer = AlbumSerializer(data=data)
>>> serializer.is_valid()
True
>>> serializer.save()
<Album: Album object>
# Custom relational fields
To implement a custom relational field, you should override `RelatedField`, and implement the `.to_representation(self, value)` method. This method takes the target of the field as the `value` argument, and should return the representation that should be used to serialize the target. The `value` argument will typically be a model instance.
@ -304,6 +363,65 @@ This custom field would then serialize to the following representation.
---
# Custom hyperlinked fields
In some cases you may need to customize the behavior of a hyperlinked field, in order to represent URLs that require more than a single lookup field.
You can achieve this by overriding `HyperlinkedRelatedField`. There are two methods that may be overridden:
**get_url(self, obj, view_name, request, format)**
The `get_url` method is used to map the object instance to its URL representation.
May raise a `NoReverseMatch` if the `view_name` and `lookup_field`
attributes are not configured to correctly match the URL conf.
**get_object(self, queryset, view_name, view_args, view_kwargs)**
If you want to support a writable hyperlinked field then you'll also want to override `get_object`, in order to map incoming URLs back to the object they represent. For read-only hyperlinked fields there is no need to override this method.
The return value of this method should the object that corresponds to the matched URL conf arguments.
May raise an `ObjectDoesNotExist` exception.
## Example
Say we have a URL for a customer object that takes two keyword arguments, like so:
/api/<organization_slug>/customers/<customer_pk>/
This cannot be represented with the default implementation, which accepts only a single lookup field.
In this case we'd need to override `HyperlinkedRelatedField` to get the behavior we want:
from rest_framework import serializers
from rest_framework.reverse import reverse
class CustomerHyperlink(serializers.HyperlinkedRelatedField):
# We define these as class attributes, so we don't need to pass them as arguments.
view_name = 'customer-detail'
queryset = Customer.objects.all()
def get_url(self, obj, view_name, request, format):
url_kwargs = {
'organization_slug': obj.organization.slug,
'customer_pk': obj.pk
}
return reverse(view_name, kwargs=url_kwargs, request=request, format=format)
def get_object(self, view_name, view_args, view_kwargs):
lookup_kwargs = {
'organization__slug': view_kwargs['organization_slug'],
'pk': view_kwargs['customer_pk']
}
return self.get_queryset().get(**lookup_kwargs)
Note that if you wanted to use this style together with the generic views then you'd also need to override `.get_object` on the view in order to get the correct lookup behavior.
Generally we recommend a flat style for API representations where possible, but the nested URL style can also be reasonable when used in moderation.
---
# Further notes
## The `queryset` argument
@ -316,6 +434,35 @@ This behavior is now replaced with *always* using an explicit `queryset` argumen
Doing so reduces the amount of hidden 'magic' that `ModelSerializer` provides, makes the behavior of the field more clear, and ensures that it is trivial to move between using the `ModelSerializer` shortcut, or using fully explicit `Serializer` classes.
## Customizing the HTML display
The built-in `__str__` method of the model will be used to generate string representations of the objects used to populate the `choices` property. These choices are used to populate select HTML inputs in the browsable API.
To provide customized representations for such inputs, override `display_value()` of a `RelatedField` subclass. This method will receive a model object, and should return a string suitable for representing it. For example:
class TrackPrimaryKeyRelatedField(serializers.PrimaryKeyRelatedField):
def display_value(self, instance):
return 'Track: %s' % (instance.title)
## Select field cutoffs
When rendered in the browsable API relational fields will default to only displaying a maximum of 1000 selectable items. If more items are present then a disabled option with "More than 1000 items…" will be displayed.
This behavior is intended to prevent a template from being unable to render in an acceptable timespan due to a very large number of relationships being displayed.
There are two keyword arguments you can use to control this behavior:
- `html_cutoff` - If set this will be the maximum number of choices that will be displayed by a HTML select drop down. Set to `None` to disable any limiting. Defaults to `1000`.
- `html_cutoff_text` - If set this will display a textual indicator if the maximum number of items have been cutoff in an HTML select drop down. Defaults to `"More than {count} items…"`
In cases where the cutoff is being enforced you may want to instead use a plain input field in the HTML form. You can do so using the `style` keyword argument. For example:
assigned_to = serializers.SlugRelatedField(
queryset=User.objects.all(),
slug field='username',
style={'base_template': 'input.html'}
)
## Reverse relations
Note that reverse relationships are not automatically included by the `ModelSerializer` and `HyperlinkedModelSerializer` classes. To include a reverse relationship, you must explicitly add it to the fields list. For example:
@ -356,7 +503,7 @@ For example, given the following model for a tag, which has a generic relationsh
tagged_object = GenericForeignKey('content_type', 'object_id')
def __unicode__(self):
return self.tag
return self.tag_name
And the following two models, which may be have associated tags:
@ -421,39 +568,6 @@ If you explicitly specify a relational field pointing to a
``ManyToManyField`` with a through model, be sure to set ``read_only``
to ``True``.
## Advanced Hyperlinked fields
If you have very specific requirements for the style of your hyperlinked relationships you can override `HyperlinkedRelatedField`.
There are two methods you'll need to override.
#### get_url(self, obj, view_name, request, format)
This method should return the URL that corresponds to the given object.
May raise a `NoReverseMatch` if the `view_name` and `lookup_field`
attributes are not configured to correctly match the URL conf.
#### get_object(self, queryset, view_name, view_args, view_kwargs)
This method should the object that corresponds to the matched URL conf arguments.
May raise an `ObjectDoesNotExist` exception.
### Example
For example, if all your object URLs used both a account and a slug in the the URL to reference the object, you might create a custom field like this:
class CustomHyperlinkedField(serializers.HyperlinkedRelatedField):
def get_url(self, obj, view_name, request, format):
kwargs = {'account': obj.account, 'slug': obj.slug}
return reverse(view_name, kwargs=kwargs, request=request, format=format)
def get_object(self, queryset, view_name, view_args, view_kwargs):
account = view_kwargs['account']
slug = view_kwargs['slug']
return queryset.get(account=account, slug=slug)
---
# Third Party Packages

View File

@ -153,23 +153,13 @@ You can use `StaticHTMLRenderer` either to return regular HTML pages using REST
See also: `TemplateHTMLRenderer`
## HTMLFormRenderer
Renders data returned by a serializer into an HTML form. The output of this renderer does not include the enclosing `<form>` tags or an submit actions, as you'll probably need those to include the desired method and URL. Also note that the `HTMLFormRenderer` does not yet support including field error messages.
Note that the template used by the `HTMLFormRenderer` class, and the context submitted to it **may be subject to change**. If you need to use this renderer class it is advised that you either make a local copy of the class and templates, or follow the release note on REST framework upgrades closely.
**.media_type**: `text/html`
**.format**: `'.form'`
**.charset**: `utf-8`
**.template**: `'rest_framework/form.html'`
## BrowsableAPIRenderer
Renders data into HTML for the Browsable 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.
Renders data into HTML for the Browsable API:
![The BrowsableAPIRenderer](../img/quickstart.png)
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`
@ -181,12 +171,63 @@ Renders data into HTML for the Browsable API. This renderer will determine whic
#### Customizing BrowsableAPIRenderer
By default the response content will be rendered with the highest priority renderer apart from `BrowseableAPIRenderer`. If you need to customize this behavior, for example to use HTML as the default return format, but use JSON in the browsable API, you can do so by overriding the `get_default_renderer()` method. For example:
By default the response content will be rendered with the highest priority renderer apart from `BrowsableAPIRenderer`. If you need to customize this behavior, for example to use HTML as the default return format, but use JSON in the browsable API, you can do so by overriding the `get_default_renderer()` method. For example:
class CustomBrowsableAPIRenderer(BrowsableAPIRenderer):
def get_default_renderer(self, view):
return JSONRenderer()
## AdminRenderer
Renders data into HTML for an admin-like display:
![The AdminRender view](../img/admin.png)
This renderer is suitable for CRUD-style web APIs that should also present a user-friendly interface for managing the data.
Note that views that have nested or list serializers for their input won't work well with the `AdminRenderer`, as the HTML forms are unable to properly support them.
**Note**: The `AdminRenderer` is only able to include links to detail pages when a properly configured `URL_FIELD_NAME` (`url` by default) attribute is present in the data. For `HyperlinkedModelSerializer` this will be the case, but for `ModelSerializer` or plain `Serializer` classes you'll need to make sure to include the field explicitly. For example here we use models `get_absolute_url` method:
class AccountSerializer(serializers.ModelSerializer):
url = serializers.CharField(source='get_absolute_url', read_only=True)
class Meta:
model = Account
**.media_type**: `text/html`
**.format**: `'.admin'`
**.charset**: `utf-8`
**.template**: `'rest_framework/admin.html'`
## HTMLFormRenderer
Renders data returned by a serializer into an HTML form. The output of this renderer does not include the enclosing `<form>` tags, a hidden CSRF input or any submit buttons.
This renderer is not intended to be used directly, but can instead be used in templates by passing a serializer instance to the `render_form` template tag.
{% load rest_framework %}
<form action="/submit-report/" method="post">
{% csrf_token %}
{% render_form serializer %}
<input type="submit" value="Save" />
</form>
For more information see the [HTML & Forms][html-and-forms] documentation.
**.media_type**: `text/html`
**.format**: `'.form'`
**.charset**: `utf-8`
**.template**: `'rest_framework/horizontal/form.html'`
## MultiPartRenderer
This renderer is used for rendering HTML multipart form data. **It is not suitable as a response renderer**, but is instead used for creating test requests, using REST framework's [test client and test request factory][testing].
@ -433,6 +474,7 @@ Comma-separated values are a plain-text tabular data format, that can be easily
[cite]: https://docs.djangoproject.com/en/dev/ref/template-response/#the-rendering-process
[conneg]: content-negotiation.md
[html-and-forms]: ../topics/html-and-forms.md
[browser-accept-headers]: http://www.gethifi.com/blog/browser-rest-http-accept-headers
[testing]: testing.md
[HATEOAS]: http://timelessrepo.com/haters-gonna-hateoas

View File

@ -30,14 +30,6 @@ For more details see the [parsers documentation].
For clarity inside your code, we recommend using `request.query_params` instead of the Django's standard `request.GET`. Doing so will help keep your codebase more correct and obvious - any HTTP method type may include query parameters, not just `GET` requests.
## .DATA and .FILES
The old-style version 2.x `request.DATA` and `request.FILES` attributes are still available, but are now pending deprecation in favor of the unified `request.data` attribute.
## .QUERY_PARAMS
The old-style version 2.x `request.QUERY_PARAMS` attribute is still available, but is now pending deprecation in favor of the more pythonic `request.query_params`.
## .parsers
The `APIView` class or `@api_view` decorator will ensure that this property is automatically set to a list of `Parser` instances, based on the `parser_classes` set on the view or based on the `DEFAULT_PARSER_CLASSES` setting.

View File

@ -189,6 +189,12 @@ Your `validate_<field_name>` methods should return the validated value or raise
raise serializers.ValidationError("Blog post is not about Django")
return value
---
**Note:** If your `<field_name>` is declared on your serializer with the parameter `required=False` then this validation step will not take place if the field is not included.
---
#### Object-level validation
To do any other validation that requires access to multiple fields, add a method called `.validate()` to your `Serializer` subclass. This method takes a single argument, which is a dictionary of field values. It should raise a `ValidationError` if necessary, or just return the validated values. For example:
@ -281,7 +287,7 @@ Similarly if a nested representation should be a list of items, you should pass
## Writable nested representations
When dealing with nested representations that support deserializing the data, an errors with nested objects will be nested under the field name of the nested object.
When dealing with nested representations that support deserializing the data, any errors with nested objects will be nested under the field name of the nested object.
serializer = CommentSerializer(data={'user': {'email': 'foobar', 'username': 'doe'}, 'content': 'baz'})
serializer.is_valid()
@ -350,7 +356,7 @@ It is possible that a third party package, providing automatic support some kind
#### Handling saving related instances in model manager classes
An alternative to saving multiple related instances in the serializer is to write custom model manager classes handle creating the correct instances.
An alternative to saving multiple related instances in the serializer is to write custom model manager classes that handle creating the correct instances.
For example, suppose we wanted to ensure that `User` instances and `Profile` instances are always created together as a pair. We might write a custom manager class that looks something like this:
@ -399,7 +405,7 @@ To serialize a queryset or list of objects instead of a single object instance,
#### Deserializing multiple objects
The default behavior for deserializing multiple objects is to support multiple object creation, but not support multiple object updates. For more information on how to support or customize either of these cases, see the [ListSerializer](#ListSerializer) documentation below.
The default behavior for deserializing multiple objects is to support multiple object creation, but not support multiple object updates. For more information on how to support or customize either of these cases, see the [ListSerializer](#listserializer) documentation below.
## Including extra context
@ -432,6 +438,7 @@ Declaring a `ModelSerializer` looks like this:
class AccountSerializer(serializers.ModelSerializer):
class Meta:
model = Account
fields = ('id', 'account_name', 'users', 'created')
By default, all the model fields on the class will be mapped to a corresponding serializer fields.
@ -453,7 +460,7 @@ To do so, open the Django shell, using `python manage.py shell`, then import the
## Specifying which fields to include
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`.
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`. It is strongly recommended that you explicitly set all fields that should be serialized using the `fields` attribute. This will make it less likely to result in unintentionally exposing data when your models change.
For example:
@ -462,7 +469,27 @@ For example:
model = Account
fields = ('id', 'account_name', 'users', 'created')
The names in the `fields` option will normally map to model fields on the model class.
You can also set the `fields` attribute to the special value `'__all__'` to indicate that all fields in the model should be used.
For example:
class AccountSerializer(serializers.ModelSerializer):
class Meta:
model = Account
fields = '__all__'
You can set the `exclude` attribute to a list of fields to be excluded from the serializer.
For example:
class AccountSerializer(serializers.ModelSerializer):
class Meta:
model = Account
exclude = ('users',)
In the example above, if the `Account` model had 3 fields `account_name`, `users`, and `created`, this will result in the fields `account_name` and `created` to be serialized.
The names in the `fields` and `exclude` attributes will normally map to model fields on the model class.
Alternatively names in the `fields` options can map to properties or methods which take no arguments that exist on the model class.
@ -524,7 +551,7 @@ Please review the [Validators Documentation](/api-guide/validators/) for details
## Additional keyword arguments
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.
There is also a shortcut allowing you to specify arbitrary additional keyword arguments on fields, using the `extra_kwargs` option. As in the case of `read_only_fields`, this means you do not need to explicitly declare the field on the serializer.
This option is a dictionary, mapping field names to a dictionary of keyword arguments. For example:
@ -565,7 +592,7 @@ Typically we would recommend *not* using inheritance on inner Meta classes, but
The ModelSerializer class also exposes an API that you can override in order to alter how serializer fields are automatically determined when instantiating the serializer.
Normally if a `ModelSerializer` does not generate the fields you need by default the you should either add them to the class explicitly, or simply use a regular `Serializer` class instead. However in some cases you may want to create a new base class that defines how the serializer fields are created for any given model.
Normally if a `ModelSerializer` does not generate the fields you need by default then you should either add them to the class explicitly, or simply use a regular `Serializer` class instead. However in some cases you may want to create a new base class that defines how the serializer fields are created for any given model.
### `.serializer_field_mapping`
@ -773,6 +800,10 @@ Here's an example of how you might choose to implement multiple updates:
return ret
class BookSerializer(serializers.Serializer):
# We need to identify elements in the list using their primary key,
# so use a writable field here, rather than the default which would be read-only.
id = serializers.IntegerField()
...
class Meta:
list_serializer_class = BookListSerializer
@ -805,7 +836,7 @@ This class implements the same basic API as the `Serializer` class:
* `.data` - Returns the outgoing primitive representation.
* `.is_valid()` - Deserializes and validates incoming data.
* `.validated_data` - Returns the validated incoming data.
* `.errors` - Returns an errors during validation.
* `.errors` - Returns any errors during validation.
* `.save()` - Persists the validated data into an object instance.
There are four methods that can be overridden, depending on what functionality you want the serializer class to support:
@ -1022,6 +1053,13 @@ A new interface for controlling this behavior is currently planned for REST fram
The following third party packages are also available.
## Django REST marshmallow
The [django-rest-marshmallow][django-rest-marshmallow] package provides an alternative implementation for serializers, using the python [marshmallow][marshmallow] library. It exposes the same API as the REST framework serializers, and can be used as a drop-in replacement in some use-cases.
## Serpy
The [serpy][serpy] package is an alternative implementation for serializers that is built for speed. [Serpy][serpy] serializes complex datatypes to simple native types. The native types can be easily converted to JSON or any other format needed.
## MongoengineModelSerializer
The [django-rest-framework-mongoengine][mongoengine] package provides a `MongoEngineModelSerializer` serializer class that supports using MongoDB as the storage layer for Django REST framework.
@ -1038,6 +1076,9 @@ The [django-rest-framework-hstore][django-rest-framework-hstore] package provide
[relations]: relations.md
[model-managers]: https://docs.djangoproject.com/en/dev/topics/db/managers/
[encapsulation-blogpost]: http://www.dabapps.com/blog/django-models-and-encapsulation/
[django-rest-marshmallow]: http://tomchristie.github.io/django-rest-marshmallow/
[marshmallow]: https://marshmallow.readthedocs.org/en/latest/
[serpy]: https://github.com/clarkduvall/serpy
[mongoengine]: https://github.com/umutbozkurt/django-rest-framework-mongoengine
[django-rest-framework-gis]: https://github.com/djangonauts/django-rest-framework-gis
[django-rest-framework-hstore]: https://github.com/djangonauts/django-rest-framework-hstore

View File

@ -119,6 +119,14 @@ Default: `None`
#### PAGINATE_BY_PARAM
---
**This setting is pending deprecation.**
See the pagination documentation for further guidance on [setting the pagination style](pagination.md#modifying-the-pagination-style).
---
The name of a query parameter, which can be used by the client to override the default page size to use for pagination. If set to `None`, clients may not override the default page size.
For example, given the following settings:
@ -136,6 +144,14 @@ Default: `None`
#### MAX_PAGINATE_BY
---
**This setting is pending deprecation.**
See the pagination documentation for further guidance on [setting the pagination style](pagination.md#modifying-the-pagination-style).
---
The maximum page size to allow when the page size is specified by the client. If set to `None`, then no maximum limit is applied.
For example, given the following settings:
@ -233,45 +249,23 @@ Default:
---
## Browser overrides
*The following settings provide URL or form-based overrides of the default browser behavior.*
#### FORM_METHOD_OVERRIDE
The name of a form field that may be used to override the HTTP method of the form.
If the value of this setting is `None` then form method overloading will be disabled.
Default: `'_method'`
#### FORM_CONTENT_OVERRIDE
The name of a form field that may be used to override the content of the form payload. Must be used together with `FORM_CONTENTTYPE_OVERRIDE`.
If either setting is `None` then form content overloading will be disabled.
Default: `'_content'`
#### FORM_CONTENTTYPE_OVERRIDE
The name of a form field that may be used to override the content type of the form payload. Must be used together with `FORM_CONTENT_OVERRIDE`.
If either setting is `None` then form content overloading will be disabled.
Default: `'_content_type'`
#### URL_ACCEPT_OVERRIDE
The name of a URL parameter that may be used to override the HTTP `Accept` header.
If the value of this setting is `None` then URL accept overloading will be disabled.
Default: `'accept'`
## Content type controls
#### URL_FORMAT_OVERRIDE
The name of a URL parameter that may be used to override the default `Accept` header based content negotiation.
The name of a URL parameter that may be used to override the default content negotiation `Accept` header behavior, by using a `format=…` query parameter in the request URL.
For example: `http://example.com/organizations/?format=csv`
If the value of this setting is `None` then URL format overrides will be disabled.
Default: `'format'`
#### FORMAT_SUFFIX_KWARG
The name of a parameter in the URL conf that may be used to provide a format suffix. This setting is applied when using `format_suffix_patterns` to include suffixed URL patterns.
For example: `http://example.com/organizations.csv/`
Default: `'format'`
@ -433,12 +427,6 @@ A string representing the key that should be used for the URL fields generated b
Default: `'url'`
#### FORMAT_SUFFIX_KWARG
The name of a parameter in the URL conf that may be used to provide a format suffix.
Default: `'format'`
#### NUM_PROXIES
An integer of 0 or more, that may be used to specify the number of application proxies that the API runs behind. This allows throttling to more accurately identify client IP addresses. If set to `None` then less strict IP matching will be used by the throttle classes.

View File

@ -200,6 +200,7 @@ You can use any of REST framework's test case classes as you would for the regul
from django.core.urlresolvers import reverse
from rest_framework import status
from rest_framework.test import APITestCase
from myproject.apps.core.models import Account
class AccountTests(APITestCase):
def test_create_account(self):
@ -210,7 +211,8 @@ You can use any of REST framework's test case classes as you would for the regul
data = {'name': 'DabApps'}
response = self.client.post(url, data, format='json')
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
self.assertEqual(response.data, data)
self.assertEqual(Account.objects.count(), 1)
self.assertEqual(Account.objects.get().name, 'DabApps')
---

View File

@ -148,7 +148,7 @@ For example, given the following views...
throttle_scope = 'contacts'
...
class ContactDetailView(ApiView):
class ContactDetailView(APIView):
throttle_scope = 'contacts'
...
@ -184,7 +184,7 @@ If the `.wait()` method is implemented and the request is throttled, then a `Ret
The following is an example of a rate throttle, that will randomly throttle 1 in every 10 requests.
class RandomRateThrottle(throttles.BaseThrottle):
class RandomRateThrottle(throttling.BaseThrottle):
def allow_request(self, request, view):
return random.randint(1, 10) == 1

View File

@ -204,7 +204,7 @@ A validator may be any callable that raises a `serializers.ValidationError` on f
To write a class based validator, use the `__call__` method. Class based validators are useful as they allow you to parameterize and reuse behavior.
class MultipleOf:
class MultipleOf(object):
def __init__(self, base):
self.base = base

View File

@ -3,7 +3,7 @@ source: versioning.py
# Versioning
> Versioning an interface is just a "polite" way to kill deployed clients.
>
>
> &mdash; [Roy Fielding][cite].
API versioning allows you to alter behavior between different clients. REST framework provides for a number of different versioning schemes.
@ -71,8 +71,21 @@ You can also set the versioning scheme on an individual view. Typically you won'
The following settings keys are also used to control versioning:
* `DEFAULT_VERSION`. The value that should be used for `request.version` when no versioning information is present. Defaults to `None`.
* `ALLOWED_VERSIONS`. If set, this value will restrict the set of versions that may be returned by the versioning scheme, and will raise an error if the provided version if not in this set. Defaults to `None`.
* `VERSION_PARAMETER`. The string that should used for any versioning parameters, such as in the media type or URL query parameters. Defaults to `'version'`.
* `ALLOWED_VERSIONS`. If set, this value will restrict the set of versions that may be returned by the versioning scheme, and will raise an error if the provided version if not in this set. Note that the value used for the `DEFAULT_VERSION` setting is always considered to be part of the `ALLOWED_VERSIONS` set. Defaults to `None`.
* `VERSION_PARAM`. The string that should used for any versioning parameters, such as in the media type or URL query parameters. Defaults to `'version'`.
You can also set your versioning class plus those three values on a per-view or a per-viewset basis by defining your own versioning scheme and using the `default_version`, `allowed_versions` and `version_param` class variables. For example, if you want to use `URLPathVersioning`:
from rest_framework.versioning import URLPathVersioning
from rest_framework.views import APIView
class ExampleVersioning(URLPathVersioning):
default_version = ...
allowed_versions = ...
version_param = ...
class ExampleView(APIVIew):
versioning_class = ExampleVersioning
---
@ -117,12 +130,12 @@ Your URL conf must include a pattern that matches the version with a `'version'`
urlpatterns = [
url(
r'^(?P<version>{v1,v2})/bookings/$',
r'^(?P<version>(v1|v2))/bookings/$',
bookings_list,
name='bookings-list'
),
url(
r'^(?P<version>{v1,v2})/bookings/(?P<pk>[0-9]+)/$',
r'^(?P<version>(v1|v2))/bookings/(?P<pk>[0-9]+)/$',
bookings_detail,
name='bookings-detail'
)

View File

@ -27,7 +27,7 @@ Let's define a simple viewset that can be used to list or retrieve all the users
class UserViewSet(viewsets.ViewSet):
"""
A simple ViewSet that for listing or retrieving users.
A simple ViewSet for listing or retrieving users.
"""
def list(self, request):
queryset = User.objects.all()

BIN
docs/img/admin.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

BIN
docs/img/django-filter.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

BIN
docs/img/horizontal.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
docs/img/inline.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

BIN
docs/img/search-filter.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

BIN
docs/img/vertical.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -1,17 +1,18 @@
<p class="badges" height=20px>
<iframe src="http://ghbtns.com/github-btn.html?user=tomchristie&amp;repo=django-rest-framework&amp;type=watch&amp;count=true" class="github-star-button" allowtransparency="true" frameborder="0" scrolling="0" width="110px" height="20px"></iframe>
<iframe src="http://ghbtns.com/github-btn.html?user=tomchristie&amp;repo=django-rest-framework&amp;type=watch&amp;count=true" class="github-star-button" allowtransparency="true" frameborder="0" scrolling="0" width="110px" height="20px"></iframe>
<a href="https://twitter.com/share" class="twitter-share-button" data-url="django-rest-framework.org" data-text="Checking out the totally awesome Django REST framework! http://www.django-rest-framework.org" data-count="none"></a>
<script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0];if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src="http://platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");</script>
<a href="http://travis-ci.org/tomchristie/django-rest-framework?branch=master">
<img src="https://secure.travis-ci.org/tomchristie/django-rest-framework.svg?branch=master" class="status-badge">
</a>
<img src="https://secure.travis-ci.org/tomchristie/django-rest-framework.svg?branch=master" class="travis-build-image">
<a href="https://pypi.python.org/pypi/djangorestframework">
<img src="https://img.shields.io/pypi/v/djangorestframework.svg" class="status-badge">
</a>
</p>
---
**Note**: This is the documentation for the **version 3.1** of REST framework. Documentation for [version 2.4](http://tomchristie.github.io/rest-framework-2-docs/) is also available.
For more details see the [3.1 release notes][3.1-announcement].
**Note**: This is the documentation for the **version 3** of REST framework. Documentation for [version 2](http://tomchristie.github.io/rest-framework-2-docs/) is also available.
---
@ -28,7 +29,7 @@ For more details see the [3.1 release notes][3.1-announcement].
<img alt="Django REST Framework" title="Logo by Jake 'Sid' Smith" src="img/logo.png" width="600px" style="display: block; margin: 0 auto 0 auto">
</p>
Django REST framework is a powerful and flexible toolkit that makes it easy to build Web APIs.
Django REST framework is a powerful and flexible toolkit for building Web APIs.
Some reasons you might want to use REST framework:
@ -49,13 +50,14 @@ Some reasons you might want to use REST framework:
REST framework requires the following:
* Python (2.6.5+, 2.7, 3.2, 3.3, 3.4)
* Django (1.4.11+, 1.5.6+, 1.6.3+, 1.7+, 1.8)
* Python (2.7, 3.2, 3.3, 3.4, 3.5)
* Django (1.7+, 1.8, 1.9)
The following packages are optional:
* [Markdown][markdown] (2.1.0+) - Markdown support for the browsable API.
* [django-filter][django-filter] (0.9.2+) - Filtering support.
* [django-crispy-forms][django-crispy-forms] - Improved HTML display for filtering.
* [django-guardian][django-guardian] (1.1.1+) - Object level permissions support.
## Installation
@ -84,7 +86,7 @@ If you're intending to use the browsable API you'll probably also want to add RE
url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework'))
]
Note that the URL path can be whatever you want, but you must include `'rest_framework.urls'` with the `'rest_framework'` namespace.
Note that the URL path can be whatever you want, but you must include `'rest_framework.urls'` with the `'rest_framework'` namespace. You may leave out the namespace in Django 1.9+, and REST framework will set it for you.
## Example
@ -188,7 +190,9 @@ The API guide is your complete reference manual to all the functionality provide
General guides to using REST framework.
* [Documenting your API][documenting-your-api]
* [Internationalization][internationalization]
* [AJAX, CSRF & CORS][ajax-csrf-cors]
* [HTML & Forms][html-and-forms]
* [Browser enhancements][browser-enhancements]
* [The Browsable API][browsableapi]
* [REST, Hypermedia & HATEOAS][rest-hypermedia-hateoas]
@ -197,6 +201,8 @@ General guides to using REST framework.
* [Project management][project-management]
* [3.0 Announcement][3.0-announcement]
* [3.1 Announcement][3.1-announcement]
* [3.2 Announcement][3.2-announcement]
* [3.3 Announcement][3.3-announcement]
* [Kickstarter Announcement][kickstarter-announcement]
* [Release Notes][release-notes]
@ -248,12 +254,11 @@ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[travis]: http://travis-ci.org/tomchristie/django-rest-framework?branch=master
[travis-build-image]: https://secure.travis-ci.org/tomchristie/django-rest-framework.png?branch=master
[mozilla]: http://www.mozilla.org/en-US/about/
[eventbrite]: https://www.eventbrite.co.uk/about/
[markdown]: http://pypi.python.org/pypi/Markdown/
[django-filter]: http://pypi.python.org/pypi/django-filter
[django-crispy-forms]: https://github.com/maraujop/django-crispy-forms
[django-guardian]: https://github.com/lukaszb/django-guardian
[0.4]: https://github.com/tomchristie/django-rest-framework/tree/0.4.X
[image]: img/quickstart.png
@ -301,8 +306,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[settings]: api-guide/settings.md
[documenting-your-api]: topics/documenting-your-api.md
[internationalization]: topics/documenting-your-api.md
[internationalization]: topics/internationalization.md
[ajax-csrf-cors]: topics/ajax-csrf-cors.md
[html-and-forms]: topics/html-and-forms.md
[browser-enhancements]: topics/browser-enhancements.md
[browsableapi]: topics/browsable-api.md
[rest-hypermedia-hateoas]: topics/rest-hypermedia-hateoas.md
@ -311,7 +317,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[third-party-resources]: topics/third-party-resources.md
[3.0-announcement]: topics/3.0-announcement.md
[3.1-announcement]: topics/3.1-announcement.md
[3.2-announcement]: topics/3.2-announcement.md
[3.3-announcement]: topics/3.3-announcement.md
[kickstarter-announcement]: topics/kickstarter-announcement.md
[funding]: topics/funding.md
[release-notes]: topics/release-notes.md
[tox]: http://testrun.org/tox/latest/

View File

@ -940,7 +940,7 @@ The default JSON renderer will return float objects for un-coerced `Decimal` ins
* The serializer `ChoiceField` does not currently display nested choices, as was the case in 2.4. This will be address as part of 3.1.
* Due to the new templated form rendering, the 'widget' option is no longer valid. This means there's no easy way of using third party "autocomplete" widgets for rendering select inputs that contain a large number of choices. You'll either need to use a regular select or a plain text input. We may consider addressing this in 3.1 or 3.2 if there's sufficient demand.
* Some of the default validation error messages were rewritten and might no longer be pre-translated. You can still [create language files with Django][django-localization] if you wish to localize them.
* `APIException` subclasses could previously take could previously take any arbitrary type in the `detail` argument. These exceptions now use translatable text strings, and as a result call `force_text` on the `detail` argument, which *must be a string*. If you need complex arguments to an `APIException` class, you should subclass it and override the `__init__()` method. Typically you'll instead want to use a custom exception handler to provide for non-standard error responses.
* `APIException` subclasses could previously take any arbitrary type in the `detail` argument. These exceptions now use translatable text strings, and as a result call `force_text` on the `detail` argument, which *must be a string*. If you need complex arguments to an `APIException` class, you should subclass it and override the `__init__()` method. Typically you'll instead want to use a custom exception handler to provide for non-standard error responses.
---

View File

@ -0,0 +1,113 @@
# Django REST framework 3.2
The 3.2 release is the first version to include an admin interface for the browsable API.
![The AdminRenderer](../img/admin.png)
This interface is intended to act as a more user-friendly interface to the API. It can be used either as a replacement to the existing `BrowsableAPIRenderer`, or used together with it, allowing you to switch between the two styles as required.
We've also fixed a huge number of issues, and made numerous cleanups and improvements.
Over the course of the 3.1.x series we've [resolved nearly 600 tickets](https://github.com/tomchristie/django-rest-framework/issues?utf8=%E2%9C%93&q=closed%3A%3E2015-03-05) on our GitHub issue tracker. This means we're currently running at a rate of **closing around 100 issues or pull requests per month**.
None of this would have been possible without the support of our wonderful Kickstarter backers. If you're looking for a job in Django development we'd strongly recommend taking [a look through our sponsors](http://www.django-rest-framework.org/topics/kickstarter-announcement/#sponsors) and finding out who's hiring.
## AdminRenderer
To include `AdminRenderer` simply add it to your settings:
REST_FRAMEWORK = {
'DEFAULT_RENDERER_CLASSES': [
'rest_framework.renderers.JSONRenderer',
'rest_framework.renderers.AdminRenderer',
'rest_framework.renderers.BrowsableAPIRenderer'
],
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 100
}
There are some limitations to the `AdminRenderer`, in particular it is not yet able to handle list or dictionary inputs, as we do not have any HTML form fields that support those.
Also note that this is an initial release and we do not yet have a public API for modifying the behavior or documentation on overriding the templates.
The idea is to get this released to users early, so we can start getting feedback and release a more fully featured version in 3.3.
## Supported versions
This release drops support for Django 1.4.
Our supported Django versions are now 1.5.6+, 1.6.3+, 1.7 and 1.8.
## Deprecations
There are no new deprecations in 3.2, although a number of existing deprecations have now escalated in line with our deprecation policy.
* `request.DATA` was put on the deprecation path in 3.0. It has now been removed and its usage will result in an error. Use the more pythonic style of `request.data` instead.
* `request.QUERY_PARAMS` was put on the deprecation path in 3.0. It has now been removed and its usage will result in an error. Use the more pythonic style of `request.query_params` instead.
* The following `ModelSerializer.Meta` options have now been removed: `write_only_fields`, `view_name`, `lookup_field`. Use the more general `extra_kwargs` option instead.
The following pagination view attributes and settings have been moved into attributes on the pagination class since 3.1. Their usage was formerly in 'pending deprecation', and has now escalated to 'deprecated'. They will continue to function but will raise errors.
* `view.paginate_by` - Use `paginator.page_size` instead.
* `view.page_query_param` - Use `paginator.page_query_param` instead.
* `view.paginate_by_param` - Use `paginator.page_size_query_param` instead.
* `view.max_paginate_by` - Use `paginator.max_page_size` instead.
* `settings.PAGINATE_BY` - Use `paginator.page_size` instead.
* `settings.PAGINATE_BY_PARAM` - Use `paginator.page_size_query_param` instead.
* `settings.MAX_PAGINATE_BY` - Use `max_page_size` instead.
## Modifications to list behaviors
There are a couple of bug fixes that are worth calling out as they introduce differing behavior.
These are a little subtle and probably won't affect most users, but are worth understanding before upgrading your project.
### ManyToMany fields and blank=True
We've now added an `allow_empty` argument, which can be used with `ListSerializer`, or with `many=True` relationships. This is `True` by default, but can be set to `False` if you want to disallow empty lists as valid input.
As a follow-up to this we are now able to properly mirror the behavior of Django's `ModelForm` with respect to how many-to-many fields are validated.
Previously a many-to-many field on a model would map to a serializer field that would allow either empty or non-empty list inputs. Now, a many-to-many field will map to a serializer field that requires at least one input, unless the model field has `blank=True` set.
Here's what the mapping looks like in practice:
* `models.ManyToManyField()``serializers.PrimaryKeyRelatedField(many=True, allow_empty=False)`
* `models.ManyToManyField(blank=True)``serializers.PrimaryKeyRelatedField(many=True)`
The upshot is this: If you have many to many fields in your models, then make sure you've included the argument `blank=True` if you want to allow empty inputs in the equivalent `ModelSerializer` fields.
### List fields and allow_null
When using `allow_null` with `ListField` or a nested `many=True` serializer the previous behavior was to allow `null` values as items in the list. The behavior is now to allow `null` values instead of the list.
For example, take the following field:
NestedSerializer(many=True, allow_null=True)
Previously the validation behavior would be:
* `[{…}, null, {…}]` is **valid**.
* `null` is **invalid**.
Our validation behavior as of 3.2.0 is now:
* `[{…}, null, {…}]` is **invalid**.
* `null` is **valid**.
If you want to allow `null` child items, you'll need to instead specify `allow_null` on the child class, using an explicit `ListField` instead of `many=True`. For example:
ListField(child=NestedSerializer(allow_null=True))
## What's next?
The 3.3 release is currently planned for the start of October, and will be the last Kickstarter-funded release.
This release is planned to include:
* Search and filtering controls in the browsable API and admin interface.
* Improvements and public API for the admin interface.
* Improvements and public API for our templated HTML forms and fields.
* Nested object and list support in HTML forms.
Thanks once again to all our sponsors and supporters.

View File

@ -0,0 +1,58 @@
# Django REST framework 3.3
The 3.3 release marks the final work in the Kickstarter funded series. We'd like to offer a final resounding **thank you** to all our wonderful sponsors and supporters.
The amount of work that has been achieved as a direct result of the funding is immense. We've added a huge amounts of new functionality, resolved nearly 2,000 tickets, and redesigned & refined large parts of the project.
In order to continue driving REST framework forward, we'll shortly be announcing a new set of funding plans. Follow [@_tomchristie](https://twitter.com/_tomchristie) to keep up to date with these announcements, and be among the first set of sign ups.
We strongly believe that collaboratively funded software development yields outstanding results for a relatively low investment-per-head. If you or your company use REST framework commercially, then we would strongly urge you to participate in this latest funding drive, and help us continue to build an increasingly polished & professional product.
---
## Release notes
Significant new functionality in the 3.3 release includes:
* Filters presented as HTML controls in the browsable API.
* A [forms API][forms-api], allowing serializers to be rendered as HTML forms.
* Django 1.9 support.
* A [`JSONField` serializer field][jsonfield], corresponding to Django 1.9's Postgres `JSONField` model field.
* Browsable API support [via AJAX][ajax-form], rather than server side request overloading.
![Filter Controls](../img/filter-controls.png)
*Example of the new filter controls*
---
## Supported versions
This release drops support for Django 1.5 and 1.6. Django 1.7, 1.8 or 1.9 are now required.
This brings our supported versions into line with Django's [currently supported versions][django-supported-versions]
## Deprecations
The AJAX based support for the browsable API means that there are a number of internal cleanups in the `request` class. For the vast majority of developers this should largely remain transparent:
* To support form based `PUT` and `DELETE`, or to support form content types such as JSON, you should now use the [AJAX forms][ajax-form] javascript library. This replaces the previous 'method and content type overloading' that required significant internal complexity to the request class.
* The `accept` query parameter is no longer supported by the default content negotiation class. If you require it then you'll need to [use a custom content negotiation class](browser-enhancements.md#url-based-accept-headers).
* The custom `HTTP_X_HTTP_METHOD_OVERRIDE` header is no longer supported by default. If you require it then you'll need to [use custom middleware](browser-enhancements.md#http-header-based-method-overriding).
The following pagination view attributes and settings have been moved into attributes on the pagination class since 3.1. Their usage was formerly deprecated, and has now been removed entirely, in line with the deprecation policy.
* `view.paginate_by` - Use `paginator.page_size` instead.
* `view.page_query_param` - Use `paginator.page_query_param` instead.
* `view.paginate_by_param` - Use `paginator.page_size_query_param` instead.
* `view.max_paginate_by` - Use `paginator.max_page_size` instead.
* `settings.PAGINATE_BY` - Use `paginator.page_size` instead.
* `settings.PAGINATE_BY_PARAM` - Use `paginator.page_size_query_param` instead.
* `settings.MAX_PAGINATE_BY` - Use `paginator.max_page_size` instead.
The `ModelSerializer` and `HyperlinkedModelSerializer` classes should now include either a `fields` or `exclude` option, although the `fields = '__all__'` shortcut may be used. Failing to include either of these two options is currently pending deprecation, and will be removed entirely in the 3.5 release. This behavior brings `ModelSerializer` more closely in line with Django's `ModelForm` behavior.
[forms-api]: html-and-forms.md
[ajax-form]: https://github.com/tomchristie/ajax-form
[jsonfield]: ../../api-guide/fields#jsonfield
[django-supported-versions]: https://www.djangoproject.com/download/#supported-versions

View File

@ -35,7 +35,7 @@ To replace the default theme, add a `bootstrap_theme` block to your `api.html` a
<link rel="stylesheet" href="/path/to/my/bootstrap.css" type="text/css">
{% endblock %}
A suitable replacement theme can be generated using Bootstrap's [Customize Tool][bcustomize]. There are also pre-made themes available at [Bootswatch][bswatch]. To use any of the Bootswatch themes, simply download the theme's `bootstrap.min.css` file, add it to your project, and replace the default one as described above.
Suitable pre-made replacement themes are available at [Bootswatch][bswatch]. To use any of the Bootswatch themes, simply download the theme's `bootstrap.min.css` file, add it to your project, and replace the default one as described above.
You can also change the navbar variant, which by default is `navbar-inverse`, using the `bootstrap_navbar_variant` block. The empty `{% block bootstrap_navbar_variant %}{% endblock %}` will use the original Bootstrap navbar style.
@ -75,7 +75,6 @@ All of the blocks available in the browsable API base template that can be used
* `bootstrap_navbar_variant` - CSS class for the navbar.
* `branding` - Branding section of the navbar, see [Bootstrap components][bcomponentsnav].
* `breadcrumbs` - Links showing resource nesting, allowing the user to go back up the resources. It's recommended to preserve these, but they can be overridden using the breadcrumbs block.
* `footer` - Any copyright notices or similar footer materials can go here (by default right-aligned).
* `script` - JavaScript files for the page.
* `style` - CSS stylesheets for the page.
* `title` - Title of the page.

View File

@ -4,58 +4,36 @@
>
> &mdash; [RESTful Web Services][cite], Leonard Richardson & Sam Ruby.
In order to allow the browsable API to function, there are a couple of browser enhancements that REST framework needs to provide.
As of version 3.3.0 onwards these are enabled with javascript, using the [ajax-form][ajax-form] library.
## Browser based PUT, DELETE, etc...
REST framework supports browser-based `PUT`, `DELETE` and other methods, by
overloading `POST` requests using a hidden form field.
The [AJAX form library][ajax-form] supports browser-based `PUT`, `DELETE` and other methods on HTML forms.
Note that this is the same strategy as is used in [Ruby on Rails][rails].
After including the library, use the `data-method` attribute on the form, like so:
For example, given the following form:
<form action="/news-items/5" method="POST">
<input type="hidden" name="_method" value="DELETE">
<form action="/" data-method="PUT">
<input name='foo'/>
...
</form>
`request.method` would return `"DELETE"`.
## HTTP header based method overriding
REST framework also supports method overriding via the semi-standard `X-HTTP-Method-Override` header. This can be useful if you are working with non-form content such as JSON and are working with an older web server and/or hosting provider that doesn't recognise particular HTTP methods such as `PATCH`. For example [Amazon Web Services ELB][aws_elb].
To use it, make a `POST` request, setting the `X-HTTP-Method-Override` header.
For example, making a `PATCH` request via `POST` in jQuery:
$.ajax({
url: '/myresource/',
method: 'POST',
headers: {'X-HTTP-Method-Override': 'PATCH'},
...
});
Note that prior to 3.3.0, this support was server-side rather than javascript based. The method overloading style (as used in [Ruby on Rails][rails]) is no longer supported due to subtle issues that it introduces in request parsing.
## Browser based submission of non-form content
Browser-based submission of content types other than form are supported by
using form fields named `_content` and `_content_type`:
Browser-based submission of content types such as JSON are supported by the [AJAX form library][ajax-form], using form fields with `data-override='content-type'` and `data-override='content'` attributes.
For example, given the following form:
For example:
<form action="/news-items/5" method="PUT">
<input type="hidden" name="_content_type" value="application/json">
<input name="_content" value="{'count': 1}">
</form>
<form action="/">
<input data-override='content-type' value='application/json' type='hidden'/>
<textarea data-override='content'>{}</textarea>
<input type="submit"/>
</form>
`request.content_type` would return `"application/json"`, and
`request.stream` would return `"{'count': 1}"`
## URL based accept headers
REST framework can take `?accept=application/json` style URL parameters,
which allow the `Accept` header to be overridden.
This can be useful for testing the API from a web browser, where you don't
have any control over what is sent in the `Accept` header.
Note that prior to 3.3.0, this support was server-side rather than javascript based.
## URL based format suffixes
@ -63,8 +41,37 @@ REST framework can take `?format=json` style URL parameters, which can be a
useful shortcut for determining which content type should be returned from
the view.
This is a more concise than using the `accept` override, but it also gives
you less control. (For example you can't specify any media type parameters)
This behavior is controlled using the `URL_FORMAT_OVERRIDE` setting.
## HTTP header based method overriding
Prior to version 3.3.0 the semi extension header `X-HTTP-Method-Override` was supported for overriding the request method. This behavior is no longer in core, but can be adding if needed using middleware.
For example:
METHOD_OVERRIDE_HEADER = 'HTTP_X_HTTP_METHOD_OVERRIDE'
class MethodOverrideMiddleware(object):
def process_view(self, request, callback, callback_args, callback_kwargs):
if request.method != 'POST':
return
if METHOD_OVERRIDE_HEADER not in request.META:
return
request.method = request.META[METHOD_OVERRIDE_HEADER]
## URL based accept headers
Until version 3.3.0 REST framework included built-in support for `?accept=application/json` style URL parameters, which would allow the `Accept` header to be overridden.
Since the introduction of the content negotiation API this behavior is no longer included in core, but may be added using a custom content negotiation class, if needed.
For example:
class AcceptQueryParamOverride()
def get_accept_list(self, request):
header = request.META.get('HTTP_ACCEPT', '*/*')
header = request.query_params.get('_accept', header)
return [token.strip() for token in header.split(',')]
## Doesn't HTML5 support PUT and DELETE forms?
@ -74,7 +81,7 @@ was later [dropped from the spec][html5]. There remains
as well as how to support content types other than form-encoded data.
[cite]: http://www.amazon.com/Restful-Web-Services-Leonard-Richardson/dp/0596529260
[ajax-form]: https://github.com/tomchristie/ajax-form
[rails]: http://guides.rubyonrails.org/form_helpers.html#how-do-forms-with-put-or-delete-methods-work
[html5]: http://www.w3.org/TR/html5-diff/#changes-2010-06-24
[put_delete]: http://amundsen.com/examples/put-delete-forms/
[aws_elb]: https://forums.aws.amazon.com/thread.jspa?messageID=400724

314
docs/topics/funding.md Normal file
View File

@ -0,0 +1,314 @@
<script>
// Imperfect, but easier to fit in with the existing docs build.
// Hyperlinks should point directly to the "fund." subdomain, but this'll
// handle the nav bar links without requiring any docs build changes for the moment.
if (window.location.hostname == "www.django-rest-framework.org") {
window.location.replace("https://fund.django-rest-framework.org/topics/funding/");
}
</script>
<style>
.chart {
background-color: #e3e3e3;
background: -webkit-linear-gradient(top, #fff 0, #e3e3e3 100%);
border: 1px solid #E6E6E6;
border-radius: 5px;
box-shadow: 0px 0px 2px 0px rgba(181, 181, 181, 0.3);
padding: 40px 0px 5px;
position: relative;
text-align: center;
width: 97%;
min-height: 255px;
position: relative;
top: 37px;
margin-bottom: 20px }
.quantity {
text-align: center }
.dollar {
font-size: 19px;
position: relative;
top: -18px;
}
.price {
font-size: 49px; }
.period {
font-size: 17px;
position: relative;
top: -8px;
margin-left: 4px; }
.plan-name {
text-align: center;
font-size: 20px;
font-weight: 400;
color: #777;
border-bottom: 1px solid #d5d5d5;
padding-bottom: 15px;
width: 90%;
margin: 0 auto;
margin-top: 8px; }
.specs {
margin-top: 20px; }
.specs.startup {
margin-bottom: 93px }
.spec {
font-size: 15px;
color: #474747;
text-align: center;
font-weight: 300;
margin-bottom: 13px; }
.variable {
color: #1FBEE7;
font-weight: 400; }
form.signup {
margin-top: 35px }
.clear-promo {
padding-top: 30px }
#main-content h1:first-of-type {
margin: 0 0 50px;
font-size: 60px;
font-weight: 200;
text-align: center
}
#main-content {
padding-top: 10px; line-height: 23px
}
#main-content li {
line-height: 23px
}
</style>
# Funding
If you use REST framework commercially we strongly encourage you to invest in its continued development by signing up for a paid plan.
**We believe that collaboratively funded software can offer outstanding returns on investment, by allowing users and clients to collectively share the cost of development.**
Signing up for a paid plan will:
* Directly contribute to faster releases, more features and higher quality software.
* Allow more time to be invested in documentation, issue triage and community support.
* Safeguard the future development of REST framework.
REST framework will always be open source and permissively licensed, but we firmly believe it is in the commercial best-interest for users of the project to fund its ongoing development.
---
## Making the business case
Our successful Kickstarter campaign demonstrates the cost-reward ratio of shared development funding.
With *typical corporate fundings of just £100-£1000 per organization* we successfully delivered:
* The comprehensive 3.0 serializer redesign.
* Substantial improvements to the Browsable API.
* The admin interface.
* A new pagination API including offset/limit and cursor pagination implementations, plus on-page controls.
* A versioning API, including URL-based and header-based versioning schemes.
* Support for customizable exception handling.
* Support for Django's PostgreSQL HStoreField, ArrayField and JSONField.
* Templated HTML form support, including HTML forms with nested list and objects.
* Internationalization support for API responses, currently with 27 languages.
* The metadata APIs for handling `OPTIONS` requests and schema endpoints.
* Numerous minor improvements and better quality throughout the codebase.
* Ongoing triage and community support, closing over 1600 tickets.
This incredible level of return on investment is *only possible through collaboratively funded models*, which is why we believe that supporting our paid plans is in everyone's best interest.
---
## Individual plan
This subscription is recommended for freelancers and other individuals with an interest in seeing REST framework continue to&nbsp;improve.
If you are using REST framework as an full-time employee, consider recommending that your company takes out a [corporate&nbsp;plan](#corporate-plans).
<div class="pricing">
<div class="span4">
<div class="chart first">
<div class="quantity">
<span class="dollar">$</span>
<span class="price">15</span>
<span class="period">/month</span>
</div>
<div class="plan-name">Individual</div>
<div class="specs">
<div class="spec">
Support ongoing development
</div>
<div class="spec">
Credited on the site
</div>
</div>
<form class="signup" action="/signup/individual/" method="POST">
<script
src="https://checkout.stripe.com/checkout.js" class="stripe-button"
data-key="{{ stripe_public }}"
data-amount="1500"
data-name="Django REST framework"
data-description="Individual"
data-currency="usd"
data-allow-remember-me=false
data-billing-address=true
data-label='Sign up'
data-panel-label='Sign up - {% verbatim %}{{amount}}{% endverbatim %}/mo'>
</script>
</form>
</div>
</div>
</div>
<div style="clear: both; padding-top: 50px"></div>
*Billing is monthly and you can cancel at any time.*
---
## Corporate plans
These subscriptions are recommended for companies and organizations using REST framework either publicly or privately.
In exchange for funding you'll also receive advertising space on our site, allowing you to **promote your company or product to many tens of thousands of developers worldwide**.
Our professional and premium plans also include **priority support**. At any time your engineers can escalate an issue or discussion group thread, and we'll ensure it gets a guaranteed response within the next working day.
<div class="pricing">
<div class="span4">
<div class="chart first">
<div class="quantity">
<span class="dollar">$</span>
<span class="price">50</span>
<span class="period">/month</span>
</div>
<div class="plan-name">Basic</div>
<div class="specs startup">
<div class="spec">
Support ongoing development
</div>
<div class="spec">
<span class="variable">Funding page</span> ad placement
</div>
</div>
<form class="signup" action="/signup/startup/" method="POST">
<script
src="https://checkout.stripe.com/checkout.js" class="stripe-button"
data-key="{{ stripe_public }}"
data-amount="5000"
data-name="Django REST framework"
data-description="Basic"
data-currency="usd"
data-allow-remember-me=false
data-billing-address=true
data-label='Sign up'
data-panel-label='Sign up - {% verbatim %}{{amount}}{% endverbatim %}/mo'>
</script>
</form>
</div>
</div>
<div class="span4">
<div class="chart">
<div class="quantity">
<span class="dollar">$</span>
<span class="price">250</span>
<span class="period">/month</span>
</div>
<div class="plan-name">Professional</div>
<div class="specs">
<div class="spec">
Add a <span class="variable">half day per&nbsp;month</span> development time to the project
</div>
<div class="spec">
<span class="variable">Homepage</span> ad placement
</div>
<div class="spec">
<span class="variable">Priority support</span> for your engineers
</div>
</div>
<form class="signup" action="/signup/professional/" method="POST">
<script
src="https://checkout.stripe.com/checkout.js" class="stripe-button"
data-key="{{ stripe_public }}"
data-amount="25000"
data-name="Django REST framework"
data-description="Professional"
data-currency="usd"
data-allow-remember-me=false
data-billing-address=true
data-label='Sign up'
data-panel-label='Sign up - {% verbatim %}{{amount}}{% endverbatim %}/mo'>
</script>
</form>
</div>
</div>
<div class="span4">
<div class="chart last">
<div class="quantity">
<span class="dollar">$</span>
<span class="price">500</span>
<span class="period">/month</span>
</div>
<div class="plan-name">Premium</div>
<div class="specs">
<div class="spec">
Add <span class="variable">one full day per&nbsp;month</span> development time to the project
</div>
<div class="spec">
<span class="variable">Full site</span> ad placement
</div>
<div class="spec">
<span class="variable">Priority support</span> for your engineers
</div>
</div>
<form class="signup" action="/signup/premium/" method="POST">
<script
src="https://checkout.stripe.com/checkout.js" class="stripe-button"
data-key="{{ stripe_public }}"
data-amount="50000"
data-name="Django REST framework"
data-description="Premium"
data-currency="usd"
data-allow-remember-me=false
data-billing-address=true
data-label='Sign up'
data-panel-label='Sign up - {% verbatim %}{{amount}}{% endverbatim %}/mo'>
</script>
</form>
</div>
</div>
</div>
<div style="clear: both; padding-top: 50px"></div>
*Billing is monthly and you can cancel at any time.*
Once you've signed up we'll contact you via email and arrange your ad placements on the site.
For further enquires please contact <a href=mailto:tom@tomchristie.com>tom@tomchristie.com</a>.
---
## Roadmap
Although we're incredibly proud of REST framework in its current state we believe there is still huge scope for improvement. What we're aiming for here is a *highly polished, rock solid product*. This needs to backed up with impeccable documentation and a great third party ecosystem.
The roadmap below is a broad indication of just some of the ongoing and future work we believe is important to REST framework.
* Increasing our "bus factor" through documented organizational process & safeguards.
* More time towards testing and hardening releases, with only gradual, well-documented deprecations.
* A formal policy on security backports for non-current releases.
* Continuing triage & community support.
* Improved project documentation, including versioned & internationalized docs.
* Improved third party package visibility.
* Refining the admin interface, ensuring it has a fully customizable API and making it suitable as end-user facing application.
* Cleaning up internal complexities including the `BrowsableAPIRenderer` and `Request` object.
* Support for alternative backends such as SQLAlchemy.
* Support for non-database backed services.
* HTTP Caching API & support for conditional database lookups.
* Benchmarking and performance improvements.
* In depth documentation on advanced usage and best practices.
* Documentation & support for integration with realtime systems.
* Hypermedia support and client libraries.
* Support for JSON schema as endpoints or `OPTIONS` responses.
* API metric tools.
* Debug & logging tools.
* Third party GraphQL support.
By taking out a paid plan you'll be directly contributing towards making these features happen.

View File

@ -0,0 +1,219 @@
# HTML & Forms
REST framework is suitable for returning both API style responses, and regular HTML pages. Additionally, serializers can used as HTML forms and rendered in templates.
## Rendering HTML
In order to return HTML responses you'll need to either `TemplateHTMLRenderer`, or `StaticHTMLRenderer`.
The `TemplateHTMLRenderer` class expects the response to contain a dictionary of context data, and renders an HTML page based on a template that must be specified either in the view or on the response.
The `StaticHTMLRender` class expects the response to contain a string of the pre-rendered HTML content.
Because static HTML pages typically have different behavior from API responses you'll probably need to write any HTML views explicitly, rather than relying on the built-in generic views.
Here's an example of a view that returns a list of "Profile" instances, rendered in an HTML template:
**views.py**:
from my_project.example.models import Profile
from rest_framework.renderers import TemplateHTMLRenderer
from rest_framework.response import Response
from rest_framework.views import APIView
class ProfileList(APIView):
renderer_classes = [TemplateHTMLRenderer]
template_name = 'profile_list.html'
def get(self, request):
queryset = Profile.objects.all()
return Response({'profiles': queryset})
**profile_list.html**:
<html><body>
<h1>Profiles</h1>
<ul>
{% for profile in profiles %}
<li>{{ profile.name }}</li>
{% endfor %}
</ul>
</body></html>
## Rendering Forms
Serializers may be rendered as forms by using the `render_form` template tag, and including the serializer instance as context to the template.
The following view demonstrates an example of using a serializer in a template for viewing and updating a model instance:
**views.py**:
from django.shortcuts import get_object_or_404
from my_project.example.models import Profile
from rest_framework.renderers import TemplateHTMLRenderer
from rest_framework.views import APIView
class ProfileDetail(APIView):
renderer_classes = [TemplateHTMLRenderer]
template_name = 'profile_detail.html'
def get(self, request, pk):
profile = get_object_or_404(Profile, pk=pk)
serializer = ProfileSerializer(profile)
return Response({'serializer': serializer, 'profile': profile})
def post(self, request, pk):
profile = get_object_or_404(Profile, pk=pk)
serializer = ProfileSerializer(profile)
if not serializer.is_valid():
return Response({'serializer': serializer, 'profile': profile})
return redirect('profile-list')
**profile_detail.html**:
{% load rest_framework %}
<html><body>
<h1>Profile - {{ profile.name }}</h1>
<form action="{% url 'profile-detail' pk=profile.pk %}" method="POST">
{% csrf_token %}
{% render_form serializer %}
<input type="submit" value="Save">
</form>
</body></html>
### Using template packs
The `render_form` tag takes an optional `template_pack` argument, that specifies which template directory should be used for rendering the form and form fields.
REST framework includes three built-in template packs, all based on Bootstrap 3. The built-in styles are `horizontal`, `vertical`, and `inline`. The default style is `horizontal`. To use any of these template packs you'll want to also include the Bootstrap 3 CSS.
The following HTML will link to a CDN hosted version of the Bootstrap 3 CSS:
<head>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
</head>
Third party packages may include alternate template packs, by bundling a template directory containing the necessary form and field templates.
Let's take a look at how to render each of the three available template packs. For these examples we'll use a single serializer class to present a "Login" form.
class LoginSerializer(serializers.Serializer):
email = serializers.EmailField(
max_length=100,
style={'placeholder': 'Email'}
)
password = serializers.CharField(
max_length=100,
style={'input_type': 'password', 'placeholder': 'Password'}
)
remember_me = serializers.BooleanField()
---
#### `rest_framework/vertical`
Presents form labels above their corresponding control inputs, using the standard Bootstrap layout.
*This is the default template pack.*
{% load rest_framework %}
...
<form action="{% url 'login' %}" method="post" novalidate>
{% csrf_token %}
{% render_form serializer template_pack='rest_framework/vertical' %}
<button type="submit" class="btn btn-default">Sign in</button>
</form>
![Vertical form example](../img/vertical.png)
---
#### `rest_framework/horizontal`
Presents labels and controls alongside each other, using a 2/10 column split.
*This is the form style used in the browsable API and admin renderers.*
{% load rest_framework %}
...
<form class="form-horizontal" action="{% url 'login' %}" method="post" novalidate>
{% csrf_token %}
{% render_form serializer %}
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-default">Sign in</button>
</div>
</div>
</form>
![Horizontal form example](../img/horizontal.png)
---
#### `rest_framework/inline`
A compact form style that presents all the controls inline.
{% load rest_framework %}
...
<form class="form-inline" action="{% url 'login' %}" method="post" novalidate>
{% csrf_token %}
{% render_form serializer template_pack='rest_framework/inline' %}
<button type="submit" class="btn btn-default">Sign in</button>
</form>
![Inline form example](../img/inline.png)
## Field styles
Serializer fields can have their rendering style customized by using the `style` keyword argument. This argument is a dictionary of options that control the template and layout used.
The most common way to customize the field style is to use the `base_template` style keyword argument to select which template in the template pack should be use.
For example, to render a `CharField` as an HTML textarea rather than the default HTML input, you would use something like this:
details = serializers.CharField(
max_length=1000,
style={'base_template': 'textarea.html'}
)
If you instead want a field to be rendered using a custom template that is *not part of an included template pack*, you can instead use the `template` style option, to fully specify a template name:
details = serializers.CharField(
max_length=1000,
style={'template': 'my-field-templates/custom-input.html'}
)
Field templates can also use additional style properties, depending on their type. For example, the `textarea.html` template also accepts a `rows` property that can be used to affect the sizing of the control.
details = serializers.CharField(
max_length=1000,
style={'base_template': 'textarea.html', 'rows': 10}
)
The complete list of `base_template` options and their associated style options is listed below.
base_template | Valid field types | Additional style options
----|----|----
input.html | Any string, numeric or date/time field | input_type, placeholder, hide_label
textarea.html | `CharField` | rows, placeholder, hide_label
select.html | `ChoiceField` or relational field types | hide_label
radio.html | `ChoiceField` or relational field types | inline, hide_label
select_multiple.html | `MultipleChoiceField` or relational fields with `many=True` | hide_label
checkbox_multiple.html | `MultipleChoiceField` or relational fields with `many=True` | inline, hide_label
checkbox.html | `BooleanField` | hide_label
fieldset.html | Nested serializer | hide_label
list_fieldset.html | `ListField` or nested serializer with `many=True` | hide_label

View File

@ -38,6 +38,142 @@ You can determine your currently installed version using `pip freeze`:
---
## 3.3.x series
### 3.3.2
**Date**: [14th December 2015][3.3.2-milestone].
* `ListField` enforces input is a list. ([#3513][gh3513])
* Fix regression hiding raw data form. ([#3600][gh3600], [#3578][gh3578])
* Fix Python 3.5 compatibility. ([#3534][gh3534], [#3626][gh3626])
* Allow setting a custom Django Paginator in `pagination.PageNumberPagination`. ([#3631][gh3631], [#3684][gh3684])
* Fix relational fields without `to_fields` attribute. ([#3635][gh3635], [#3634][gh3634])
* Fix `template.render` deprecation warnings for Django 1.9. ([#3654][gh3654])
* Sort response headers in browsable API renderer. ([#3655][gh3655])
* Use related_objects api for Django 1.9+. ([#3656][gh3656], [#3252][gh3252])
* Add confirm modal when deleting. ([#3228][gh3228], [#3662][gh3662])
* Reveal previously hidden AttributeErrors and TypeErrors while calling has_[object_]permissions. ([#3668][gh3668])
* Make DRF compatible with multi template engine in Django 1.8. ([#3672][gh3672])
* Update `NestedBoundField` to also handle empty string when rendering its form. ([#3677][gh3677])
* Fix UUID validation to properly catch invalid input types. ([#3687][gh3687], [#3679][gh3679])
* Fix caching issues. ([#3628][gh3628], [#3701][gh3701])
* Fix Admin and API browser for views without a filter_class. ([#3705][gh3705], [#3596][gh3596], [#3597][gh3597])
* Add app_name to rest_framework.urls. ([#3714][gh3714])
* Improve authtoken's views to support url versioning. ([#3718][gh3718], [#3723][gh3723])
### 3.3.1
**Date**: [4th November 2015][3.3.1-milestone].
* Resolve parsing bug when accessing `request.POST` ([#3592][gh3592])
* Correctly deal with `to_field` referring to primary key. ([#3593][gh3593])
* Allow filter HTML to render when no `filter_class` is defined. ([#3560][gh3560])
* Fix admin rendering issues. ([#3564][gh3564], [#3556][gh3556])
* Fix issue with DecimalValidator. ([#3568][gh3568])
### 3.3.0
**Date**: [28th October 2015][3.3.0-milestone].
* HTML controls for filters. ([#3315][gh3315])
* Forms API. ([#3475][gh3475])
* AJAX browsable API. ([#3410][gh3410])
* Added JSONField. ([#3454][gh3454])
* Correctly map `to_field` when creating `ModelSerializer` relational fields. ([#3526][gh3526])
* Include keyword arguments when mapping `FilePathField` to a serializer field. ([#3536][gh3536])
* Map appropriate model `error_messages` on `ModelSerializer` uniqueness constraints. ([#3435][gh3435])
* Include `max_length` constraint for `ModelSerializer` fields mapped from TextField. ([#3509][gh3509])
* Added support for Django 1.9. ([#3450][gh3450], [#3525][gh3525])
* Removed support for Django 1.5 & 1.6. ([#3421][gh3421], [#3429][gh3429])
* Removed 'south' migrations. ([#3495][gh3495])
## 3.2.x series
### 3.2.5
**Date**: [27th October 2015][3.2.5-milestone].
* Escape `username` in optional logout tag. ([#3550][gh3550])
### 3.2.4
**Date**: [21th September 2015][3.2.4-milestone].
* Don't error on missing `ViewSet.search_fields` attribute. ([#3324][gh3324], [#3323][gh3323])
* Fix `allow_empty` not working on serializers with `many=True`. ([#3361][gh3361], [#3364][gh3364])
* Let `DurationField` accepts integers. ([#3359][gh3359])
* Multi-level dictionaries not supported in multipart requests. ([#3314][gh3314])
* Fix `ListField` truncation on HTTP PATCH ([#3415][gh3415], [#2761][gh2761])
### 3.2.3
**Date**: [24th August 2015][3.2.3-milestone].
* Added `html_cutoff` and `html_cutoff_text` for limiting select dropdowns. ([#3313][gh3313])
* Added regex style to `SearchFilter`. ([#3316][gh3316])
* Resolve issues with setting blank HTML fields. ([#3318][gh3318]) ([#3321][gh3321])
* Correctly display existing 'select multiple' values in browsable API forms. ([#3290][gh3290])
* Resolve duplicated validation message for `IPAddressField`. ([#3249[gh3249]) ([#3250][gh3250])
* Fix to ensure admin renderer continues to work when pagination is disabled. ([#3275][gh3275])
* Resolve error with `LimitOffsetPagination` when count=0, offset=0. ([#3303][gh3303])
### 3.2.2
**Date**: [13th August 2015][3.2.2-milestone].
* Add `display_value()` method for use when displaying relational field select inputs. ([#3254][gh3254])
* Fix issue with `BooleanField` checkboxes incorrectly displaying as checked. ([#3258][gh3258])
* Ensure empty checkboxes properly set `BooleanField` to `False` in all cases. ([#2776][gh2776])
* Allow `WSGIRequest.FILES` property without raising incorrect deprecated error. ([#3261][gh3261])
* Resolve issue with rendering nested serializers in forms. ([#3260][gh3260])
* Raise an error if user accidentally pass a serializer instance to a response, rather than data. ([#3241][gh3241])
### 3.2.1
**Date**: [7th August 2015][3.2.1-milestone].
* Fix for relational select widgets rendering without any choices. ([#3237][gh3237])
* Fix for `1`, `0` rendering as `true`, `false` in the admin interface. [#3227][gh3227])
* Fix for ListFields with single value in HTML form input. ([#3238][gh3238])
* Allow `request.FILES` for compat with Django's `HTTPRequest` class. ([#3239][gh3239])
### 3.2.0
**Date**: [6th August 2015][3.2.0-milestone].
* Add `AdminRenderer`. ([#2926][gh2926])
* Add `FilePathField`. ([#1854][gh1854])
* Add `allow_empty` to `ListField`. ([#2250][gh2250])
* Support django-guardian 1.3. ([#3165][gh3165])
* Support grouped choices. ([#3225][gh3225])
* Support error forms in browsable API. ([#3024][gh3024])
* Allow permission classes to customize the error message. ([#2539][gh2539])
* Support `source=<method>` on hyperlinked fields. ([#2690][gh2690])
* `ListField(allow_null=True)` now allows null as the list value, not null items in the list. ([#2766][gh2766])
* `ManyToMany()` maps to `allow_empty=False`, `ManyToMany(blank=True)` maps to `allow_empty=True`. ([#2804][gh2804])
* Support custom serialization styles for primary key fields. ([#2789][gh2789])
* `OPTIONS` requests support nested representations. ([#2915][gh2915])
* Set `view.action == "metadata"` for viewsets with `OPTIONS` requests. ([#3115][gh3115])
* Support `allow_blank` on `UUIDField`. ([#3130][gh#3130])
* Do not display view docstrings with 401 or 403 response codes. ([#3216][gh3216])
* Resolve Django 1.8 deprecation warnings. ([#2886][gh2886])
* Fix for `DecimalField` validation. ([#3139][gh3139])
* Fix behavior of `allow_blank=False` when used with `trim_whitespace=True`. ([#2712][gh2712])
* Fix issue with some field combinations incorrectly mapping to an invalid `allow_blank` argument. ([#3011][gh3011])
* Fix for output representations with prefetches and modified querysets. ([#2704][gh2704], [#2727][gh2727])
* Fix assertion error when CursorPagination is provided with certains invalid query parameters. (#2920)[gh2920].
* Fix `UnicodeDecodeError` when invalid characters included in header with `TokenAuthentication`. ([#2928][gh2928])
* Fix transaction rollbacks with `@non_atomic_requests` decorator. ([#3016][gh3016])
* Fix duplicate results issue with Oracle databases using `SearchFilter`. ([#2935][gh2935])
* Fix checkbox alignment and rendering in browsable API forms. ([#2783][gh2783])
* Fix for unsaved file objects which should use `"url": null` in the representation. ([#2759][gh2759])
* Fix field value rendering in browsable API. ([#2416][gh2416])
* Fix `HStoreField` to include `allow_blank=True` in `DictField` mapping. ([#2659][gh2659])
* Numerous other cleanups, improvements to error messaging, private API & minor fixes.
---
## 3.1.x series
### 3.1.3
@ -225,6 +361,15 @@ For older release notes, [please see the version 2.x documentation][old-release-
[3.1.1-milestone]: https://github.com/tomchristie/django-rest-framework/issues?q=milestone%3A%223.1.1+Release%22
[3.1.2-milestone]: https://github.com/tomchristie/django-rest-framework/issues?q=milestone%3A%223.1.2+Release%22
[3.1.3-milestone]: https://github.com/tomchristie/django-rest-framework/issues?q=milestone%3A%223.1.3+Release%22
[3.2.0-milestone]: https://github.com/tomchristie/django-rest-framework/issues?q=milestone%3A%223.2.0+Release%22
[3.2.1-milestone]: https://github.com/tomchristie/django-rest-framework/issues?q=milestone%3A%223.2.1+Release%22
[3.2.2-milestone]: https://github.com/tomchristie/django-rest-framework/issues?q=milestone%3A%223.2.2+Release%22
[3.2.3-milestone]: https://github.com/tomchristie/django-rest-framework/issues?q=milestone%3A%223.2.3+Release%22
[3.2.4-milestone]: https://github.com/tomchristie/django-rest-framework/issues?q=milestone%3A%223.2.4+Release%22
[3.2.5-milestone]: https://github.com/tomchristie/django-rest-framework/issues?q=milestone%3A%223.2.5+Release%22
[3.3.0-milestone]: https://github.com/tomchristie/django-rest-framework/issues?q=milestone%3A%223.3.0+Release%22
[3.3.1-milestone]: https://github.com/tomchristie/django-rest-framework/issues?q=milestone%3A%223.3.1+Release%22
[3.3.2-milestone]: https://github.com/tomchristie/django-rest-framework/issues?q=milestone%3A%223.3.2+Release%22
<!-- 3.0.1 -->
[gh2013]: https://github.com/tomchristie/django-rest-framework/issues/2013
@ -382,3 +527,125 @@ For older release notes, [please see the version 2.x documentation][old-release-
[gh2618]: https://github.com/tomchristie/django-rest-framework/issues/2618
[gh3008]: https://github.com/tomchristie/django-rest-framework/issues/3008
[gh2695]: https://github.com/tomchristie/django-rest-framework/issues/2695
<!-- 3.2.0 -->
[gh1854]: https://github.com/tomchristie/django-rest-framework/issues/1854
[gh2250]: https://github.com/tomchristie/django-rest-framework/issues/2250
[gh2416]: https://github.com/tomchristie/django-rest-framework/issues/2416
[gh2539]: https://github.com/tomchristie/django-rest-framework/issues/2539
[gh2659]: https://github.com/tomchristie/django-rest-framework/issues/2659
[gh2690]: https://github.com/tomchristie/django-rest-framework/issues/2690
[gh2704]: https://github.com/tomchristie/django-rest-framework/issues/2704
[gh2712]: https://github.com/tomchristie/django-rest-framework/issues/2712
[gh2727]: https://github.com/tomchristie/django-rest-framework/issues/2727
[gh2759]: https://github.com/tomchristie/django-rest-framework/issues/2759
[gh2766]: https://github.com/tomchristie/django-rest-framework/issues/2766
[gh2783]: https://github.com/tomchristie/django-rest-framework/issues/2783
[gh2789]: https://github.com/tomchristie/django-rest-framework/issues/2789
[gh2804]: https://github.com/tomchristie/django-rest-framework/issues/2804
[gh2886]: https://github.com/tomchristie/django-rest-framework/issues/2886
[gh2915]: https://github.com/tomchristie/django-rest-framework/issues/2915
[gh2920]: https://github.com/tomchristie/django-rest-framework/issues/2920
[gh2926]: https://github.com/tomchristie/django-rest-framework/issues/2926
[gh2928]: https://github.com/tomchristie/django-rest-framework/issues/2928
[gh2935]: https://github.com/tomchristie/django-rest-framework/issues/2935
[gh3011]: https://github.com/tomchristie/django-rest-framework/issues/3011
[gh3016]: https://github.com/tomchristie/django-rest-framework/issues/3016
[gh3024]: https://github.com/tomchristie/django-rest-framework/issues/3024
[gh3115]: https://github.com/tomchristie/django-rest-framework/issues/3115
[gh3139]: https://github.com/tomchristie/django-rest-framework/issues/3139
[gh3165]: https://github.com/tomchristie/django-rest-framework/issues/3165
[gh3216]: https://github.com/tomchristie/django-rest-framework/issues/3216
[gh3225]: https://github.com/tomchristie/django-rest-framework/issues/3225
<!-- 3.2.1 -->
[gh3237]: https://github.com/tomchristie/django-rest-framework/issues/3237
[gh3227]: https://github.com/tomchristie/django-rest-framework/issues/3227
[gh3238]: https://github.com/tomchristie/django-rest-framework/issues/3238
[gh3239]: https://github.com/tomchristie/django-rest-framework/issues/3239
<!-- 3.2.2 -->
[gh3254]: https://github.com/tomchristie/django-rest-framework/issues/3254
[gh3258]: https://github.com/tomchristie/django-rest-framework/issues/3258
[gh2776]: https://github.com/tomchristie/django-rest-framework/issues/2776
[gh3261]: https://github.com/tomchristie/django-rest-framework/issues/3261
[gh3260]: https://github.com/tomchristie/django-rest-framework/issues/3260
[gh3241]: https://github.com/tomchristie/django-rest-framework/issues/3241
<!-- 3.2.3 -->
[gh3249]: https://github.com/tomchristie/django-rest-framework/issues/3249
[gh3250]: https://github.com/tomchristie/django-rest-framework/issues/3250
[gh3275]: https://github.com/tomchristie/django-rest-framework/issues/3275
[gh3288]: https://github.com/tomchristie/django-rest-framework/issues/3288
[gh3290]: https://github.com/tomchristie/django-rest-framework/issues/3290
[gh3303]: https://github.com/tomchristie/django-rest-framework/issues/3303
[gh3313]: https://github.com/tomchristie/django-rest-framework/issues/3313
[gh3316]: https://github.com/tomchristie/django-rest-framework/issues/3316
[gh3318]: https://github.com/tomchristie/django-rest-framework/issues/3318
[gh3321]: https://github.com/tomchristie/django-rest-framework/issues/3321
<!-- 3.2.4 -->
[gh2761]: https://github.com/tomchristie/django-rest-framework/issues/2761
[gh3314]: https://github.com/tomchristie/django-rest-framework/issues/3314
[gh3323]: https://github.com/tomchristie/django-rest-framework/issues/3323
[gh3324]: https://github.com/tomchristie/django-rest-framework/issues/3324
[gh3359]: https://github.com/tomchristie/django-rest-framework/issues/3359
[gh3361]: https://github.com/tomchristie/django-rest-framework/issues/3361
[gh3364]: https://github.com/tomchristie/django-rest-framework/issues/3364
[gh3415]: https://github.com/tomchristie/django-rest-framework/issues/3415
<!-- 3.2.5 -->
[gh3550]:https://github.com/tomchristie/django-rest-framework/issues/3550
<!-- 3.3.0 -->
[gh3315]: https://github.com/tomchristie/django-rest-framework/issues/3315
[gh3410]: https://github.com/tomchristie/django-rest-framework/issues/3410
[gh3435]: https://github.com/tomchristie/django-rest-framework/issues/3435
[gh3450]: https://github.com/tomchristie/django-rest-framework/issues/3450
[gh3454]: https://github.com/tomchristie/django-rest-framework/issues/3454
[gh3475]: https://github.com/tomchristie/django-rest-framework/issues/3475
[gh3495]: https://github.com/tomchristie/django-rest-framework/issues/3495
[gh3509]: https://github.com/tomchristie/django-rest-framework/issues/3509
[gh3421]: https://github.com/tomchristie/django-rest-framework/issues/3421
[gh3525]: https://github.com/tomchristie/django-rest-framework/issues/3525
[gh3526]: https://github.com/tomchristie/django-rest-framework/issues/3526
[gh3429]: https://github.com/tomchristie/django-rest-framework/issues/3429
[gh3536]: https://github.com/tomchristie/django-rest-framework/issues/3536
<!-- 3.3.1 -->
[gh3556]: https://github.com/tomchristie/django-rest-framework/issues/3556
[gh3560]: https://github.com/tomchristie/django-rest-framework/issues/3560
[gh3564]: https://github.com/tomchristie/django-rest-framework/issues/3564
[gh3568]: https://github.com/tomchristie/django-rest-framework/issues/3568
[gh3592]: https://github.com/tomchristie/django-rest-framework/issues/3592
[gh3593]: https://github.com/tomchristie/django-rest-framework/issues/3593
<!-- 3.3.2 -->
[gh3228]: https://github.com/tomchristie/django-rest-framework/issues/3228
[gh3252]: https://github.com/tomchristie/django-rest-framework/issues/3252
[gh3513]: https://github.com/tomchristie/django-rest-framework/issues/3513
[gh3534]: https://github.com/tomchristie/django-rest-framework/issues/3534
[gh3578]: https://github.com/tomchristie/django-rest-framework/issues/3578
[gh3596]: https://github.com/tomchristie/django-rest-framework/issues/3596
[gh3597]: https://github.com/tomchristie/django-rest-framework/issues/3597
[gh3600]: https://github.com/tomchristie/django-rest-framework/issues/3600
[gh3626]: https://github.com/tomchristie/django-rest-framework/issues/3626
[gh3628]: https://github.com/tomchristie/django-rest-framework/issues/3628
[gh3631]: https://github.com/tomchristie/django-rest-framework/issues/3631
[gh3634]: https://github.com/tomchristie/django-rest-framework/issues/3634
[gh3635]: https://github.com/tomchristie/django-rest-framework/issues/3635
[gh3654]: https://github.com/tomchristie/django-rest-framework/issues/3654
[gh3655]: https://github.com/tomchristie/django-rest-framework/issues/3655
[gh3656]: https://github.com/tomchristie/django-rest-framework/issues/3656
[gh3662]: https://github.com/tomchristie/django-rest-framework/issues/3662
[gh3668]: https://github.com/tomchristie/django-rest-framework/issues/3668
[gh3672]: https://github.com/tomchristie/django-rest-framework/issues/3672
[gh3677]: https://github.com/tomchristie/django-rest-framework/issues/3677
[gh3679]: https://github.com/tomchristie/django-rest-framework/issues/3679
[gh3684]: https://github.com/tomchristie/django-rest-framework/issues/3684
[gh3687]: https://github.com/tomchristie/django-rest-framework/issues/3687
[gh3701]: https://github.com/tomchristie/django-rest-framework/issues/3701
[gh3705]: https://github.com/tomchristie/django-rest-framework/issues/3705
[gh3714]: https://github.com/tomchristie/django-rest-framework/issues/3714
[gh3718]: https://github.com/tomchristie/django-rest-framework/issues/3718
[gh3723]: https://github.com/tomchristie/django-rest-framework/issues/3723

View File

@ -32,7 +32,7 @@ REST framework also includes [serialization] and [parser]/[renderer] components
## What REST framework doesn't provide.
What REST framework doesn't do is give you is machine readable hypermedia formats such as [HAL][hal], [Collection+JSON][collection], [JSON API][json-api] or HTML [microformats] by default, or the ability to auto-magically create fully HATEOAS style APIs that include hypermedia-based form descriptions and semantically labelled hyperlinks. Doing so would involve making opinionated choices about API design that should really remain outside of the framework's scope.
What REST framework doesn't do is give you machine readable hypermedia formats such as [HAL][hal], [Collection+JSON][collection], [JSON API][json-api] or HTML [microformats] by default, or the ability to auto-magically create fully HATEOAS style APIs that include hypermedia-based form descriptions and semantically labelled hyperlinks. Doing so would involve making opinionated choices about API design that should really remain outside of the framework's scope.
[cite]: http://vimeo.com/channels/restfest/page:2
[dissertation]: http://www.ics.uci.edu/~fielding/pubs/dissertation/top.htm

View File

@ -195,6 +195,7 @@ To submit new content, [open an issue][drf-create-issue] or [create a pull reque
* [drf-any-permissions][drf-any-permissions] - Provides alternative permission handling.
* [djangorestframework-composed-permissions][djangorestframework-composed-permissions] - Provides a simple way to define complex permissions.
* [rest_condition][rest-condition] - Another extension for building complex permissions in a simple and convenient way.
* [dry-rest-permissions][dry-rest-permissions] - Provides a simple way to define permissions for individual api actions.
### Serializers
@ -211,6 +212,7 @@ To submit new content, [open an issue][drf-create-issue] or [create a pull reque
### Views
* [djangorestframework-bulk][djangorestframework-bulk] - Implements generic view mixins as well as some common concrete generic views to allow to apply bulk operations via API requests.
* [django-rest-multiple-models][django-rest-multiple-models] - Provides a generic view (and mixin) for sending multiple serialized models and/or querysets via a single API request.
### Routers
@ -231,17 +233,22 @@ To submit new content, [open an issue][drf-create-issue] or [create a pull reque
### Filtering
* [djangorestframework-chain][djangorestframework-chain] - Allows arbitrary chaining of both relations and lookup filters.
* [django-url-filter][django-url-filter] - Allows a safe way to filter data via human-friendly URLs. It is a generic library which is not tied to DRF but it provides easy integration with DRF.
### Misc
* [cookiecutter-django-rest][cookiecutter-django-rest] - A cookiecutter template that takes care of the setup and configuration so you can focus on making your REST apis awesome.
* [djangorestrelationalhyperlink][djangorestrelationalhyperlink] - A hyperlinked serialiser that can can be used to alter relationships via hyperlinks, but otherwise like a hyperlink model serializer.
* [django-rest-swagger][django-rest-swagger] - An API documentation generator for Swagger UI.
* [django-rest-framework-proxy][django-rest-framework-proxy] - Proxy to redirect incoming request to another API server.
* [gaiarestframework][gaiarestframework] - Utils for django-rest-framewok
* [gaiarestframework][gaiarestframework] - Utils for django-rest-framework
* [drf-extensions][drf-extensions] - A collection of custom extensions
* [ember-django-adapter][ember-django-adapter] - An adapter for working with Ember.js
* [django-versatileimagefield][django-versatileimagefield] - Provides a drop-in replacement for Django's stock `ImageField` that makes it easy to serve images in multiple sizes/renditions from a single field. For DRF-specific implementation docs, [click here][django-versatileimagefield-drf-docs].
* [drf-tracking][drf-tracking] - Utilities to track requests to DRF API views.
* [django-rest-framework-braces][django-rest-framework-braces] - Collection of utilities for working with Django Rest Framework. The most notable ones are [FormSerializer](https://django-rest-framework-braces.readthedocs.org/en/latest/overview.html#formserializer) and [SerializerForm](https://django-rest-framework-braces.readthedocs.org/en/latest/overview.html#serializerform), which are adapters between DRF serializers and Django forms.
* [drf-haystack][drf-haystack] - Haystack search for Django Rest Framework
* [django-rest-framework-version-transforms][django-rest-framework-version-transforms] - Enables the use of delta transformations for versioning of DRF resource representations.
## Other Resources
@ -286,6 +293,7 @@ To submit new content, [open an issue][drf-create-issue] or [create a pull reque
[drf-create-issue]: https://github.com/tomchristie/django-rest-framework/issues/new
[authentication]: ../api-guide/authentication.md
[permissions]: ../api-guide/permissions.md
[third-party-resources]: ../topics/third-party-resources/#existing-third-party-packages
[discussion-group]: https://groups.google.com/forum/#!forum/django-rest-framework
[djangorestframework-digestauth]: https://github.com/juanriaza/django-rest-framework-digestauth
[django-oauth-toolkit]: https://github.com/evonove/django-oauth-toolkit
@ -303,6 +311,7 @@ To submit new content, [open an issue][drf-create-issue] or [create a pull reque
[drf-compound-fields]: https://github.com/estebistec/drf-compound-fields
[django-extra-fields]: https://github.com/Hipo/drf-extra-fields
[djangorestframework-bulk]: https://github.com/miki725/django-rest-framework-bulk
[django-rest-multiple-models]: https://github.com/Axiologue/DjangoRestMultipleModels
[drf-nested-routers]: https://github.com/alanjds/drf-nested-routers
[wq.db.rest]: http://wq.io/docs/about-rest
[djangorestframework-msgpack]: https://github.com/juanriaza/django-rest-framework-msgpack
@ -336,3 +345,9 @@ To submit new content, [open an issue][drf-create-issue] or [create a pull reque
[django-versatileimagefield-drf-docs]:http://django-versatileimagefield.readthedocs.org/en/latest/drf_integration.html
[cdrf.co]:http://www.cdrf.co
[drf-tracking]: https://github.com/aschn/drf-tracking
[django-rest-framework-braces]: https://github.com/dealertrack/django-rest-framework-braces
[dry-rest-permissions]: https://github.com/Helioscene/dry-rest-permissions
[django-url-filter]: https://github.com/miki725/django-url-filter
[cookiecutter-django-rest]: https://github.com/agconti/cookiecutter-django-rest
[drf-haystack]: http://drf-haystack.readthedocs.org/en/latest/
[django-rest-framework-version-transforms]: https://github.com/mrhwick/django-rest-framework-version-transforms

View File

@ -89,7 +89,6 @@ We'll also need to create an initial migration for our snippet model, and sync t
The first thing we need to get started on our Web API is to provide a way of serializing and deserializing the snippet instances into representations such as `json`. We can do this by declaring serializers that work very similar to Django's forms. Create a file in the `snippets` directory named `serializers.py` and add the following.
from django.forms import widgets
from rest_framework import serializers
from snippets.models import Snippet, LANGUAGE_CHOICES, STYLE_CHOICES
@ -182,7 +181,7 @@ We can also serialize querysets instead of model instances. To do so we simply
serializer = SnippetSerializer(Snippet.objects.all(), many=True)
serializer.data
# [{'pk': 1, 'title': u'', 'code': u'foo = "bar"\n', 'linenos': False, 'language': u'python', 'style': u'friendly'}, {'pk': 2, 'title': u'', 'code': u'print "hello, world"\n', 'linenos': False, 'language': u'python', 'style': u'friendly'}]
# [OrderedDict([('pk', 1), ('title', u''), ('code', u'foo = "bar"\n'), ('linenos', False), ('language', 'python'), ('style', 'friendly')]), OrderedDict([('pk', 2), ('title', u''), ('code', u'print "hello, world"\n'), ('linenos', False), ('language', 'python'), ('style', 'friendly')]), OrderedDict([('pk', 3), ('title', u''), ('code', u'print "hello, world"'), ('linenos', False), ('language', 'python'), ('style', 'friendly')])]
## Using ModelSerializers
@ -318,7 +317,7 @@ Quit out of the shell...
Validating models...
0 errors found
Django version 1.4.3, using settings 'tutorial.settings'
Django version 1.8.3, using settings 'tutorial.settings'
Development server is running at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

View File

@ -108,7 +108,7 @@ and
Now update the `urls.py` file slightly, to append a set of `format_suffix_patterns` in addition to the existing URLs.
from django.conf.urls import patterns, url
from django.conf.urls import url
from rest_framework.urlpatterns import format_suffix_patterns
from snippets import views
@ -157,8 +157,8 @@ We can control the format of the response that we get back, either by using the
Or by appending a format suffix:
http http://127.0.0.1:8000/snippets/.json # JSON suffix
http http://127.0.0.1:8000/snippets/.api # Browsable API suffix
http http://127.0.0.1:8000/snippets.json # JSON suffix
http http://127.0.0.1:8000/snippets.api # Browsable API suffix
Similarly, we can control the format of the request that we send, using the `Content-Type` header.

View File

@ -146,7 +146,7 @@ And, at the end of the file, add a pattern to include the login and logout views
namespace='rest_framework')),
]
The `r'^api-auth/'` part of pattern can actually be whatever URL you want to use. The only restriction is that the included urls must use the `'rest_framework'` namespace.
The `r'^api-auth/'` part of pattern can actually be whatever URL you want to use. The only restriction is that the included urls must use the `'rest_framework'` namespace. In Django 1.9+, REST framework will set the namespace, so you may leave it out.
Now if you open up the browser again and refresh the page you'll see a 'Login' link in the top right of the page. If you log in as one of the users you created earlier, you'll be able to create code snippets again.

View File

@ -45,7 +45,7 @@ Next we're going to replace the `SnippetList`, `SnippetDetail` and `SnippetHighl
return Response(snippet.highlighted)
def perform_create(self, serializer):
serializer.save(owner=self.request.user)
serializer.save(owner=self.request.user)
This time we've used the `ModelViewSet` class in order to get the complete set of default read and write operations.

View File

@ -68,7 +68,7 @@ Right, we'd better write some views then. Open `tutorial/quickstart/views.py` a
"""
API endpoint that allows users to be viewed or edited.
"""
queryset = User.objects.all()
queryset = User.objects.all().order_by('-date_joined')
serializer_class = UserSerializer
@ -83,8 +83,6 @@ Rather than write multiple views we're grouping together all the common behavior
We can easily break these down into individual views if we need to, but using viewsets keeps the view logic nicely organized as well as being very concise.
For trivial cases you can simply set a `model` attribute on the `ViewSet` class and the serializer and queryset will be automatically generated for you. Setting the `queryset` and/or `serializer_class` attributes gives you more explicit control of the API behaviour, and is the recommended style for most applications.
## URLs
Okay, now let's wire up the API URLs. On to `tutorial/urls.py`...

View File

@ -57,12 +57,10 @@
<body onload="prettyPrint()" class="{% if current_page and current_page.is_homepage %}index{% endif %}-page">
<div class="wrapper">
{% include "nav.html" %}
<div class="body-content">
<div class="container-fluid">
<!-- Search Modal -->
<div id="mkdocs_search_modal" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-header">
@ -71,7 +69,7 @@
</div>
<div class="modal-body">
<form role="form">
<form role="form" autocomplete="off">
<div class="form-group">
<input type="text" name="q" class="form-control" placeholder="Search..." id="mkdocs-search-query">
</div>
@ -85,25 +83,16 @@
</div>
<div class="row-fluid">
<div class="span3">
<!-- TODO
<p style="margin-top: -12px">
<a class="btn btn-mini btn-primary" style="width: 60px">&laquo; previous</a>
<a class="btn btn-mini btn-primary" style="float: right; margin-right: 8px; width: 60px;">next &raquo;</a>
</p>
-->
<div id="table-of-contents">
<ul class="nav nav-list side-nav well sidebar-nav-fixed">
{% if current_page and current_page.is_homepage %}
<li class="main">
<a href="#">Django REST framework</a>
</li>
<li class="main">
<a href="#">Django REST framework</a>
</li>
{% endif %}
{% for toc_item in toc %}
<li class="{% if current_page and not current_page.is_homepage %}main{% endif %}">
<a href="{{ toc_item.url }}">{{ toc_item.title }}</a>
</li>
@ -113,25 +102,21 @@
<a href="{{ toc_item.url }}">{{ toc_item.title }}</a>
</li>
{% endfor %}
{% endfor %}
{% if current_page and current_page.is_homepage %}
<div class="promo">
<hr/>
<script type="text/javascript" src="//cdn.fusionads.net/fusion.js?zoneid=1332&serve=C6SDP2Y&placement=djangorestframework" id="_fusionads_js"></script>
</div>
<div class="promo">
<hr/>
<script type="text/javascript" src="//cdn.fusionads.net/fusion.js?zoneid=1332&serve=C6SDP2Y&placement=djangorestframework" id="_fusionads_js"></script>
</div>
{% endif %}
</ul>
</div>
</div>
<div id="main-content" class="span9">
{% block content %}
{% if meta.source %}
{% for filename in meta.source %}
<a class="github" href="https://github.com/tomchristie/django-rest-framework/tree/master/rest_framework/{{ filename }}">
@ -141,23 +126,17 @@
{% endif %}
{{ content }}
{% endblock %}
</div>
<!--/span-->
</div>
<!--/row-->
</div>
<!--/.fluid-container-->
</div>
<!--/.body content-->
</div> <!--/span-->
</div> <!--/row-->
</div> <!--/.fluid-container-->
</div> <!--/.body content-->
<div id="push"></div>
</div>
<!--/.wrapper -->
</div> <!--/.wrapper -->
<footer class="span12">
<p>Documentation built with <a href="http://www.mkdocs.org/">MkDocs</a>.</a>
<p>Documentation built with <a href="http://www.mkdocs.org/">MkDocs</a>.
</p>
</footer>
@ -172,10 +151,10 @@
<script src="{{ base_url }}/js/theme.js"></script>
<script>
//$('.side-nav').scrollspy()
var shiftWindow = function() {
scrollBy(0, -50)
};
if (location.hash) shiftWindow();
window.addEventListener("hashchange", shiftWindow);
@ -183,12 +162,12 @@
event.stopPropagation();
});
// Dynamically force sidenav to no higher than browser window
$('.side-nav').css('max-height', window.innerHeight - 130);
// Dynamically force sidenav/dropdown to no higher than browser window
$('.side-nav, .dropdown-menu').css('max-height', window.innerHeight - 130);
$(function() {
$(window).resize(function() {
$('.side-nav').css('max-height', window.innerHeight - 130);
$('.side-nav, .dropdown-menu').css('max-height', window.innerHeight - 130);
});
});
</script>

View File

@ -5,11 +5,12 @@ pre {
}
.dropdown .dropdown-menu {
display: none;
display: none;
overflow-y: scroll;
}
.dropdown.open .dropdown-menu {
display: block;
display: block;
}
@media (max-width: 480px) {
@ -36,15 +37,8 @@ body.index-page #main-content iframe.github-star-button {
margin-right: -15px;
}
/* Tweet button */
body.index-page #main-content iframe.twitter-share-button {
float: right;
margin-top: -12px;
margin-right: 8px;
}
/* Travis CI badge */
body.index-page #main-content img.travis-build-image {
/* Travis CI and PyPI badge */
body.index-page #main-content img.status-badge {
float: right;
margin-right: 8px;
margin-top: -11px;
@ -182,7 +176,7 @@ body{
}
#main-content h3, #main-content h4, #main-content h5 {
font-weight: 500;
font-weight: 300;
margin-top: 15px
}
@ -419,3 +413,7 @@ ul.sponsor {
#mkdocs_search_modal article p{
word-wrap: break-word;
}
.toclink {
color: #333;
}

View File

@ -1,35 +1,35 @@
function getSearchTerm()
{
var sPageURL = window.location.search.substring(1);
var sURLVariables = sPageURL.split('&');
for (var i = 0; i < sURLVariables.length; i++)
{
var sParameterName = sURLVariables[i].split('=');
if (sParameterName[0] == 'q')
{
return sParameterName[1];
}
var getSearchTerm = function() {
var sPageURL = window.location.search.substring(1);
var sURLVariables = sPageURL.split('&');
for (var i = 0; i < sURLVariables.length; i++) {
var sParameterName = sURLVariables[i].split('=');
if (sParameterName[0] === 'q') {
return sParameterName[1];
}
}
}
};
var initilizeSearch = function() {
require.config({ baseUrl: '/mkdocs/js' });
require(['search']);
};
$(function() {
var searchTerm = getSearchTerm(),
$searchModal = $('#mkdocs_search_modal'),
$searchQuery = $searchModal.find('#mkdocs-search-query'),
$searchResults = $searchModal.find('#mkdocs-search-results');
var initialise_search = function(){
require.config({"baseUrl":"/mkdocs/js"});
require(["search",]);
}
$('pre code').parent().addClass('prettyprint well');
var search_term = getSearchTerm();
if(search_term){
$('#mkdocs_search_modal').modal();
}
$('pre code').parent().addClass('prettyprint well');
$(document).on("submit", "#mkdocs_search_modal form", function (e) {
$("#mkdocs-search-results").html("Searching...");
initialise_search();
return false;
});
if (searchTerm) {
$searchQuery.val(searchTerm);
$searchResults.text('Searching...');
$searchModal.modal();
}
$searchModal.on('shown', function() {
$searchQuery.focus();
initilizeSearch();
});
});

View File

@ -6,6 +6,10 @@ repo_url: https://github.com/tomchristie/django-rest-framework
theme_dir: docs_theme
markdown_extensions:
- toc:
anchorlink: True
pages:
- Home: 'index.md'
- Tutorial:
@ -47,6 +51,7 @@ pages:
- 'Documenting your API': 'topics/documenting-your-api.md'
- 'Internationalization': 'topics/internationalization.md'
- 'AJAX, CSRF & CORS': 'topics/ajax-csrf-cors.md'
- 'HTML & Forms': 'topics/html-and-forms.md'
- 'Browser Enhancements': 'topics/browser-enhancements.md'
- 'The Browsable API': 'topics/browsable-api.md'
- 'REST, Hypermedia & HATEOAS': 'topics/rest-hypermedia-hateoas.md'
@ -55,5 +60,7 @@ pages:
- 'Project management': 'topics/project-management.md'
- '3.0 Announcement': 'topics/3.0-announcement.md'
- '3.1 Announcement': 'topics/3.1-announcement.md'
- '3.2 Announcement': 'topics/3.2-announcement.md'
- '3.3 Announcement': 'topics/3.3-announcement.md'
- 'Kickstarter Announcement': 'topics/kickstarter-announcement.md'
- 'Release Notes': 'topics/release-notes.md'

View File

@ -1,10 +1,10 @@
# The base set of requirements for REST framework is actually
# just Django, but for the purposes of development and testing
# there are a number of packages that it is useful to install.
# there are a number of packages that are useful to install.
# Laying these out as seperate requirements files, allows us to
# only included the relevent sets when running tox, and ensures
# we are only ever declaring out dependancies in one place.
# we are only ever declaring our dependencies in one place.
-r requirements/requirements-optionals.txt
-r requirements/requirements-testing.txt

View File

@ -1,3 +1,6 @@
# PEP8 code linting, which we run on all commits.
flake8==2.4.0
pep8==1.5.7
# Sort and lint imports
isort==4.2.2

View File

@ -1,4 +1,4 @@
# Optional packages which may be used with REST framework.
markdown==2.5.2
django-guardian==1.2.5
django-filter==0.9.2
django-guardian==1.3.0
django-filter==0.10.0

View File

@ -5,4 +5,4 @@ wheel==0.24.0
twine==1.4.0
# Transifex client for managing translation resources.
transifex-client==0.10
transifex-client==0.11

View File

@ -1,3 +1,4 @@
# PyTest for running the tests.
pytest==2.6.4
pytest-django==2.8.0
pytest-cov==1.8.1

View File

@ -8,7 +8,7 @@ ______ _____ _____ _____ __
"""
__title__ = 'Django REST framework'
__version__ = '3.1.3'
__version__ = '3.3.2'
__author__ = 'Tom Christie'
__license__ = 'BSD 2-Clause'
__copyright__ = 'Copyright 2011-2015 Tom Christie'

View File

@ -2,13 +2,15 @@
Provides various authentication policies.
"""
from __future__ import unicode_literals
import base64
from django.contrib.auth import authenticate
from django.contrib.auth import authenticate, get_user_model
from django.middleware.csrf import CsrfViewMiddleware
from django.utils.translation import ugettext_lazy as _
from rest_framework import exceptions, HTTP_HEADER_ENCODING
from rest_framework import HTTP_HEADER_ENCODING, exceptions
from rest_framework.authtoken.models import Token
from rest_framework.compat import get_user_model
def get_authorization_header(request):
@ -86,9 +88,8 @@ class BasicAuthentication(BaseAuthentication):
"""
Authenticate the userid and password against username and password.
"""
username_field = getattr(get_user_model(), 'USERNAME_FIELD', 'username')
credentials = {
username_field: userid,
get_user_model().USERNAME_FIELD: userid,
'password': password
}
user = authenticate(**credentials)
@ -116,9 +117,8 @@ class SessionAuthentication(BaseAuthentication):
Otherwise returns `None`.
"""
# Get the underlying HttpRequest object
request = request._request
user = getattr(request, 'user', None)
# Get the session-based user from the underlying HttpRequest object
user = getattr(request._request, 'user', None)
# Unauthenticated, CSRF validation not required
if not user or not user.is_active:
@ -170,7 +170,13 @@ class TokenAuthentication(BaseAuthentication):
msg = _('Invalid token header. Token string should not contain spaces.')
raise exceptions.AuthenticationFailed(msg)
return self.authenticate_credentials(auth[1])
try:
token = auth[1].decode()
except UnicodeError:
msg = _('Invalid token header. Token string should not contain invalid characters.')
raise exceptions.AuthenticationFailed(msg)
return self.authenticate_credentials(token)
def authenticate_credentials(self, key):
try:

View File

@ -1,4 +1,5 @@
from django.contrib import admin
from rest_framework.authtoken.models import Token

View File

@ -1,8 +1,8 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):

View File

@ -5,7 +5,6 @@ from django.conf import settings
from django.db import models
from django.utils.encoding import python_2_unicode_compatible
# Prior to Django 1.5, the AUTH_USER_MODEL setting does not exist.
# Note that we don't perform this code in the compat module due to
# bug report #1297

View File

@ -1,7 +1,7 @@
from django.contrib.auth import authenticate
from django.utils.translation import ugettext_lazy as _
from rest_framework import exceptions, serializers
from rest_framework import serializers
class AuthTokenSerializer(serializers.Serializer):
@ -18,13 +18,13 @@ class AuthTokenSerializer(serializers.Serializer):
if user:
if not user.is_active:
msg = _('User account is disabled.')
raise exceptions.ValidationError(msg)
raise serializers.ValidationError(msg)
else:
msg = _('Unable to log in with provided credentials.')
raise exceptions.ValidationError(msg)
raise serializers.ValidationError(msg)
else:
msg = _('Must include "username" and "password".')
raise exceptions.ValidationError(msg)
raise serializers.ValidationError(msg)
attrs['user'] = user
return attrs

View File

@ -1,60 +0,0 @@
# -*- coding: utf-8 -*-
from south.db import db
from south.v2 import SchemaMigration
try:
from django.contrib.auth import get_user_model
except ImportError: # django < 1.5
from django.contrib.auth.models import User
else:
User = get_user_model()
class Migration(SchemaMigration):
def forwards(self, orm):
# Adding model 'Token'
db.create_table('authtoken_token', (
('key', self.gf('django.db.models.fields.CharField')(max_length=40, primary_key=True)),
('user', self.gf('django.db.models.fields.related.OneToOneField')(related_name='auth_token', unique=True, to=orm['%s.%s' % (User._meta.app_label, User._meta.object_name)])),
('created', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)),
))
db.send_create_signal('authtoken', ['Token'])
def backwards(self, orm):
# Deleting model 'Token'
db.delete_table('authtoken_token')
models = {
'auth.group': {
'Meta': {'object_name': 'Group'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
},
'auth.permission': {
'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
"%s.%s" % (User._meta.app_label, User._meta.module_name): {
'Meta': {'object_name': User._meta.module_name, 'db_table': repr(User._meta.db_table)},
},
'authtoken.token': {
'Meta': {'object_name': 'Token'},
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'key': ('django.db.models.fields.CharField', [], {'max_length': '40', 'primary_key': 'True'}),
'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'auth_token'", 'unique': 'True', 'to': "orm['%s.%s']" % (User._meta.app_label, User._meta.object_name)})
},
'contenttypes.contenttype': {
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
}
}
complete_apps = ['authtoken']

View File

@ -1,9 +1,8 @@
from rest_framework.views import APIView
from rest_framework import parsers
from rest_framework import renderers
from rest_framework.response import Response
from rest_framework import parsers, renderers
from rest_framework.authtoken.models import Token
from rest_framework.authtoken.serializers import AuthTokenSerializer
from rest_framework.response import Response
from rest_framework.views import APIView
class ObtainAuthToken(APIView):
@ -13,7 +12,7 @@ class ObtainAuthToken(APIView):
renderer_classes = (renderers.JSONRenderer,)
serializer_class = AuthTokenSerializer
def post(self, request):
def post(self, request, *args, **kwargs):
serializer = self.serializer_class(data=request.data)
serializer.is_valid(raise_exception=True)
user = serializer.validated_data['user']

View File

@ -1,22 +1,23 @@
"""
The `compat` module provides support for backwards compatibility with older
versions of django/python, and compatibility wrappers around optional packages.
versions of Django/Python, and compatibility wrappers around optional packages.
"""
# flake8: noqa
from __future__ import unicode_literals
from django.core.exceptions import ImproperlyConfigured
import django
from django.conf import settings
from django.db import connection, transaction
from django.utils.encoding import force_text
from django.utils.six.moves.urllib.parse import urlparse as _urlparse
from django.template import Context, RequestContext, Template
from django.utils import six
import django
import inspect
from django.views.generic import View
try:
import importlib
import importlib # Available in Python 3.1+
except ImportError:
from django.utils import importlib
from django.utils import importlib # Will be removed in Django 1.9
def unicode_repr(instance):
# Get the repr of an instance, but ensure it is a unicode string
@ -50,21 +51,11 @@ def total_seconds(timedelta):
return (timedelta.days * 86400.0) + float(timedelta.seconds) + (timedelta.microseconds / 1000000.0)
# OrderedDict only available in Python 2.7.
# This will always be the case in Django 1.7 and above, as these versions
# no longer support Python 2.6.
# For Django <= 1.6 and Python 2.6 fall back to SortedDict.
try:
from collections import OrderedDict
except ImportError:
from django.utils.datastructures import SortedDict as OrderedDict
# HttpResponseBase only exists from 1.5 onwards
try:
from django.http.response import HttpResponseBase
except ImportError:
from django.http import HttpResponse as HttpResponseBase
def distinct(queryset, base):
if settings.DATABASES[queryset.db]["ENGINE"] == "django.db.backends.oracle":
# distinct analogue for Oracle users
return base.filter(pk__in=set(queryset.values_list('pk', flat=True)))
return queryset.distinct()
# contrib.postgres only supported from 1.8 onwards.
@ -74,14 +65,11 @@ except ImportError:
postgres_fields = None
# request only provides `resolver_match` from 1.5 onwards.
def get_resolver_match(request):
try:
return request.resolver_match
except AttributeError:
# Django < 1.5
from django.core.urlresolvers import resolve
return resolve(request.path_info)
# JSONField is only supported from 1.9 onwards
try:
from django.contrib.postgres.fields import JSONField
except ImportError:
JSONField = None
# django-filter is optional
@ -90,6 +78,14 @@ try:
except ImportError:
django_filters = None
# django-crispy-forms is optional
try:
import crispy_forms
except ImportError:
crispy_forms = None
if django.VERSION >= (1, 6):
def clean_manytomany_helptext(text):
return text
@ -101,42 +97,16 @@ else:
text = text[:-69]
return text
# Django-guardian is optional. Import only if guardian is in INSTALLED_APPS
# Fixes (#1712). We keep the try/except for the test suite.
guardian = None
if 'guardian' in settings.INSTALLED_APPS:
try:
try:
if 'guardian' in settings.INSTALLED_APPS:
import guardian
import guardian.shortcuts # Fixes #1624
except ImportError:
pass
def get_model_name(model_cls):
try:
return model_cls._meta.model_name
except AttributeError:
# < 1.6 used module_name instead of model_name
return model_cls._meta.module_name
# Support custom user models in Django 1.5+
try:
from django.contrib.auth import get_user_model
except ImportError:
from django.contrib.auth.models import User
get_user_model = lambda: User
# View._allowed_methods only present from 1.5 onwards
if django.VERSION >= (1, 5):
from django.views.generic import View
else:
from django.views.generic import View as DjangoView
class View(DjangoView):
def _allowed_methods(self):
return [m.upper() for m in self.http_method_names if hasattr(self, m)]
pass
# MinValueValidator, MaxValueValidator et al. only accept `message` in 1.8+
@ -149,92 +119,41 @@ else:
from django.core.validators import MinLengthValidator as DjangoMinLengthValidator
from django.core.validators import MaxLengthValidator as DjangoMaxLengthValidator
class MinValueValidator(DjangoMinValueValidator):
def __init__(self, *args, **kwargs):
self.message = kwargs.pop('message', self.message)
super(MinValueValidator, self).__init__(*args, **kwargs)
class MaxValueValidator(DjangoMaxValueValidator):
def __init__(self, *args, **kwargs):
self.message = kwargs.pop('message', self.message)
super(MaxValueValidator, self).__init__(*args, **kwargs)
class MinLengthValidator(DjangoMinLengthValidator):
def __init__(self, *args, **kwargs):
self.message = kwargs.pop('message', self.message)
super(MinLengthValidator, self).__init__(*args, **kwargs)
class MaxLengthValidator(DjangoMaxLengthValidator):
def __init__(self, *args, **kwargs):
self.message = kwargs.pop('message', self.message)
super(MaxLengthValidator, self).__init__(*args, **kwargs)
# URLValidator only accepts `message` in 1.6+
if django.VERSION >= (1, 6):
from django.core.validators import URLValidator
else:
from django.core.validators import URLValidator as DjangoURLValidator
class URLValidator(DjangoURLValidator):
def __init__(self, *args, **kwargs):
self.message = kwargs.pop('message', self.message)
super(URLValidator, self).__init__(*args, **kwargs)
# EmailValidator requires explicit regex prior to 1.6+
if django.VERSION >= (1, 6):
from django.core.validators import EmailValidator
else:
from django.core.validators import EmailValidator as DjangoEmailValidator
from django.core.validators import email_re
class EmailValidator(DjangoEmailValidator):
def __init__(self, *args, **kwargs):
super(EmailValidator, self).__init__(email_re, *args, **kwargs)
# PATCH method is not implemented by Django
if 'patch' not in View.http_method_names:
View.http_method_names = View.http_method_names + ['patch']
# RequestFactory only provides `generic` from 1.5 onwards
from django.test.client import RequestFactory as DjangoRequestFactory
from django.test.client import FakePayload
try:
# In 1.5 the test client uses force_bytes
from django.utils.encoding import force_bytes as force_bytes_or_smart_bytes
except ImportError:
# In 1.4 the test client just uses smart_str
from django.utils.encoding import smart_str as force_bytes_or_smart_bytes
class RequestFactory(DjangoRequestFactory):
def generic(self, method, path,
data='', content_type='application/octet-stream', **extra):
parsed = _urlparse(path)
data = force_bytes_or_smart_bytes(data, settings.DEFAULT_CHARSET)
r = {
'PATH_INFO': self._get_path(parsed),
'QUERY_STRING': force_text(parsed[4]),
'REQUEST_METHOD': six.text_type(method),
}
if data:
r.update({
'CONTENT_LENGTH': len(data),
'CONTENT_TYPE': six.text_type(content_type),
'wsgi.input': FakePayload(data),
})
r.update(extra)
return self.request(**r)
# Markdown is optional
try:
import markdown
def apply_markdown(text):
"""
Simple wrapper around :func:`markdown.markdown` to set the base level
@ -260,7 +179,6 @@ else:
LONG_SEPARATORS = (b', ', b': ')
INDENT_SEPARATORS = (b',', b': ')
if django.VERSION >= (1, 8):
from django.db.models import DurationField
from django.utils.dateparse import parse_duration
@ -268,13 +186,20 @@ if django.VERSION >= (1, 8):
else:
DurationField = duration_string = parse_duration = None
try:
# DecimalValidator is unavailable in Django < 1.9
from django.core.validators import DecimalValidator
except ImportError:
DecimalValidator = None
def set_rollback():
if hasattr(transaction, 'set_rollback'):
if connection.settings_dict.get('ATOMIC_REQUESTS', False):
# If running in >=1.6 then mark a rollback as required,
# and allow it to be handled by Django.
transaction.set_rollback(True)
if connection.in_atomic_block:
transaction.set_rollback(True)
elif transaction.is_managed():
# Otherwise handle it explicitly if in managed mode.
if transaction.is_dirty():
@ -283,3 +208,54 @@ def set_rollback():
else:
# transaction not managed
pass
def template_render(template, context=None, request=None):
"""
Passing Context or RequestContext to Template.render is deprecated in 1.9+,
see https://github.com/django/django/pull/3883 and
https://github.com/django/django/blob/1.9rc1/django/template/backends/django.py#L82-L84
:param template: Template instance
:param context: dict
:param request: Request instance
:return: rendered template as SafeText instance
"""
if django.VERSION < (1, 8) or isinstance(template, Template):
if request:
context = RequestContext(request, context)
else:
context = Context(context)
return template.render(context)
# backends template, e.g. django.template.backends.django.Template
else:
return template.render(context, request=request)
def get_all_related_objects(opts):
"""
Django 1.8 changed meta api, see
https://docs.djangoproject.com/en/1.8/ref/models/meta/#migrating-old-meta-api
https://code.djangoproject.com/ticket/12663
https://github.com/django/django/pull/3848
:param opts: Options instance
:return: list of relations except many-to-many ones
"""
if django.VERSION < (1, 9):
return opts.get_all_related_objects()
else:
return [r for r in opts.related_objects if not r.field.many_to_many]
def get_all_related_many_to_many_objects(opts):
"""
Django 1.8 changed meta api, see docstr in compat.get_all_related_objects()
:param opts: Options instance
:return: list of many-to-many relations
"""
if django.VERSION < (1, 9):
return opts.get_all_related_many_to_many_objects()
else:
return [r for r in opts.related_objects if r.field.many_to_many]

View File

@ -7,10 +7,13 @@ based views, as well as the `@detail_route` and `@list_route` decorators, which
used to annotate methods on viewsets that should be included by routers.
"""
from __future__ import unicode_literals
from django.utils import six
from rest_framework.views import APIView
import types
from django.utils import six
from rest_framework.views import APIView
def api_view(http_method_names=None):

View File

@ -5,11 +5,16 @@ In addition Django's built in 403 and 404 exceptions are handled.
(`django.http.Http404` and `django.core.exceptions.PermissionDenied`)
"""
from __future__ import unicode_literals
import math
from django.utils import six
from django.utils.encoding import force_text
from django.utils.translation import ugettext_lazy as _, ungettext
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import ungettext
from rest_framework import status
import math
from rest_framework.utils.serializer_helpers import ReturnDict, ReturnList
def _force_text_recursive(data):
@ -18,14 +23,20 @@ def _force_text_recursive(data):
lazy translation strings into plain text.
"""
if isinstance(data, list):
return [
ret = [
_force_text_recursive(item) for item in data
]
if isinstance(data, ReturnList):
return ReturnList(ret, serializer=data.serializer)
return data
elif isinstance(data, dict):
return dict([
(key, _force_text_recursive(value))
ret = {
key: _force_text_recursive(value)
for key, value in data.items()
])
}
if isinstance(data, ReturnDict):
return ReturnDict(ret, serializer=data.serializer)
return data
return force_text(data)

View File

@ -1,30 +1,39 @@
from __future__ import unicode_literals
from django.conf import settings
from django.core.exceptions import ObjectDoesNotExist
from django.core.exceptions import ValidationError as DjangoValidationError
from django.core.validators import RegexValidator, ip_address_validators
from django.forms import ImageField as DjangoImageField
from django.utils import six, timezone
from django.utils.dateparse import parse_date, parse_datetime, parse_time
from django.utils.encoding import is_protected_type, smart_text
from django.utils.translation import ugettext_lazy as _
from django.utils.ipv6 import clean_ipv6_address
from rest_framework import ISO_8601
from rest_framework.compat import (
EmailValidator, MinValueValidator, MaxValueValidator,
MinLengthValidator, MaxLengthValidator, URLValidator, OrderedDict,
unicode_repr, unicode_to_repr, parse_duration, duration_string,
)
from rest_framework.exceptions import ValidationError
from rest_framework.settings import api_settings
from rest_framework.utils import html, representation, humanize_datetime
import collections
import copy
import datetime
import decimal
import inspect
import json
import re
import uuid
from collections import OrderedDict
from django.conf import settings
from django.core.exceptions import ValidationError as DjangoValidationError
from django.core.exceptions import ObjectDoesNotExist
from django.core.validators import (
EmailValidator, RegexValidator, URLValidator, ip_address_validators
)
from django.forms import FilePathField as DjangoFilePathField
from django.forms import ImageField as DjangoImageField
from django.utils import six, timezone
from django.utils.dateparse import parse_date, parse_datetime, parse_time
from django.utils.encoding import is_protected_type, smart_text
from django.utils.functional import cached_property
from django.utils.ipv6 import clean_ipv6_address
from django.utils.translation import ugettext_lazy as _
from rest_framework import ISO_8601
from rest_framework.compat import (
MaxLengthValidator, MaxValueValidator, MinLengthValidator,
MinValueValidator, duration_string, parse_duration, unicode_repr,
unicode_to_repr
)
from rest_framework.exceptions import ValidationError
from rest_framework.settings import api_settings
from rest_framework.utils import html, humanize_datetime, representation
class empty:
@ -104,6 +113,100 @@ def set_value(dictionary, keys, value):
dictionary[keys[-1]] = value
def to_choices_dict(choices):
"""
Convert choices into key/value dicts.
pairwise_choices([1]) -> {1: 1}
pairwise_choices([(1, '1st'), (2, '2nd')]) -> {1: '1st', 2: '2nd'}
pairwise_choices([('Group', ((1, '1st'), 2))]) -> {'Group': {1: '1st', 2: '2nd'}}
"""
# Allow single, paired or grouped choices style:
# choices = [1, 2, 3]
# choices = [(1, 'First'), (2, 'Second'), (3, 'Third')]
# choices = [('Category', ((1, 'First'), (2, 'Second'))), (3, 'Third')]
ret = OrderedDict()
for choice in choices:
if (not isinstance(choice, (list, tuple))):
# single choice
ret[choice] = choice
else:
key, value = choice
if isinstance(value, (list, tuple)):
# grouped choices (category, sub choices)
ret[key] = to_choices_dict(value)
else:
# paired choice (key, display value)
ret[key] = value
return ret
def flatten_choices_dict(choices):
"""
Convert a group choices dict into a flat dict of choices.
flatten_choices({1: '1st', 2: '2nd'}) -> {1: '1st', 2: '2nd'}
flatten_choices({'Group': {1: '1st', 2: '2nd'}}) -> {1: '1st', 2: '2nd'}
"""
ret = OrderedDict()
for key, value in choices.items():
if isinstance(value, dict):
# grouped choices (category, sub choices)
for sub_key, sub_value in value.items():
ret[sub_key] = sub_value
else:
# choice (key, display value)
ret[key] = value
return ret
def iter_options(grouped_choices, cutoff=None, cutoff_text=None):
"""
Helper function for options and option groups in templates.
"""
class StartOptionGroup(object):
start_option_group = True
end_option_group = False
def __init__(self, label):
self.label = label
class EndOptionGroup(object):
start_option_group = False
end_option_group = True
class Option(object):
start_option_group = False
end_option_group = False
def __init__(self, value, display_text, disabled=False):
self.value = value
self.display_text = display_text
self.disabled = disabled
count = 0
for key, value in grouped_choices.items():
if cutoff and count >= cutoff:
break
if isinstance(value, dict):
yield StartOptionGroup(label=key)
for sub_key, sub_value in value.items():
if cutoff and count >= cutoff:
break
yield Option(value=sub_key, display_text=sub_value)
count += 1
yield EndOptionGroup()
else:
yield Option(value=key, display_text=value)
count += 1
if cutoff and count >= cutoff and cutoff_text:
cutoff_text = cutoff_text.format(count=cutoff)
yield Option(value='n/a', display_text=cutoff_text, disabled=True)
class CreateOnlyDefault(object):
"""
This class may be used to provide default values that are only used
@ -196,9 +299,7 @@ class Field(object):
self.allow_null = allow_null
if self.default_empty_html is not empty:
if not required:
self.default_empty_html = empty
elif default is not empty:
if default is not empty:
self.default_empty_html = default
if validators is not None:
@ -288,6 +389,10 @@ class Field(object):
# If the field is blank, and null is a valid value then
# determine if we should use null instead.
return '' if getattr(self, 'allow_blank', False) else None
elif ret == '' and not self.required:
# If the field is blank, and emptyness is valid then
# determine if we should use emptyness instead.
return '' if getattr(self, 'allow_blank', False) else empty
return ret
return dictionary.get(self.field_name, empty)
@ -417,10 +522,11 @@ class Field(object):
Transform the *outgoing* native value into primitive data.
"""
raise NotImplementedError(
'{cls}.to_representation() must be implemented.\n'
'If you are upgrading from REST framework version 2 '
'you might want `ReadOnlyField`.'.format(
cls=self.__class__.__name__
'{cls}.to_representation() must be implemented for field '
'{field_name}. If you do not need to support write operations '
'you probably want to subclass `ReadOnlyField` instead.'.format(
cls=self.__class__.__name__,
field_name=self.field_name,
)
)
@ -437,7 +543,7 @@ class Field(object):
message_string = msg.format(**kwargs)
raise ValidationError(message_string)
@property
@cached_property
def root(self):
"""
Returns the top-level serializer for this field.
@ -447,7 +553,7 @@ class Field(object):
root = root.parent
return root
@property
@cached_property
def context(self):
"""
Returns the context as passed to the root serializer on initialization.
@ -498,18 +604,21 @@ class BooleanField(Field):
}
default_empty_html = False
initial = False
TRUE_VALUES = set(('t', 'T', 'true', 'True', 'TRUE', '1', 1, True))
FALSE_VALUES = set(('f', 'F', 'false', 'False', 'FALSE', '0', 0, 0.0, False))
TRUE_VALUES = {'t', 'T', 'true', 'True', 'TRUE', '1', 1, True}
FALSE_VALUES = {'f', 'F', 'false', 'False', 'FALSE', '0', 0, 0.0, False}
def __init__(self, **kwargs):
assert 'allow_null' not in kwargs, '`allow_null` is not a valid option. Use `NullBooleanField` instead.'
super(BooleanField, self).__init__(**kwargs)
def to_internal_value(self, data):
if data in self.TRUE_VALUES:
return True
elif data in self.FALSE_VALUES:
return False
try:
if data in self.TRUE_VALUES:
return True
elif data in self.FALSE_VALUES:
return False
except TypeError: # Input is an unhashable type
pass
self.fail('invalid', input=data)
def to_representation(self, value):
@ -525,9 +634,9 @@ class NullBooleanField(Field):
'invalid': _('"{input}" is not a valid boolean.')
}
initial = None
TRUE_VALUES = set(('t', 'T', 'true', 'True', 'TRUE', '1', 1, True))
FALSE_VALUES = set(('f', 'F', 'false', 'False', 'FALSE', '0', 0, 0.0, False))
NULL_VALUES = set(('n', 'N', 'null', 'Null', 'NULL', '', None))
TRUE_VALUES = {'t', 'T', 'true', 'True', 'TRUE', '1', 1, True}
FALSE_VALUES = {'f', 'F', 'false', 'False', 'FALSE', '0', 0, 0.0, False}
NULL_VALUES = {'n', 'N', 'null', 'Null', 'NULL', '', None}
def __init__(self, **kwargs):
assert 'allow_null' not in kwargs, '`allow_null` is not a valid option.'
@ -580,7 +689,7 @@ class CharField(Field):
# Test for the empty string here so that it does not get validated,
# and so that subclasses do not need to handle it explicitly
# inside the `to_internal_value()` method.
if data == '':
if data == '' or (self.trim_whitespace and six.text_type(data).strip() == ''):
if not self.allow_blank:
self.fail('blank')
return ''
@ -660,9 +769,11 @@ class UUIDField(Field):
try:
if isinstance(data, six.integer_types):
return uuid.UUID(int=data)
else:
elif isinstance(data, six.string_types):
return uuid.UUID(hex=data)
except (ValueError, TypeError):
else:
self.fail('invalid', value=data)
except (ValueError):
self.fail('invalid', value=data)
return data
@ -780,16 +891,20 @@ class DecimalField(Field):
}
MAX_STRING_LENGTH = 1000 # Guard against malicious string inputs.
coerce_to_string = api_settings.COERCE_DECIMAL_TO_STRING
def __init__(self, max_digits, decimal_places, coerce_to_string=None, max_value=None, min_value=None, **kwargs):
self.max_digits = max_digits
self.decimal_places = decimal_places
self.coerce_to_string = coerce_to_string if (coerce_to_string is not None) else self.coerce_to_string
if coerce_to_string is not None:
self.coerce_to_string = coerce_to_string
self.max_value = max_value
self.min_value = min_value
if self.max_digits is not None and self.decimal_places is not None:
self.max_whole_digits = self.max_digits - self.decimal_places
else:
self.max_whole_digits = None
super(DecimalField, self).__init__(**kwargs)
if self.max_value is not None:
@ -833,34 +948,41 @@ class DecimalField(Field):
values or to enhance it in any way you need to.
"""
sign, digittuple, exponent = value.as_tuple()
decimals = exponent * decimal.Decimal(-1) if exponent < 0 else 0
# digittuple doesn't include any leading zeros.
digits = len(digittuple)
if decimals > digits:
# We have leading zeros up to or past the decimal point. Count
# everything past the decimal point as a digit. We do not count
# 0 before the decimal point as a digit since that would mean
# we would not allow max_digits = decimal_places.
digits = decimals
whole_digits = digits - decimals
if exponent >= 0:
# 1234500.0
total_digits = len(digittuple) + exponent
whole_digits = total_digits
decimal_places = 0
elif len(digittuple) > abs(exponent):
# 123.45
total_digits = len(digittuple)
whole_digits = total_digits - abs(exponent)
decimal_places = abs(exponent)
else:
# 0.001234
total_digits = abs(exponent)
whole_digits = 0
decimal_places = total_digits
if self.max_digits is not None and digits > self.max_digits:
if self.max_digits is not None and total_digits > self.max_digits:
self.fail('max_digits', max_digits=self.max_digits)
if self.decimal_places is not None and decimals > self.decimal_places:
if self.decimal_places is not None and decimal_places > self.decimal_places:
self.fail('max_decimal_places', max_decimal_places=self.decimal_places)
if self.max_digits is not None and self.decimal_places is not None and whole_digits > (self.max_digits - self.decimal_places):
self.fail('max_whole_digits', max_whole_digits=self.max_digits - self.decimal_places)
if self.max_whole_digits is not None and whole_digits > self.max_whole_digits:
self.fail('max_whole_digits', max_whole_digits=self.max_whole_digits)
return value
def to_representation(self, value):
coerce_to_string = getattr(self, 'coerce_to_string', api_settings.COERCE_DECIMAL_TO_STRING)
if not isinstance(value, decimal.Decimal):
value = decimal.Decimal(six.text_type(value).strip())
quantized = self.quantize(value)
if not self.coerce_to_string:
if not coerce_to_string:
return quantized
return '{0:f}'.format(quantized)
@ -882,14 +1004,15 @@ class DateTimeField(Field):
'invalid': _('Datetime has wrong format. Use one of these formats instead: {format}.'),
'date': _('Expected a datetime but got a date.'),
}
format = api_settings.DATETIME_FORMAT
input_formats = api_settings.DATETIME_INPUT_FORMATS
default_timezone = timezone.get_default_timezone() if settings.USE_TZ else None
datetime_parser = datetime.datetime.strptime
def __init__(self, format=empty, input_formats=None, default_timezone=None, *args, **kwargs):
self.format = format if format is not empty else self.format
self.input_formats = input_formats if input_formats is not None else self.input_formats
self.default_timezone = default_timezone if default_timezone is not None else self.default_timezone
if format is not empty:
self.format = format
if input_formats is not None:
self.input_formats = input_formats
if default_timezone is not None:
self.timezone = default_timezone
super(DateTimeField, self).__init__(*args, **kwargs)
def enforce_timezone(self, value):
@ -897,21 +1020,28 @@ class DateTimeField(Field):
When `self.default_timezone` is `None`, always return naive datetimes.
When `self.default_timezone` is not `None`, always return aware datetimes.
"""
if (self.default_timezone is not None) and not timezone.is_aware(value):
return timezone.make_aware(value, self.default_timezone)
elif (self.default_timezone is None) and timezone.is_aware(value):
field_timezone = getattr(self, 'timezone', self.default_timezone())
if (field_timezone is not None) and not timezone.is_aware(value):
return timezone.make_aware(value, field_timezone)
elif (field_timezone is None) and timezone.is_aware(value):
return timezone.make_naive(value, timezone.UTC())
return value
def default_timezone(self):
return timezone.get_default_timezone() if settings.USE_TZ else None
def to_internal_value(self, value):
input_formats = getattr(self, 'input_formats', api_settings.DATETIME_INPUT_FORMATS)
if isinstance(value, datetime.date) and not isinstance(value, datetime.datetime):
self.fail('date')
if isinstance(value, datetime.datetime):
return self.enforce_timezone(value)
for format in self.input_formats:
if format.lower() == ISO_8601:
for input_format in input_formats:
if input_format.lower() == ISO_8601:
try:
parsed = parse_datetime(value)
except (ValueError, TypeError):
@ -921,25 +1051,27 @@ class DateTimeField(Field):
return self.enforce_timezone(parsed)
else:
try:
parsed = datetime.datetime.strptime(value, format)
parsed = self.datetime_parser(value, input_format)
except (ValueError, TypeError):
pass
else:
return self.enforce_timezone(parsed)
humanized_format = humanize_datetime.datetime_formats(self.input_formats)
humanized_format = humanize_datetime.datetime_formats(input_formats)
self.fail('invalid', format=humanized_format)
def to_representation(self, value):
if self.format is None:
output_format = getattr(self, 'format', api_settings.DATETIME_FORMAT)
if output_format is None:
return value
if self.format.lower() == ISO_8601:
if output_format.lower() == ISO_8601:
value = value.isoformat()
if value.endswith('+00:00'):
value = value[:-6] + 'Z'
return value
return value.strftime(self.format)
return value.strftime(output_format)
class DateField(Field):
@ -947,23 +1079,26 @@ class DateField(Field):
'invalid': _('Date has wrong format. Use one of these formats instead: {format}.'),
'datetime': _('Expected a date but got a datetime.'),
}
format = api_settings.DATE_FORMAT
input_formats = api_settings.DATE_INPUT_FORMATS
datetime_parser = datetime.datetime.strptime
def __init__(self, format=empty, input_formats=None, *args, **kwargs):
self.format = format if format is not empty else self.format
self.input_formats = input_formats if input_formats is not None else self.input_formats
if format is not empty:
self.format = format
if input_formats is not None:
self.input_formats = input_formats
super(DateField, self).__init__(*args, **kwargs)
def to_internal_value(self, value):
input_formats = getattr(self, 'input_formats', api_settings.DATE_INPUT_FORMATS)
if isinstance(value, datetime.datetime):
self.fail('datetime')
if isinstance(value, datetime.date):
return value
for format in self.input_formats:
if format.lower() == ISO_8601:
for input_format in input_formats:
if input_format.lower() == ISO_8601:
try:
parsed = parse_date(value)
except (ValueError, TypeError):
@ -973,20 +1108,22 @@ class DateField(Field):
return parsed
else:
try:
parsed = datetime.datetime.strptime(value, format)
parsed = self.datetime_parser(value, input_format)
except (ValueError, TypeError):
pass
else:
return parsed.date()
humanized_format = humanize_datetime.date_formats(self.input_formats)
humanized_format = humanize_datetime.date_formats(input_formats)
self.fail('invalid', format=humanized_format)
def to_representation(self, value):
output_format = getattr(self, 'format', api_settings.DATE_FORMAT)
if not value:
return None
if self.format is None:
if output_format is None:
return value
# Applying a `DateField` to a datetime value is almost always
@ -998,32 +1135,35 @@ class DateField(Field):
'read-only field and deal with timezone issues explicitly.'
)
if self.format.lower() == ISO_8601:
if output_format.lower() == ISO_8601:
if (isinstance(value, str)):
value = datetime.datetime.strptime(value, '%Y-%m-%d').date()
return value.isoformat()
return value.strftime(self.format)
return value.strftime(output_format)
class TimeField(Field):
default_error_messages = {
'invalid': _('Time has wrong format. Use one of these formats instead: {format}.'),
}
format = api_settings.TIME_FORMAT
input_formats = api_settings.TIME_INPUT_FORMATS
datetime_parser = datetime.datetime.strptime
def __init__(self, format=empty, input_formats=None, *args, **kwargs):
self.format = format if format is not empty else self.format
self.input_formats = input_formats if input_formats is not None else self.input_formats
if format is not empty:
self.format = format
if input_formats is not None:
self.input_formats = input_formats
super(TimeField, self).__init__(*args, **kwargs)
def to_internal_value(self, value):
input_formats = getattr(self, 'input_formats', api_settings.TIME_INPUT_FORMATS)
if isinstance(value, datetime.time):
return value
for format in self.input_formats:
if format.lower() == ISO_8601:
for input_format in input_formats:
if input_format.lower() == ISO_8601:
try:
parsed = parse_time(value)
except (ValueError, TypeError):
@ -1033,17 +1173,19 @@ class TimeField(Field):
return parsed
else:
try:
parsed = datetime.datetime.strptime(value, format)
parsed = self.datetime_parser(value, input_format)
except (ValueError, TypeError):
pass
else:
return parsed.time()
humanized_format = humanize_datetime.time_formats(self.input_formats)
humanized_format = humanize_datetime.time_formats(input_formats)
self.fail('invalid', format=humanized_format)
def to_representation(self, value):
if self.format is None:
output_format = getattr(self, 'format', api_settings.TIME_FORMAT)
if output_format is None:
return value
# Applying a `TimeField` to a datetime value is almost always
@ -1055,9 +1197,9 @@ class TimeField(Field):
'read-only field and deal with timezone issues explicitly.'
)
if self.format.lower() == ISO_8601:
if output_format.lower() == ISO_8601:
return value.isoformat()
return value.strftime(self.format)
return value.strftime(output_format)
class DurationField(Field):
@ -1074,7 +1216,7 @@ class DurationField(Field):
def to_internal_value(self, value):
if isinstance(value, datetime.timedelta):
return value
parsed = parse_duration(value)
parsed = parse_duration(six.text_type(value))
if parsed is not None:
return parsed
self.fail('invalid', format='[DD] [HH:[MM:]]ss[.uuuuuu]')
@ -1089,26 +1231,21 @@ class ChoiceField(Field):
default_error_messages = {
'invalid_choice': _('"{input}" is not a valid choice.')
}
html_cutoff = None
html_cutoff_text = _('More than {count} items...')
def __init__(self, choices, **kwargs):
# Allow either single or paired choices style:
# choices = [1, 2, 3]
# choices = [(1, 'First'), (2, 'Second'), (3, 'Third')]
pairs = [
isinstance(item, (list, tuple)) and len(item) == 2
for item in choices
]
if all(pairs):
self.choices = OrderedDict([(key, display_value) for key, display_value in choices])
else:
self.choices = OrderedDict([(item, item) for item in choices])
self.grouped_choices = to_choices_dict(choices)
self.choices = flatten_choices_dict(self.grouped_choices)
self.html_cutoff = kwargs.pop('html_cutoff', self.html_cutoff)
self.html_cutoff_text = kwargs.pop('html_cutoff_text', self.html_cutoff_text)
# Map the string representation of choices to the underlying value.
# Allows us to deal with eg. integer choices while supporting either
# integer or string input, but still get the correct datatype out.
self.choice_strings_to_values = dict([
(six.text_type(key), key) for key in self.choices.keys()
])
self.choice_strings_to_values = {
six.text_type(key): key for key in self.choices.keys()
}
self.allow_blank = kwargs.pop('allow_blank', False)
@ -1128,38 +1265,71 @@ class ChoiceField(Field):
return value
return self.choice_strings_to_values.get(six.text_type(value), value)
def iter_options(self):
"""
Helper method for use with templates rendering select widgets.
"""
return iter_options(
self.grouped_choices,
cutoff=self.html_cutoff,
cutoff_text=self.html_cutoff_text
)
class MultipleChoiceField(ChoiceField):
default_error_messages = {
'invalid_choice': _('"{input}" is not a valid choice.'),
'not_a_list': _('Expected a list of items but got type "{input_type}".')
'not_a_list': _('Expected a list of items but got type "{input_type}".'),
'empty': _('This selection may not be empty.')
}
default_empty_html = []
def __init__(self, *args, **kwargs):
self.allow_empty = kwargs.pop('allow_empty', True)
super(MultipleChoiceField, self).__init__(*args, **kwargs)
def get_value(self, dictionary):
if self.field_name not in dictionary:
if getattr(self.root, 'partial', False):
return empty
# We override the default field access in order to support
# lists in HTML forms.
if html.is_html_input(dictionary):
ret = dictionary.getlist(self.field_name)
if getattr(self.root, 'partial', False) and not ret:
ret = empty
return ret
return dictionary.getlist(self.field_name)
return dictionary.get(self.field_name, empty)
def to_internal_value(self, data):
if isinstance(data, type('')) or not hasattr(data, '__iter__'):
self.fail('not_a_list', input_type=type(data).__name__)
if not self.allow_empty and len(data) == 0:
self.fail('empty')
return set([
return {
super(MultipleChoiceField, self).to_internal_value(item)
for item in data
])
}
def to_representation(self, value):
return set([
return {
self.choice_strings_to_values.get(six.text_type(item), item) for item in value
])
}
class FilePathField(ChoiceField):
default_error_messages = {
'invalid_choice': _('"{input}" is not a valid path choice.')
}
def __init__(self, path, match=None, recursive=False, allow_files=True,
allow_folders=False, required=None, **kwargs):
# Defer to Django's FilePathField implmentation to get the
# valid set of choices.
field = DjangoFilePathField(
path, match=match, recursive=recursive, allow_files=allow_files,
allow_folders=allow_folders, required=required
)
kwargs['choices'] = field.choices
super(FilePathField, self).__init__(**kwargs)
# File types...
@ -1172,12 +1342,12 @@ class FileField(Field):
'empty': _('The submitted file is empty.'),
'max_length': _('Ensure this filename has at most {max_length} characters (it has {length}).'),
}
use_url = api_settings.UPLOADED_FILES_USE_URL
def __init__(self, *args, **kwargs):
self.max_length = kwargs.pop('max_length', None)
self.allow_empty_file = kwargs.pop('allow_empty_file', False)
self.use_url = kwargs.pop('use_url', self.use_url)
if 'use_url' in kwargs:
self.use_url = kwargs.pop('use_url')
super(FileField, self).__init__(*args, **kwargs)
def to_internal_value(self, data):
@ -1198,8 +1368,14 @@ class FileField(Field):
return data
def to_representation(self, value):
if self.use_url:
if not value:
use_url = getattr(self, 'use_url', api_settings.UPLOADED_FILES_USE_URL)
if not value:
return None
if use_url:
if not getattr(value, 'url', None):
# If the file has not been saved it may not have a URL.
return None
url = value.url
request = self.context.get('request', None)
@ -1250,19 +1426,34 @@ class ListField(Field):
child = _UnvalidatedField()
initial = []
default_error_messages = {
'not_a_list': _('Expected a list of items but got type "{input_type}".')
'not_a_list': _('Expected a list of items but got type "{input_type}".'),
'empty': _('This list may not be empty.')
}
def __init__(self, *args, **kwargs):
self.child = kwargs.pop('child', copy.deepcopy(self.child))
self.allow_empty = kwargs.pop('allow_empty', True)
assert not inspect.isclass(self.child), '`child` has not been instantiated.'
assert self.child.source is None, (
"The `source` argument is not meaningful when applied to a `child=` field. "
"Remove `source=` from the field declaration."
)
super(ListField, self).__init__(*args, **kwargs)
self.child.bind(field_name='', parent=self)
def get_value(self, dictionary):
if self.field_name not in dictionary:
if getattr(self.root, 'partial', False):
return empty
# We override the default field access in order to support
# lists in HTML forms.
if html.is_html_input(dictionary):
val = dictionary.getlist(self.field_name, [])
if len(val) > 0:
# Support QueryDict lists in HTML input.
return val
return html.parse_html_list(dictionary, prefix=self.field_name)
return dictionary.get(self.field_name, empty)
@ -1272,8 +1463,10 @@ class ListField(Field):
"""
if html.is_html_input(data):
data = html.parse_html_list(data)
if isinstance(data, type('')) or not hasattr(data, '__iter__'):
if isinstance(data, type('')) or isinstance(data, collections.Mapping) or not hasattr(data, '__iter__'):
self.fail('not_a_list', input_type=type(data).__name__)
if not self.allow_empty and len(data) == 0:
self.fail('empty')
return [self.child.run_validation(item) for item in data]
def to_representation(self, data):
@ -1292,7 +1485,13 @@ class DictField(Field):
def __init__(self, *args, **kwargs):
self.child = kwargs.pop('child', copy.deepcopy(self.child))
assert not inspect.isclass(self.child), '`child` has not been instantiated.'
assert self.child.source is None, (
"The `source` argument is not meaningful when applied to a `child=` field. "
"Remove `source=` from the field declaration."
)
super(DictField, self).__init__(*args, **kwargs)
self.child.bind(field_name='', parent=self)
@ -1311,19 +1510,50 @@ class DictField(Field):
data = html.parse_html_dict(data)
if not isinstance(data, dict):
self.fail('not_a_dict', input_type=type(data).__name__)
return dict([
(six.text_type(key), self.child.run_validation(value))
return {
six.text_type(key): self.child.run_validation(value)
for key, value in data.items()
])
}
def to_representation(self, value):
"""
List of object instances -> List of dicts of primitive datatypes.
"""
return dict([
(six.text_type(key), self.child.to_representation(val))
return {
six.text_type(key): self.child.to_representation(val)
for key, val in value.items()
])
}
class JSONField(Field):
default_error_messages = {
'invalid': _('Value must be valid JSON.')
}
def __init__(self, *args, **kwargs):
self.binary = kwargs.pop('binary', False)
super(JSONField, self).__init__(*args, **kwargs)
def to_internal_value(self, data):
try:
if self.binary:
if isinstance(data, six.binary_type):
data = data.decode('utf-8')
return json.loads(data)
else:
json.dumps(data)
except (TypeError, ValueError):
self.fail('invalid')
return data
def to_representation(self, value):
if self.binary:
value = json.dumps(value)
# On python 2.x the return type for json.dumps() is underspecified.
# On python 3.x json.dumps() returns unicode strings.
if isinstance(value, six.text_type):
value = bytes(value.encode('utf-8'))
return value
# Miscellaneous field types...
@ -1337,7 +1567,7 @@ class ReadOnlyField(Field):
For example, the following would call `get_expiry_date()` on the object:
class ExampleSerializer(self):
class ExampleSerializer(Serializer):
expiry_date = ReadOnlyField(source='get_expiry_date')
"""

View File

@ -4,15 +4,60 @@ returned by list views.
"""
from __future__ import unicode_literals
import operator
from functools import reduce
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
from django.db import models
from django.template import loader
from django.utils import six
from rest_framework.compat import django_filters, guardian, get_model_name
from rest_framework.settings import api_settings
from functools import reduce
import operator
from django.utils.translation import ugettext_lazy as _
FilterSet = django_filters and django_filters.FilterSet or None
from rest_framework.compat import (
crispy_forms, distinct, django_filters, guardian, template_render
)
from rest_framework.settings import api_settings
if 'crispy_forms' in settings.INSTALLED_APPS and crispy_forms and django_filters:
# If django-crispy-forms is installed, use it to get a bootstrap3 rendering
# of the DjangoFilterBackend controls when displayed as HTML.
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Layout, Submit
class FilterSet(django_filters.FilterSet):
def __init__(self, *args, **kwargs):
super(FilterSet, self).__init__(*args, **kwargs)
for field in self.form.fields.values():
field.help_text = None
layout_components = list(self.form.fields.keys()) + [
Submit('', _('Submit'), css_class='btn-default'),
]
helper = FormHelper()
helper.form_method = 'GET'
helper.template_pack = 'bootstrap3'
helper.layout = Layout(*layout_components)
self.form.helper = helper
filter_template = 'rest_framework/filters/django_filter_crispyforms.html'
elif django_filters:
# If django-crispy-forms is not installed, use the standard
# 'form.as_p' rendering when DjangoFilterBackend is displayed as HTML.
class FilterSet(django_filters.FilterSet):
def __init__(self, *args, **kwargs):
super(FilterSet, self).__init__(*args, **kwargs)
for field in self.form.fields.values():
field.help_text = None
filter_template = 'rest_framework/filters/django_filter.html'
else:
FilterSet = None
filter_template = None
class BaseFilterBackend(object):
@ -32,6 +77,7 @@ class DjangoFilterBackend(BaseFilterBackend):
A filter backend that uses django-filter.
"""
default_filter_set = FilterSet
template = filter_template
def __init__(self):
assert django_filters, 'Using DjangoFilterBackend, but django-filter is not installed'
@ -53,10 +99,11 @@ class DjangoFilterBackend(BaseFilterBackend):
return filter_class
if filter_fields:
class AutoFilterSet(self.default_filter_set):
class AutoFilterSet(FilterSet):
class Meta:
model = queryset.model
fields = filter_fields
return AutoFilterSet
return None
@ -69,10 +116,22 @@ class DjangoFilterBackend(BaseFilterBackend):
return queryset
def to_html(self, request, queryset, view):
filter_class = self.get_filter_class(view, queryset)
if not filter_class:
return None
filter_instance = filter_class(request.query_params, queryset=queryset)
context = {
'filter': filter_instance
}
template = loader.get_template(self.template)
return template_render(template, context)
class SearchFilter(BaseFilterBackend):
# The URL query parameter used for the search.
search_param = api_settings.SEARCH_PARAM
template = 'rest_framework/filters/search.html'
def get_search_terms(self, request):
"""
@ -89,30 +148,55 @@ class SearchFilter(BaseFilterBackend):
return "%s__iexact" % field_name[1:]
elif field_name.startswith('@'):
return "%s__search" % field_name[1:]
if field_name.startswith('$'):
return "%s__iregex" % field_name[1:]
else:
return "%s__icontains" % field_name
def filter_queryset(self, request, queryset, view):
search_fields = getattr(view, 'search_fields', None)
search_terms = self.get_search_terms(request)
if not search_fields:
if not search_fields or not search_terms:
return queryset
orm_lookups = [self.construct_search(six.text_type(search_field))
for search_field in search_fields]
orm_lookups = [
self.construct_search(six.text_type(search_field))
for search_field in search_fields
]
for search_term in self.get_search_terms(request):
or_queries = [models.Q(**{orm_lookup: search_term})
for orm_lookup in orm_lookups]
queryset = queryset.filter(reduce(operator.or_, or_queries)).distinct()
base = queryset
for search_term in search_terms:
queries = [
models.Q(**{orm_lookup: search_term})
for orm_lookup in orm_lookups
]
queryset = queryset.filter(reduce(operator.or_, queries))
return queryset
# Filtering against a many-to-many field requires us to
# call queryset.distinct() in order to avoid duplicate items
# in the resulting queryset.
return distinct(queryset, base)
def to_html(self, request, queryset, view):
if not getattr(view, 'search_fields', None):
return ''
term = self.get_search_terms(request)
term = term[0] if term else ''
context = {
'param': self.search_param,
'term': term
}
template = loader.get_template(self.template)
return template_render(template, context)
class OrderingFilter(BaseFilterBackend):
# The URL query parameter used for the ordering.
ordering_param = api_settings.ORDERING_PARAM
ordering_fields = None
template = 'rest_framework/filters/ordering.html'
def get_ordering(self, request, queryset, view):
"""
@ -138,7 +222,7 @@ class OrderingFilter(BaseFilterBackend):
return (ordering,)
return ordering
def remove_invalid_fields(self, queryset, fields, view):
def get_valid_fields(self, queryset, view):
valid_fields = getattr(view, 'ordering_fields', self.ordering_fields)
if valid_fields is None:
@ -149,15 +233,30 @@ class OrderingFilter(BaseFilterBackend):
"'serializer_class' or 'ordering_fields' attribute.")
raise ImproperlyConfigured(msg % self.__class__.__name__)
valid_fields = [
field.source or field_name
(field.source or field_name, field.label)
for field_name, field in serializer_class().fields.items()
if not getattr(field, 'write_only', False)
if not getattr(field, 'write_only', False) and not field.source == '*'
]
elif valid_fields == '__all__':
# View explicitly allows filtering on any model field
valid_fields = [field.name for field in queryset.model._meta.fields]
valid_fields += queryset.query.aggregates.keys()
valid_fields = [
(field.name, getattr(field, 'label', field.name.title()))
for field in queryset.model._meta.fields
]
valid_fields += [
(key, key.title().split('__'))
for key in queryset.query.aggregates.keys()
]
else:
valid_fields = [
(item, item) if isinstance(item, six.string_types) else item
for item in valid_fields
]
return valid_fields
def remove_invalid_fields(self, queryset, fields, view):
valid_fields = [item[0] for item in self.get_valid_fields(queryset, view)]
return [term for term in fields if term.lstrip('-') in valid_fields]
def filter_queryset(self, request, queryset, view):
@ -168,6 +267,25 @@ class OrderingFilter(BaseFilterBackend):
return queryset
def get_template_context(self, request, queryset, view):
current = self.get_ordering(request, queryset, view)
current = None if current is None else current[0]
options = []
for key, label in self.get_valid_fields(queryset, view):
options.append((key, '%s - ascending' % label))
options.append(('-' + key, '%s - descending' % label))
return {
'request': request,
'current': current,
'param': self.ordering_param,
'options': options,
}
def to_html(self, request, queryset, view):
template = loader.get_template(self.template)
context = self.get_template_context(request, queryset, view)
return template_render(template, context)
class DjangoObjectPermissionsFilter(BaseFilterBackend):
"""
@ -180,11 +298,17 @@ class DjangoObjectPermissionsFilter(BaseFilterBackend):
perm_format = '%(app_label)s.view_%(model_name)s'
def filter_queryset(self, request, queryset, view):
extra = {}
user = request.user
model_cls = queryset.model
kwargs = {
'app_label': model_cls._meta.app_label,
'model_name': get_model_name(model_cls)
'model_name': model_cls._meta.model_name
}
permission = self.perm_format % kwargs
return guardian.shortcuts.get_objects_for_user(user, permission, queryset)
if guardian.VERSION >= (1, 3):
# Maintain behavior compatibility with versions prior to 1.3
extra = {'accept_global_perms': False}
else:
extra = {}
return guardian.shortcuts.get_objects_for_user(user, permission, queryset, **extra)

View File

@ -2,10 +2,12 @@
Generic views that provide commonly needed behaviour.
"""
from __future__ import unicode_literals
from django.db.models.query import QuerySet
from django.http import Http404
from django.shortcuts import get_object_or_404 as _get_object_or_404
from rest_framework import views, mixins
from rest_framework import mixins, views
from rest_framework.settings import api_settings

Binary file not shown.

View File

@ -0,0 +1,426 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# Translators:
msgid ""
msgstr ""
"Project-Id-Version: Django REST framework\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-12-07 18:53+0100\n"
"PO-Revision-Date: 2015-12-07 17:55+0000\n"
"Last-Translator: Xavier Ordoquy <xordoquy@linovia.com>\n"
"Language-Team: Acoli (http://www.transifex.com/django-rest-framework-1/django-rest-framework/language/ach/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: ach\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
#: authentication.py:72
msgid "Invalid basic header. No credentials provided."
msgstr ""
#: authentication.py:75
msgid "Invalid basic header. Credentials string should not contain spaces."
msgstr ""
#: authentication.py:81
msgid "Invalid basic header. Credentials not correctly base64 encoded."
msgstr ""
#: authentication.py:98
msgid "Invalid username/password."
msgstr ""
#: authentication.py:101 authentication.py:188
msgid "User inactive or deleted."
msgstr ""
#: authentication.py:167
msgid "Invalid token header. No credentials provided."
msgstr ""
#: authentication.py:170
msgid "Invalid token header. Token string should not contain spaces."
msgstr ""
#: authentication.py:176
msgid ""
"Invalid token header. Token string should not contain invalid characters."
msgstr ""
#: authentication.py:185
msgid "Invalid token."
msgstr ""
#: authtoken/serializers.py:20
msgid "User account is disabled."
msgstr ""
#: authtoken/serializers.py:23
msgid "Unable to log in with provided credentials."
msgstr ""
#: authtoken/serializers.py:26
msgid "Must include \"username\" and \"password\"."
msgstr ""
#: exceptions.py:49
msgid "A server error occurred."
msgstr ""
#: exceptions.py:84
msgid "Malformed request."
msgstr ""
#: exceptions.py:89
msgid "Incorrect authentication credentials."
msgstr ""
#: exceptions.py:94
msgid "Authentication credentials were not provided."
msgstr ""
#: exceptions.py:99
msgid "You do not have permission to perform this action."
msgstr ""
#: exceptions.py:104 views.py:81
msgid "Not found."
msgstr ""
#: exceptions.py:109
#, python-brace-format
msgid "Method \"{method}\" not allowed."
msgstr ""
#: exceptions.py:120
msgid "Could not satisfy the request Accept header."
msgstr ""
#: exceptions.py:132
#, python-brace-format
msgid "Unsupported media type \"{media_type}\" in request."
msgstr ""
#: exceptions.py:145
msgid "Request was throttled."
msgstr ""
#: fields.py:266 relations.py:195 relations.py:228 validators.py:79
#: validators.py:162
msgid "This field is required."
msgstr ""
#: fields.py:267
msgid "This field may not be null."
msgstr ""
#: fields.py:603 fields.py:634
#, python-brace-format
msgid "\"{input}\" is not a valid boolean."
msgstr ""
#: fields.py:669
msgid "This field may not be blank."
msgstr ""
#: fields.py:670 fields.py:1656
#, python-brace-format
msgid "Ensure this field has no more than {max_length} characters."
msgstr ""
#: fields.py:671
#, python-brace-format
msgid "Ensure this field has at least {min_length} characters."
msgstr ""
#: fields.py:708
msgid "Enter a valid email address."
msgstr ""
#: fields.py:719
msgid "This value does not match the required pattern."
msgstr ""
#: fields.py:730
msgid ""
"Enter a valid \"slug\" consisting of letters, numbers, underscores or "
"hyphens."
msgstr ""
#: fields.py:742
msgid "Enter a valid URL."
msgstr ""
#: fields.py:755
#, python-brace-format
msgid "\"{value}\" is not a valid UUID."
msgstr ""
#: fields.py:791
msgid "Enter a valid IPv4 or IPv6 address."
msgstr ""
#: fields.py:816
msgid "A valid integer is required."
msgstr ""
#: fields.py:817 fields.py:852 fields.py:885
#, python-brace-format
msgid "Ensure this value is less than or equal to {max_value}."
msgstr ""
#: fields.py:818 fields.py:853 fields.py:886
#, python-brace-format
msgid "Ensure this value is greater than or equal to {min_value}."
msgstr ""
#: fields.py:819 fields.py:854 fields.py:890
msgid "String value too large."
msgstr ""
#: fields.py:851 fields.py:884
msgid "A valid number is required."
msgstr ""
#: fields.py:887
#, python-brace-format
msgid "Ensure that there are no more than {max_digits} digits in total."
msgstr ""
#: fields.py:888
#, python-brace-format
msgid ""
"Ensure that there are no more than {max_decimal_places} decimal places."
msgstr ""
#: fields.py:889
#, python-brace-format
msgid ""
"Ensure that there are no more than {max_whole_digits} digits before the "
"decimal point."
msgstr ""
#: fields.py:1004
#, python-brace-format
msgid "Datetime has wrong format. Use one of these formats instead: {format}."
msgstr ""
#: fields.py:1005
msgid "Expected a datetime but got a date."
msgstr ""
#: fields.py:1079
#, python-brace-format
msgid "Date has wrong format. Use one of these formats instead: {format}."
msgstr ""
#: fields.py:1080
msgid "Expected a date but got a datetime."
msgstr ""
#: fields.py:1148
#, python-brace-format
msgid "Time has wrong format. Use one of these formats instead: {format}."
msgstr ""
#: fields.py:1207
#, python-brace-format
msgid "Duration has wrong format. Use one of these formats instead: {format}."
msgstr ""
#: fields.py:1232 fields.py:1281
#, python-brace-format
msgid "\"{input}\" is not a valid choice."
msgstr ""
#: fields.py:1235 relations.py:62 relations.py:431
#, python-brace-format
msgid "More than {count} items..."
msgstr ""
#: fields.py:1282 fields.py:1429 relations.py:427 serializers.py:520
#, python-brace-format
msgid "Expected a list of items but got type \"{input_type}\"."
msgstr ""
#: fields.py:1283
msgid "This selection may not be empty."
msgstr ""
#: fields.py:1320
#, python-brace-format
msgid "\"{input}\" is not a valid path choice."
msgstr ""
#: fields.py:1339
msgid "No file was submitted."
msgstr ""
#: fields.py:1340
msgid ""
"The submitted data was not a file. Check the encoding type on the form."
msgstr ""
#: fields.py:1341
msgid "No filename could be determined."
msgstr ""
#: fields.py:1342
msgid "The submitted file is empty."
msgstr ""
#: fields.py:1343
#, python-brace-format
msgid ""
"Ensure this filename has at most {max_length} characters (it has {length})."
msgstr ""
#: fields.py:1391
msgid ""
"Upload a valid image. The file you uploaded was either not an image or a "
"corrupted image."
msgstr ""
#: fields.py:1430 relations.py:428 serializers.py:521
msgid "This list may not be empty."
msgstr ""
#: fields.py:1483
#, python-brace-format
msgid "Expected a dictionary of items but got type \"{input_type}\"."
msgstr ""
#: fields.py:1530
msgid "Value must be valid JSON."
msgstr ""
#: filters.py:35 templates/rest_framework/filters/django_filter.html:5
msgid "Submit"
msgstr ""
#: pagination.py:189
#, python-brace-format
msgid "Invalid page \"{page_number}\": {message}."
msgstr ""
#: pagination.py:407
msgid "Invalid cursor"
msgstr ""
#: relations.py:196
#, python-brace-format
msgid "Invalid pk \"{pk_value}\" - object does not exist."
msgstr ""
#: relations.py:197
#, python-brace-format
msgid "Incorrect type. Expected pk value, received {data_type}."
msgstr ""
#: relations.py:229
msgid "Invalid hyperlink - No URL match."
msgstr ""
#: relations.py:230
msgid "Invalid hyperlink - Incorrect URL match."
msgstr ""
#: relations.py:231
msgid "Invalid hyperlink - Object does not exist."
msgstr ""
#: relations.py:232
#, python-brace-format
msgid "Incorrect type. Expected URL string, received {data_type}."
msgstr ""
#: relations.py:391
#, python-brace-format
msgid "Object with {slug_name}={value} does not exist."
msgstr ""
#: relations.py:392
msgid "Invalid value."
msgstr ""
#: serializers.py:326
#, python-brace-format
msgid "Invalid data. Expected a dictionary, but got {datatype}."
msgstr ""
#: templates/rest_framework/admin.html:118
#: templates/rest_framework/base.html:128
msgid "Filters"
msgstr ""
#: templates/rest_framework/filters/django_filter.html:2
#: templates/rest_framework/filters/django_filter_crispyforms.html:4
msgid "Field filters"
msgstr ""
#: templates/rest_framework/filters/ordering.html:3
msgid "Ordering"
msgstr ""
#: templates/rest_framework/filters/search.html:2
msgid "Search"
msgstr ""
#: templates/rest_framework/horizontal/radio.html:2
#: templates/rest_framework/inline/radio.html:2
#: templates/rest_framework/vertical/radio.html:2
msgid "None"
msgstr ""
#: templates/rest_framework/horizontal/select_multiple.html:2
#: templates/rest_framework/inline/select_multiple.html:2
#: templates/rest_framework/vertical/select_multiple.html:2
msgid "No items to select."
msgstr ""
#: validators.py:24
msgid "This field must be unique."
msgstr ""
#: validators.py:78
#, python-brace-format
msgid "The fields {field_names} must make a unique set."
msgstr ""
#: validators.py:226
#, python-brace-format
msgid "This field must be unique for the \"{date_field}\" date."
msgstr ""
#: validators.py:241
#, python-brace-format
msgid "This field must be unique for the \"{date_field}\" month."
msgstr ""
#: validators.py:254
#, python-brace-format
msgid "This field must be unique for the \"{date_field}\" year."
msgstr ""
#: versioning.py:42
msgid "Invalid version in \"Accept\" header."
msgstr ""
#: versioning.py:73 versioning.py:115
msgid "Invalid version in URL path."
msgstr ""
#: versioning.py:144
msgid "Invalid version in hostname."
msgstr ""
#: versioning.py:166
msgid "Invalid version in query parameter."
msgstr ""
#: views.py:88
msgid "Permission denied."
msgstr ""

View File

@ -8,33 +8,33 @@ msgid ""
msgstr ""
"Project-Id-Version: Django REST framework\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-06-03 17:30+0100\n"
"PO-Revision-Date: 2015-06-03 16:30+0000\n"
"POT-Creation-Date: 2015-12-07 18:53+0100\n"
"PO-Revision-Date: 2015-12-07 17:55+0000\n"
"Last-Translator: Xavier Ordoquy <xordoquy@linovia.com>\n"
"Language-Team: Arabic (http://www.transifex.com/projects/p/django-rest-framework/language/ar/)\n"
"Language-Team: Arabic (http://www.transifex.com/django-rest-framework-1/django-rest-framework/language/ar/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: ar\n"
"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;\n"
#: authentication.py:70
#: authentication.py:72
msgid "Invalid basic header. No credentials provided."
msgstr ""
#: authentication.py:73
#: authentication.py:75
msgid "Invalid basic header. Credentials string should not contain spaces."
msgstr ""
#: authentication.py:79
#: authentication.py:81
msgid "Invalid basic header. Credentials not correctly base64 encoded."
msgstr ""
#: authentication.py:97
#: authentication.py:98
msgid "Invalid username/password."
msgstr "اسم المستخدم/كلمة السر غير صحيحين."
#: authentication.py:100 authentication.py:182
#: authentication.py:101 authentication.py:188
msgid "User inactive or deleted."
msgstr "المستخدم غير مفعل او تم حذفه."
@ -46,7 +46,12 @@ msgstr ""
msgid "Invalid token header. Token string should not contain spaces."
msgstr ""
#: authentication.py:179
#: authentication.py:176
msgid ""
"Invalid token header. Token string should not contain invalid characters."
msgstr ""
#: authentication.py:185
msgid "Invalid token."
msgstr ""
@ -62,261 +67,309 @@ msgstr "تعذر تسجيل الدخول بالبيانات التي ادخلت
msgid "Must include \"username\" and \"password\"."
msgstr "يجب أن تتضمن \"اسم المستخدم\" و \"كلمة المرور\"."
#: exceptions.py:38
#: exceptions.py:49
msgid "A server error occurred."
msgstr "حدث خطأ في المخدم."
#: exceptions.py:73
#: exceptions.py:84
msgid "Malformed request."
msgstr ""
#: exceptions.py:78
#: exceptions.py:89
msgid "Incorrect authentication credentials."
msgstr "بيانات الدخول غير صحيحة."
#: exceptions.py:83
#: exceptions.py:94
msgid "Authentication credentials were not provided."
msgstr "لم يتم تزويد بيانات الدخول."
#: exceptions.py:88
#: exceptions.py:99
msgid "You do not have permission to perform this action."
msgstr "ليس لديك صلاحية للقيام بهذا الإجراء."
#: exceptions.py:93 views.py:78
#: exceptions.py:104 views.py:81
msgid "Not found."
msgstr "غير موجود."
#: exceptions.py:98
#: exceptions.py:109
#, python-brace-format
msgid "Method \"{method}\" not allowed."
msgstr ""
#: exceptions.py:109
#: exceptions.py:120
msgid "Could not satisfy the request Accept header."
msgstr ""
#: exceptions.py:121
#: exceptions.py:132
#, python-brace-format
msgid "Unsupported media type \"{media_type}\" in request."
msgstr ""
#: exceptions.py:134
#: exceptions.py:145
msgid "Request was throttled."
msgstr ""
#: fields.py:162 relations.py:132 relations.py:156 validators.py:77
#: validators.py:160
#: fields.py:266 relations.py:195 relations.py:228 validators.py:79
#: validators.py:162
msgid "This field is required."
msgstr "هذا الحقل مطلوب."
#: fields.py:163
#: fields.py:267
msgid "This field may not be null."
msgstr "لا يمكن لهذا الحقل ان يكون فارغاً null."
#: fields.py:496 fields.py:524
#: fields.py:603 fields.py:634
#, python-brace-format
msgid "\"{input}\" is not a valid boolean."
msgstr "\"{input}\" ليس قيمة منطقية."
#: fields.py:559
#: fields.py:669
msgid "This field may not be blank."
msgstr "لا يمكن لهذا الحقل ان يكون فارغاً."
#: fields.py:560 fields.py:1386
#: fields.py:670 fields.py:1656
#, python-brace-format
msgid "Ensure this field has no more than {max_length} characters."
msgstr "تأكد ان الحقل لا يزيد عن {max_length} محرف."
#: fields.py:561
#: fields.py:671
#, python-brace-format
msgid "Ensure this field has at least {min_length} characters."
msgstr "تأكد ان الحقل {min_length} محرف على الاقل."
#: fields.py:598
#: fields.py:708
msgid "Enter a valid email address."
msgstr "عليك ان تدخل بريد إلكتروني صالح."
#: fields.py:609
#: fields.py:719
msgid "This value does not match the required pattern."
msgstr "هذه القيمة لا تطابق النمط المطلوب."
#: fields.py:620
#: fields.py:730
msgid ""
"Enter a valid \"slug\" consisting of letters, numbers, underscores or "
"hyphens."
msgstr ""
#: fields.py:632
#: fields.py:742
msgid "Enter a valid URL."
msgstr "الرجاء إدخال رابط إلكتروني صالح."
#: fields.py:645
#: fields.py:755
#, python-brace-format
msgid "\"{value}\" is not a valid UUID."
msgstr ""
#: fields.py:679
#: fields.py:791
msgid "Enter a valid IPv4 or IPv6 address."
msgstr ""
#: fields.py:816
msgid "A valid integer is required."
msgstr "الرجاء إدخال رقم صحيح صالح."
#: fields.py:680 fields.py:715 fields.py:748
#: fields.py:817 fields.py:852 fields.py:885
#, python-brace-format
msgid "Ensure this value is less than or equal to {max_value}."
msgstr "تأكد ان القيمة أقل أو تساوي {max_value}."
#: fields.py:681 fields.py:716 fields.py:749
#: fields.py:818 fields.py:853 fields.py:886
#, python-brace-format
msgid "Ensure this value is greater than or equal to {min_value}."
msgstr "تأكد ان القيمة أكبر أو تساوي {min_value}."
#: fields.py:682 fields.py:717 fields.py:753
#: fields.py:819 fields.py:854 fields.py:890
msgid "String value too large."
msgstr ""
#: fields.py:714 fields.py:747
#: fields.py:851 fields.py:884
msgid "A valid number is required."
msgstr "الرجاء إدخال رقم صالح."
#: fields.py:750
#: fields.py:887
#, python-brace-format
msgid "Ensure that there are no more than {max_digits} digits in total."
msgstr "تأكد ان القيمة لا تحوي أكثر من {max_digits} رقم."
#: fields.py:751
#: fields.py:888
#, python-brace-format
msgid ""
"Ensure that there are no more than {max_decimal_places} decimal places."
msgstr ""
#: fields.py:752
#: fields.py:889
#, python-brace-format
msgid ""
"Ensure that there are no more than {max_whole_digits} digits before the "
"decimal point."
msgstr ""
#: fields.py:842
#: fields.py:1004
#, python-brace-format
msgid "Datetime has wrong format. Use one of these formats instead: {format}."
msgstr "صيغة التاريخ و الوقت غير صحيحة. عليك أن تستخدم واحدة من هذه الصيغ التالية: {format}."
#: fields.py:843
#: fields.py:1005
msgid "Expected a datetime but got a date."
msgstr ""
#: fields.py:907
#: fields.py:1079
#, python-brace-format
msgid "Date has wrong format. Use one of these formats instead: {format}."
msgstr "صيغة التاريخ غير صحيحة. عليك أن تستخدم واحدة من هذه الصيغ التالية: {format}."
#: fields.py:908
#: fields.py:1080
msgid "Expected a date but got a datetime."
msgstr ""
#: fields.py:971
#: fields.py:1148
#, python-brace-format
msgid "Time has wrong format. Use one of these formats instead: {format}."
msgstr "صيغة الوقت غير صحيحة. عليك أن تستخدم واحدة من هذه الصيغ التالية: {format}."
#: fields.py:1025
#: fields.py:1207
#, python-brace-format
msgid "Duration has wrong format. Use one of these formats instead: {format}."
msgstr ""
#: fields.py:1050 fields.py:1094
#: fields.py:1232 fields.py:1281
#, python-brace-format
msgid "\"{input}\" is not a valid choice."
msgstr "\"{input}\" ليست واحدة من الخيارات الصالحة."
#: fields.py:1095 fields.py:1213 serializers.py:487
#: fields.py:1235 relations.py:62 relations.py:431
#, python-brace-format
msgid "More than {count} items..."
msgstr ""
#: fields.py:1282 fields.py:1429 relations.py:427 serializers.py:520
#, python-brace-format
msgid "Expected a list of items but got type \"{input_type}\"."
msgstr ""
#: fields.py:1129
#: fields.py:1283
msgid "This selection may not be empty."
msgstr ""
#: fields.py:1320
#, python-brace-format
msgid "\"{input}\" is not a valid path choice."
msgstr ""
#: fields.py:1339
msgid "No file was submitted."
msgstr "لم يتم إرسال أي ملف."
#: fields.py:1130
#: fields.py:1340
msgid ""
"The submitted data was not a file. Check the encoding type on the form."
msgstr ""
#: fields.py:1131
#: fields.py:1341
msgid "No filename could be determined."
msgstr ""
#: fields.py:1132
#: fields.py:1342
msgid "The submitted file is empty."
msgstr "الملف الذي تم إرساله فارغ."
#: fields.py:1133
#: fields.py:1343
#, python-brace-format
msgid ""
"Ensure this filename has at most {max_length} characters (it has {length})."
msgstr "تأكد ان اسم الملف لا يحوي أكثر من {max_length} محرف (الإسم المرسل يحوي {length} محرف)."
#: fields.py:1175
#: fields.py:1391
msgid ""
"Upload a valid image. The file you uploaded was either not an image or a "
"corrupted image."
msgstr ""
#: fields.py:1250
#: fields.py:1430 relations.py:428 serializers.py:521
msgid "This list may not be empty."
msgstr ""
#: fields.py:1483
#, python-brace-format
msgid "Expected a dictionary of items but got type \"{input_type}\"."
msgstr ""
#: pagination.py:231
#: fields.py:1530
msgid "Value must be valid JSON."
msgstr ""
#: filters.py:35 templates/rest_framework/filters/django_filter.html:5
msgid "Submit"
msgstr ""
#: pagination.py:189
#, python-brace-format
msgid "Invalid page \"{page_number}\": {message}."
msgstr "رقم الصفحة \"{page_number}\" غير صالح : {message}."
#: pagination.py:492
#: pagination.py:407
msgid "Invalid cursor"
msgstr ""
#: relations.py:133
#: relations.py:196
#, python-brace-format
msgid "Invalid pk \"{pk_value}\" - object does not exist."
msgstr "معرف العنصر \"{pk_value}\" غير صالح - العنصر غير موجود."
#: relations.py:134
#: relations.py:197
#, python-brace-format
msgid "Incorrect type. Expected pk value, received {data_type}."
msgstr ""
#: relations.py:157
#: relations.py:229
msgid "Invalid hyperlink - No URL match."
msgstr ""
#: relations.py:158
#: relations.py:230
msgid "Invalid hyperlink - Incorrect URL match."
msgstr ""
#: relations.py:159
#: relations.py:231
msgid "Invalid hyperlink - Object does not exist."
msgstr ""
#: relations.py:160
#: relations.py:232
#, python-brace-format
msgid "Incorrect type. Expected URL string, received {data_type}."
msgstr ""
#: relations.py:302
#: relations.py:391
#, python-brace-format
msgid "Object with {slug_name}={value} does not exist."
msgstr ""
#: relations.py:303
#: relations.py:392
msgid "Invalid value."
msgstr "قيمة غير صالحة."
#: serializers.py:304
#: serializers.py:326
#, python-brace-format
msgid "Invalid data. Expected a dictionary, but got {datatype}."
msgstr ""
#: templates/rest_framework/admin.html:118
#: templates/rest_framework/base.html:128
msgid "Filters"
msgstr ""
#: templates/rest_framework/filters/django_filter.html:2
#: templates/rest_framework/filters/django_filter_crispyforms.html:4
msgid "Field filters"
msgstr ""
#: templates/rest_framework/filters/ordering.html:3
msgid "Ordering"
msgstr ""
#: templates/rest_framework/filters/search.html:2
msgid "Search"
msgstr ""
#: templates/rest_framework/horizontal/radio.html:2
#: templates/rest_framework/inline/radio.html:2
#: templates/rest_framework/vertical/radio.html:2
@ -329,46 +382,46 @@ msgstr ""
msgid "No items to select."
msgstr ""
#: validators.py:22
#: validators.py:24
msgid "This field must be unique."
msgstr ""
#: validators.py:76
#: validators.py:78
#, python-brace-format
msgid "The fields {field_names} must make a unique set."
msgstr ""
#: validators.py:224
#: validators.py:226
#, python-brace-format
msgid "This field must be unique for the \"{date_field}\" date."
msgstr ""
#: validators.py:239
#: validators.py:241
#, python-brace-format
msgid "This field must be unique for the \"{date_field}\" month."
msgstr ""
#: validators.py:252
#: validators.py:254
#, python-brace-format
msgid "This field must be unique for the \"{date_field}\" year."
msgstr ""
#: versioning.py:39
#: versioning.py:42
msgid "Invalid version in \"Accept\" header."
msgstr ""
#: versioning.py:70 versioning.py:112
#: versioning.py:73 versioning.py:115
msgid "Invalid version in URL path."
msgstr ""
#: versioning.py:141
#: versioning.py:144
msgid "Invalid version in hostname."
msgstr ""
#: versioning.py:163
#: versioning.py:166
msgid "Invalid version in query parameter."
msgstr ""
#: views.py:85
#: views.py:88
msgid "Permission denied."
msgstr ""

View File

@ -7,33 +7,33 @@ msgid ""
msgstr ""
"Project-Id-Version: Django REST framework\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-06-03 17:30+0100\n"
"PO-Revision-Date: 2015-06-03 16:30+0000\n"
"POT-Creation-Date: 2015-12-07 18:53+0100\n"
"PO-Revision-Date: 2015-12-07 17:55+0000\n"
"Last-Translator: Xavier Ordoquy <xordoquy@linovia.com>\n"
"Language-Team: Belarusian (http://www.transifex.com/projects/p/django-rest-framework/language/be/)\n"
"Language-Team: Belarusian (http://www.transifex.com/django-rest-framework-1/django-rest-framework/language/be/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: be\n"
"Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);\n"
#: authentication.py:70
#: authentication.py:72
msgid "Invalid basic header. No credentials provided."
msgstr ""
#: authentication.py:73
#: authentication.py:75
msgid "Invalid basic header. Credentials string should not contain spaces."
msgstr ""
#: authentication.py:79
#: authentication.py:81
msgid "Invalid basic header. Credentials not correctly base64 encoded."
msgstr ""
#: authentication.py:97
#: authentication.py:98
msgid "Invalid username/password."
msgstr ""
#: authentication.py:100 authentication.py:182
#: authentication.py:101 authentication.py:188
msgid "User inactive or deleted."
msgstr ""
@ -45,7 +45,12 @@ msgstr ""
msgid "Invalid token header. Token string should not contain spaces."
msgstr ""
#: authentication.py:179
#: authentication.py:176
msgid ""
"Invalid token header. Token string should not contain invalid characters."
msgstr ""
#: authentication.py:185
msgid "Invalid token."
msgstr ""
@ -61,261 +66,309 @@ msgstr ""
msgid "Must include \"username\" and \"password\"."
msgstr ""
#: exceptions.py:38
#: exceptions.py:49
msgid "A server error occurred."
msgstr ""
#: exceptions.py:73
#: exceptions.py:84
msgid "Malformed request."
msgstr ""
#: exceptions.py:78
#: exceptions.py:89
msgid "Incorrect authentication credentials."
msgstr ""
#: exceptions.py:83
#: exceptions.py:94
msgid "Authentication credentials were not provided."
msgstr ""
#: exceptions.py:88
#: exceptions.py:99
msgid "You do not have permission to perform this action."
msgstr ""
#: exceptions.py:93 views.py:78
#: exceptions.py:104 views.py:81
msgid "Not found."
msgstr ""
#: exceptions.py:98
#: exceptions.py:109
#, python-brace-format
msgid "Method \"{method}\" not allowed."
msgstr ""
#: exceptions.py:109
#: exceptions.py:120
msgid "Could not satisfy the request Accept header."
msgstr ""
#: exceptions.py:121
#: exceptions.py:132
#, python-brace-format
msgid "Unsupported media type \"{media_type}\" in request."
msgstr ""
#: exceptions.py:134
#: exceptions.py:145
msgid "Request was throttled."
msgstr ""
#: fields.py:162 relations.py:132 relations.py:156 validators.py:77
#: validators.py:160
#: fields.py:266 relations.py:195 relations.py:228 validators.py:79
#: validators.py:162
msgid "This field is required."
msgstr ""
#: fields.py:163
#: fields.py:267
msgid "This field may not be null."
msgstr ""
#: fields.py:496 fields.py:524
#: fields.py:603 fields.py:634
#, python-brace-format
msgid "\"{input}\" is not a valid boolean."
msgstr ""
#: fields.py:559
#: fields.py:669
msgid "This field may not be blank."
msgstr ""
#: fields.py:560 fields.py:1386
#: fields.py:670 fields.py:1656
#, python-brace-format
msgid "Ensure this field has no more than {max_length} characters."
msgstr ""
#: fields.py:561
#: fields.py:671
#, python-brace-format
msgid "Ensure this field has at least {min_length} characters."
msgstr ""
#: fields.py:598
#: fields.py:708
msgid "Enter a valid email address."
msgstr ""
#: fields.py:609
#: fields.py:719
msgid "This value does not match the required pattern."
msgstr ""
#: fields.py:620
#: fields.py:730
msgid ""
"Enter a valid \"slug\" consisting of letters, numbers, underscores or "
"hyphens."
msgstr ""
#: fields.py:632
#: fields.py:742
msgid "Enter a valid URL."
msgstr ""
#: fields.py:645
#: fields.py:755
#, python-brace-format
msgid "\"{value}\" is not a valid UUID."
msgstr ""
#: fields.py:679
#: fields.py:791
msgid "Enter a valid IPv4 or IPv6 address."
msgstr ""
#: fields.py:816
msgid "A valid integer is required."
msgstr ""
#: fields.py:680 fields.py:715 fields.py:748
#: fields.py:817 fields.py:852 fields.py:885
#, python-brace-format
msgid "Ensure this value is less than or equal to {max_value}."
msgstr ""
#: fields.py:681 fields.py:716 fields.py:749
#: fields.py:818 fields.py:853 fields.py:886
#, python-brace-format
msgid "Ensure this value is greater than or equal to {min_value}."
msgstr ""
#: fields.py:682 fields.py:717 fields.py:753
#: fields.py:819 fields.py:854 fields.py:890
msgid "String value too large."
msgstr ""
#: fields.py:714 fields.py:747
#: fields.py:851 fields.py:884
msgid "A valid number is required."
msgstr ""
#: fields.py:750
#: fields.py:887
#, python-brace-format
msgid "Ensure that there are no more than {max_digits} digits in total."
msgstr ""
#: fields.py:751
#: fields.py:888
#, python-brace-format
msgid ""
"Ensure that there are no more than {max_decimal_places} decimal places."
msgstr ""
#: fields.py:752
#: fields.py:889
#, python-brace-format
msgid ""
"Ensure that there are no more than {max_whole_digits} digits before the "
"decimal point."
msgstr ""
#: fields.py:842
#: fields.py:1004
#, python-brace-format
msgid "Datetime has wrong format. Use one of these formats instead: {format}."
msgstr ""
#: fields.py:843
#: fields.py:1005
msgid "Expected a datetime but got a date."
msgstr ""
#: fields.py:907
#: fields.py:1079
#, python-brace-format
msgid "Date has wrong format. Use one of these formats instead: {format}."
msgstr ""
#: fields.py:908
#: fields.py:1080
msgid "Expected a date but got a datetime."
msgstr ""
#: fields.py:971
#: fields.py:1148
#, python-brace-format
msgid "Time has wrong format. Use one of these formats instead: {format}."
msgstr ""
#: fields.py:1025
#: fields.py:1207
#, python-brace-format
msgid "Duration has wrong format. Use one of these formats instead: {format}."
msgstr ""
#: fields.py:1050 fields.py:1094
#: fields.py:1232 fields.py:1281
#, python-brace-format
msgid "\"{input}\" is not a valid choice."
msgstr ""
#: fields.py:1095 fields.py:1213 serializers.py:487
#: fields.py:1235 relations.py:62 relations.py:431
#, python-brace-format
msgid "More than {count} items..."
msgstr ""
#: fields.py:1282 fields.py:1429 relations.py:427 serializers.py:520
#, python-brace-format
msgid "Expected a list of items but got type \"{input_type}\"."
msgstr ""
#: fields.py:1129
#: fields.py:1283
msgid "This selection may not be empty."
msgstr ""
#: fields.py:1320
#, python-brace-format
msgid "\"{input}\" is not a valid path choice."
msgstr ""
#: fields.py:1339
msgid "No file was submitted."
msgstr ""
#: fields.py:1130
#: fields.py:1340
msgid ""
"The submitted data was not a file. Check the encoding type on the form."
msgstr ""
#: fields.py:1131
#: fields.py:1341
msgid "No filename could be determined."
msgstr ""
#: fields.py:1132
#: fields.py:1342
msgid "The submitted file is empty."
msgstr ""
#: fields.py:1133
#: fields.py:1343
#, python-brace-format
msgid ""
"Ensure this filename has at most {max_length} characters (it has {length})."
msgstr ""
#: fields.py:1175
#: fields.py:1391
msgid ""
"Upload a valid image. The file you uploaded was either not an image or a "
"corrupted image."
msgstr ""
#: fields.py:1250
#: fields.py:1430 relations.py:428 serializers.py:521
msgid "This list may not be empty."
msgstr ""
#: fields.py:1483
#, python-brace-format
msgid "Expected a dictionary of items but got type \"{input_type}\"."
msgstr ""
#: pagination.py:231
#: fields.py:1530
msgid "Value must be valid JSON."
msgstr ""
#: filters.py:35 templates/rest_framework/filters/django_filter.html:5
msgid "Submit"
msgstr ""
#: pagination.py:189
#, python-brace-format
msgid "Invalid page \"{page_number}\": {message}."
msgstr ""
#: pagination.py:492
#: pagination.py:407
msgid "Invalid cursor"
msgstr ""
#: relations.py:133
#: relations.py:196
#, python-brace-format
msgid "Invalid pk \"{pk_value}\" - object does not exist."
msgstr ""
#: relations.py:134
#: relations.py:197
#, python-brace-format
msgid "Incorrect type. Expected pk value, received {data_type}."
msgstr ""
#: relations.py:157
#: relations.py:229
msgid "Invalid hyperlink - No URL match."
msgstr ""
#: relations.py:158
#: relations.py:230
msgid "Invalid hyperlink - Incorrect URL match."
msgstr ""
#: relations.py:159
#: relations.py:231
msgid "Invalid hyperlink - Object does not exist."
msgstr ""
#: relations.py:160
#: relations.py:232
#, python-brace-format
msgid "Incorrect type. Expected URL string, received {data_type}."
msgstr ""
#: relations.py:302
#: relations.py:391
#, python-brace-format
msgid "Object with {slug_name}={value} does not exist."
msgstr ""
#: relations.py:303
#: relations.py:392
msgid "Invalid value."
msgstr ""
#: serializers.py:304
#: serializers.py:326
#, python-brace-format
msgid "Invalid data. Expected a dictionary, but got {datatype}."
msgstr ""
#: templates/rest_framework/admin.html:118
#: templates/rest_framework/base.html:128
msgid "Filters"
msgstr ""
#: templates/rest_framework/filters/django_filter.html:2
#: templates/rest_framework/filters/django_filter_crispyforms.html:4
msgid "Field filters"
msgstr ""
#: templates/rest_framework/filters/ordering.html:3
msgid "Ordering"
msgstr ""
#: templates/rest_framework/filters/search.html:2
msgid "Search"
msgstr ""
#: templates/rest_framework/horizontal/radio.html:2
#: templates/rest_framework/inline/radio.html:2
#: templates/rest_framework/vertical/radio.html:2
@ -328,46 +381,46 @@ msgstr ""
msgid "No items to select."
msgstr ""
#: validators.py:22
#: validators.py:24
msgid "This field must be unique."
msgstr ""
#: validators.py:76
#: validators.py:78
#, python-brace-format
msgid "The fields {field_names} must make a unique set."
msgstr ""
#: validators.py:224
#: validators.py:226
#, python-brace-format
msgid "This field must be unique for the \"{date_field}\" date."
msgstr ""
#: validators.py:239
#: validators.py:241
#, python-brace-format
msgid "This field must be unique for the \"{date_field}\" month."
msgstr ""
#: validators.py:252
#: validators.py:254
#, python-brace-format
msgid "This field must be unique for the \"{date_field}\" year."
msgstr ""
#: versioning.py:39
#: versioning.py:42
msgid "Invalid version in \"Accept\" header."
msgstr ""
#: versioning.py:70 versioning.py:112
#: versioning.py:73 versioning.py:115
msgid "Invalid version in URL path."
msgstr ""
#: versioning.py:141
#: versioning.py:144
msgid "Invalid version in hostname."
msgstr ""
#: versioning.py:163
#: versioning.py:166
msgid "Invalid version in query parameter."
msgstr ""
#: views.py:85
#: views.py:88
msgid "Permission denied."
msgstr ""

Binary file not shown.

View File

@ -0,0 +1,426 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# Translators:
msgid ""
msgstr ""
"Project-Id-Version: Django REST framework\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-12-07 18:53+0100\n"
"PO-Revision-Date: 2015-12-07 17:55+0000\n"
"Last-Translator: Xavier Ordoquy <xordoquy@linovia.com>\n"
"Language-Team: Catalan (http://www.transifex.com/django-rest-framework-1/django-rest-framework/language/ca/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: ca\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: authentication.py:72
msgid "Invalid basic header. No credentials provided."
msgstr "Header Basic invàlid. No hi ha disponibles les credencials."
#: authentication.py:75
msgid "Invalid basic header. Credentials string should not contain spaces."
msgstr "Header Basic invàlid. Les credencials no poden contenir espais."
#: authentication.py:81
msgid "Invalid basic header. Credentials not correctly base64 encoded."
msgstr "Header Basic invàlid. Les credencials no estan codificades correctament en base64."
#: authentication.py:98
msgid "Invalid username/password."
msgstr "Usuari/Contrasenya incorrectes."
#: authentication.py:101 authentication.py:188
msgid "User inactive or deleted."
msgstr "Usuari inactiu o esborrat."
#: authentication.py:167
msgid "Invalid token header. No credentials provided."
msgstr "Token header invàlid. No s'han indicat les credencials."
#: authentication.py:170
msgid "Invalid token header. Token string should not contain spaces."
msgstr "Token header invàlid. El token no ha de contenir espais."
#: authentication.py:176
msgid ""
"Invalid token header. Token string should not contain invalid characters."
msgstr "Token header invàlid. El token no pot contenir caràcters invàlids."
#: authentication.py:185
msgid "Invalid token."
msgstr "Token invàlid."
#: authtoken/serializers.py:20
msgid "User account is disabled."
msgstr "Compte d'usuari desactivat."
#: authtoken/serializers.py:23
msgid "Unable to log in with provided credentials."
msgstr "No es possible loguejar-se amb les credencials introduïdes."
#: authtoken/serializers.py:26
msgid "Must include \"username\" and \"password\"."
msgstr "S'ha d'incloure \"username\" i \"password\"."
#: exceptions.py:49
msgid "A server error occurred."
msgstr "S'ha produït un error en el servidor."
#: exceptions.py:84
msgid "Malformed request."
msgstr "Request amb format incorrecte."
#: exceptions.py:89
msgid "Incorrect authentication credentials."
msgstr "Credencials d'autenticació incorrectes."
#: exceptions.py:94
msgid "Authentication credentials were not provided."
msgstr "Credencials d'autenticació no disponibles."
#: exceptions.py:99
msgid "You do not have permission to perform this action."
msgstr "No té permisos per realitzar aquesta acció."
#: exceptions.py:104 views.py:81
msgid "Not found."
msgstr "No trobat."
#: exceptions.py:109
#, python-brace-format
msgid "Method \"{method}\" not allowed."
msgstr "Mètode \"{method}\" no permès."
#: exceptions.py:120
msgid "Could not satisfy the request Accept header."
msgstr "No s'ha pogut satisfer l'Accept header de la petició."
#: exceptions.py:132
#, python-brace-format
msgid "Unsupported media type \"{media_type}\" in request."
msgstr "Media type \"{media_type}\" no suportat."
#: exceptions.py:145
msgid "Request was throttled."
msgstr "La petició ha estat limitada pel número màxim de peticions definit."
#: fields.py:266 relations.py:195 relations.py:228 validators.py:79
#: validators.py:162
msgid "This field is required."
msgstr "Aquest camp és obligatori."
#: fields.py:267
msgid "This field may not be null."
msgstr "Aquest camp no pot ser nul."
#: fields.py:603 fields.py:634
#, python-brace-format
msgid "\"{input}\" is not a valid boolean."
msgstr "\"{input}\" no és un booleà."
#: fields.py:669
msgid "This field may not be blank."
msgstr "Aquest camp no pot estar en blanc."
#: fields.py:670 fields.py:1656
#, python-brace-format
msgid "Ensure this field has no more than {max_length} characters."
msgstr "Aquest camp no pot tenir més de {max_length} caràcters."
#: fields.py:671
#, python-brace-format
msgid "Ensure this field has at least {min_length} characters."
msgstr "Aquest camp ha de tenir un mínim de {min_length} caràcters."
#: fields.py:708
msgid "Enter a valid email address."
msgstr "Introdueixi una adreça de correu vàlida."
#: fields.py:719
msgid "This value does not match the required pattern."
msgstr "Aquest valor no compleix el patró requerit."
#: fields.py:730
msgid ""
"Enter a valid \"slug\" consisting of letters, numbers, underscores or "
"hyphens."
msgstr "Introdueix un \"slug\" vàlid consistent en lletres, números, guions o guions baixos."
#: fields.py:742
msgid "Enter a valid URL."
msgstr "Introdueixi una URL vàlida."
#: fields.py:755
#, python-brace-format
msgid "\"{value}\" is not a valid UUID."
msgstr "\"{value}\" no és un UUID vàlid."
#: fields.py:791
msgid "Enter a valid IPv4 or IPv6 address."
msgstr "Introdueixi una adreça IPv4 o IPv6 vàlida."
#: fields.py:816
msgid "A valid integer is required."
msgstr "Es requereix un nombre enter vàlid."
#: fields.py:817 fields.py:852 fields.py:885
#, python-brace-format
msgid "Ensure this value is less than or equal to {max_value}."
msgstr "Aquest valor ha de ser menor o igual a {max_value}."
#: fields.py:818 fields.py:853 fields.py:886
#, python-brace-format
msgid "Ensure this value is greater than or equal to {min_value}."
msgstr "Aquest valor ha de ser més gran o igual a {min_value}."
#: fields.py:819 fields.py:854 fields.py:890
msgid "String value too large."
msgstr "Valor del text massa gran."
#: fields.py:851 fields.py:884
msgid "A valid number is required."
msgstr "Es requereix un nombre vàlid."
#: fields.py:887
#, python-brace-format
msgid "Ensure that there are no more than {max_digits} digits in total."
msgstr "No pot haver-hi més de {max_digits} dígits en total."
#: fields.py:888
#, python-brace-format
msgid ""
"Ensure that there are no more than {max_decimal_places} decimal places."
msgstr "No pot haver-hi més de {max_decimal_places} decimals."
#: fields.py:889
#, python-brace-format
msgid ""
"Ensure that there are no more than {max_whole_digits} digits before the "
"decimal point."
msgstr "No pot haver-hi més de {max_whole_digits} dígits abans del punt decimal."
#: fields.py:1004
#, python-brace-format
msgid "Datetime has wrong format. Use one of these formats instead: {format}."
msgstr "El Datetime té un format incorrecte. Utilitzi un d'aquests formats: {format}."
#: fields.py:1005
msgid "Expected a datetime but got a date."
msgstr "S'espera un Datetime però s'ha rebut un Date."
#: fields.py:1079
#, python-brace-format
msgid "Date has wrong format. Use one of these formats instead: {format}."
msgstr "El Date té un format incorrecte. Utilitzi un d'aquests formats: {format}."
#: fields.py:1080
msgid "Expected a date but got a datetime."
msgstr "S'espera un Date però s'ha rebut un Datetime."
#: fields.py:1148
#, python-brace-format
msgid "Time has wrong format. Use one of these formats instead: {format}."
msgstr "El Time té un format incorrecte. Utilitzi un d'aquests formats: {format}."
#: fields.py:1207
#, python-brace-format
msgid "Duration has wrong format. Use one of these formats instead: {format}."
msgstr "La durada té un format incorrecte. Utilitzi un d'aquests formats: {format}."
#: fields.py:1232 fields.py:1281
#, python-brace-format
msgid "\"{input}\" is not a valid choice."
msgstr "\"{input}\" no és una opció vàlida."
#: fields.py:1235 relations.py:62 relations.py:431
#, python-brace-format
msgid "More than {count} items..."
msgstr ""
#: fields.py:1282 fields.py:1429 relations.py:427 serializers.py:520
#, python-brace-format
msgid "Expected a list of items but got type \"{input_type}\"."
msgstr "S'espera una llista d'ítems però s'ha rebut el tipus \"{input_type}\"."
#: fields.py:1283
msgid "This selection may not be empty."
msgstr "Aquesta selecció no pot estar buida."
#: fields.py:1320
#, python-brace-format
msgid "\"{input}\" is not a valid path choice."
msgstr "\"{input}\" no és un path vàlid."
#: fields.py:1339
msgid "No file was submitted."
msgstr "No s'ha enviat cap fitxer."
#: fields.py:1340
msgid ""
"The submitted data was not a file. Check the encoding type on the form."
msgstr "Les dades enviades no són un fitxer. Comproveu l'encoding type del formulari."
#: fields.py:1341
msgid "No filename could be determined."
msgstr "No s'ha pogut determinar el nom del fitxer."
#: fields.py:1342
msgid "The submitted file is empty."
msgstr "El fitxer enviat està buit."
#: fields.py:1343
#, python-brace-format
msgid ""
"Ensure this filename has at most {max_length} characters (it has {length})."
msgstr "El nom del fitxer ha de tenir com a màxim {max_length} caràcters (en té {length})."
#: fields.py:1391
msgid ""
"Upload a valid image. The file you uploaded was either not an image or a "
"corrupted image."
msgstr "Envieu una imatge vàlida. El fitxer enviat no és una imatge o és una imatge corrompuda."
#: fields.py:1430 relations.py:428 serializers.py:521
msgid "This list may not be empty."
msgstr "Aquesta llista no pot estar buida."
#: fields.py:1483
#, python-brace-format
msgid "Expected a dictionary of items but got type \"{input_type}\"."
msgstr "S'espera un diccionari però s'ha rebut el tipus \"{input_type}\"."
#: fields.py:1530
msgid "Value must be valid JSON."
msgstr ""
#: filters.py:35 templates/rest_framework/filters/django_filter.html:5
msgid "Submit"
msgstr ""
#: pagination.py:189
#, python-brace-format
msgid "Invalid page \"{page_number}\": {message}."
msgstr "Pàgina invàlida \"{page_number}\": {message}."
#: pagination.py:407
msgid "Invalid cursor"
msgstr "Cursor invàlid."
#: relations.py:196
#, python-brace-format
msgid "Invalid pk \"{pk_value}\" - object does not exist."
msgstr "PK invàlida \"{pk_value}\" - l'objecte no existeix."
#: relations.py:197
#, python-brace-format
msgid "Incorrect type. Expected pk value, received {data_type}."
msgstr "Tipus incorrecte. S'espera el valor d'una PK, s'ha rebut {data_type}."
#: relations.py:229
msgid "Invalid hyperlink - No URL match."
msgstr "Hyperlink invàlid - Cap match d'URL."
#: relations.py:230
msgid "Invalid hyperlink - Incorrect URL match."
msgstr "Hyperlink invàlid - Match d'URL incorrecta."
#: relations.py:231
msgid "Invalid hyperlink - Object does not exist."
msgstr "Hyperlink invàlid - L'objecte no existeix."
#: relations.py:232
#, python-brace-format
msgid "Incorrect type. Expected URL string, received {data_type}."
msgstr "Tipus incorrecte. S'espera una URL, s'ha rebut {data_type}."
#: relations.py:391
#, python-brace-format
msgid "Object with {slug_name}={value} does not exist."
msgstr "L'objecte amb {slug_name}={value} no existeix."
#: relations.py:392
msgid "Invalid value."
msgstr "Valor invàlid."
#: serializers.py:326
#, python-brace-format
msgid "Invalid data. Expected a dictionary, but got {datatype}."
msgstr "Dades invàlides. S'espera un diccionari però s'ha rebut {datatype}."
#: templates/rest_framework/admin.html:118
#: templates/rest_framework/base.html:128
msgid "Filters"
msgstr ""
#: templates/rest_framework/filters/django_filter.html:2
#: templates/rest_framework/filters/django_filter_crispyforms.html:4
msgid "Field filters"
msgstr ""
#: templates/rest_framework/filters/ordering.html:3
msgid "Ordering"
msgstr ""
#: templates/rest_framework/filters/search.html:2
msgid "Search"
msgstr ""
#: templates/rest_framework/horizontal/radio.html:2
#: templates/rest_framework/inline/radio.html:2
#: templates/rest_framework/vertical/radio.html:2
msgid "None"
msgstr "Cap"
#: templates/rest_framework/horizontal/select_multiple.html:2
#: templates/rest_framework/inline/select_multiple.html:2
#: templates/rest_framework/vertical/select_multiple.html:2
msgid "No items to select."
msgstr "Cap opció seleccionada."
#: validators.py:24
msgid "This field must be unique."
msgstr "Aquest camp ha de ser únic."
#: validators.py:78
#, python-brace-format
msgid "The fields {field_names} must make a unique set."
msgstr "Aquests camps {field_names} han de constituir un conjunt únic."
#: validators.py:226
#, python-brace-format
msgid "This field must be unique for the \"{date_field}\" date."
msgstr "Aquest camp ha de ser únic per a la data \"{date_field}\"."
#: validators.py:241
#, python-brace-format
msgid "This field must be unique for the \"{date_field}\" month."
msgstr "Aquest camp ha de ser únic per al mes \"{date_field}\"."
#: validators.py:254
#, python-brace-format
msgid "This field must be unique for the \"{date_field}\" year."
msgstr "Aquest camp ha de ser únic per a l'any \"{date_field}\"."
#: versioning.py:42
msgid "Invalid version in \"Accept\" header."
msgstr "Versió invàlida al header \"Accept\"."
#: versioning.py:73 versioning.py:115
msgid "Invalid version in URL path."
msgstr "Versió invàlida a la URL."
#: versioning.py:144
msgid "Invalid version in hostname."
msgstr "Versió invàlida al hostname."
#: versioning.py:166
msgid "Invalid version in query parameter."
msgstr "Versió invàlida al paràmetre de consulta."
#: views.py:88
msgid "Permission denied."
msgstr "Permís denegat."

Binary file not shown.

View File

@ -0,0 +1,426 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# Translators:
msgid ""
msgstr ""
"Project-Id-Version: Django REST framework\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-12-07 18:53+0100\n"
"PO-Revision-Date: 2015-12-07 17:55+0000\n"
"Last-Translator: Xavier Ordoquy <xordoquy@linovia.com>\n"
"Language-Team: Catalan (Spain) (http://www.transifex.com/django-rest-framework-1/django-rest-framework/language/ca_ES/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: ca_ES\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: authentication.py:72
msgid "Invalid basic header. No credentials provided."
msgstr ""
#: authentication.py:75
msgid "Invalid basic header. Credentials string should not contain spaces."
msgstr ""
#: authentication.py:81
msgid "Invalid basic header. Credentials not correctly base64 encoded."
msgstr ""
#: authentication.py:98
msgid "Invalid username/password."
msgstr ""
#: authentication.py:101 authentication.py:188
msgid "User inactive or deleted."
msgstr ""
#: authentication.py:167
msgid "Invalid token header. No credentials provided."
msgstr ""
#: authentication.py:170
msgid "Invalid token header. Token string should not contain spaces."
msgstr ""
#: authentication.py:176
msgid ""
"Invalid token header. Token string should not contain invalid characters."
msgstr ""
#: authentication.py:185
msgid "Invalid token."
msgstr ""
#: authtoken/serializers.py:20
msgid "User account is disabled."
msgstr ""
#: authtoken/serializers.py:23
msgid "Unable to log in with provided credentials."
msgstr ""
#: authtoken/serializers.py:26
msgid "Must include \"username\" and \"password\"."
msgstr ""
#: exceptions.py:49
msgid "A server error occurred."
msgstr ""
#: exceptions.py:84
msgid "Malformed request."
msgstr ""
#: exceptions.py:89
msgid "Incorrect authentication credentials."
msgstr ""
#: exceptions.py:94
msgid "Authentication credentials were not provided."
msgstr ""
#: exceptions.py:99
msgid "You do not have permission to perform this action."
msgstr ""
#: exceptions.py:104 views.py:81
msgid "Not found."
msgstr ""
#: exceptions.py:109
#, python-brace-format
msgid "Method \"{method}\" not allowed."
msgstr ""
#: exceptions.py:120
msgid "Could not satisfy the request Accept header."
msgstr ""
#: exceptions.py:132
#, python-brace-format
msgid "Unsupported media type \"{media_type}\" in request."
msgstr ""
#: exceptions.py:145
msgid "Request was throttled."
msgstr ""
#: fields.py:266 relations.py:195 relations.py:228 validators.py:79
#: validators.py:162
msgid "This field is required."
msgstr ""
#: fields.py:267
msgid "This field may not be null."
msgstr ""
#: fields.py:603 fields.py:634
#, python-brace-format
msgid "\"{input}\" is not a valid boolean."
msgstr ""
#: fields.py:669
msgid "This field may not be blank."
msgstr ""
#: fields.py:670 fields.py:1656
#, python-brace-format
msgid "Ensure this field has no more than {max_length} characters."
msgstr ""
#: fields.py:671
#, python-brace-format
msgid "Ensure this field has at least {min_length} characters."
msgstr ""
#: fields.py:708
msgid "Enter a valid email address."
msgstr ""
#: fields.py:719
msgid "This value does not match the required pattern."
msgstr ""
#: fields.py:730
msgid ""
"Enter a valid \"slug\" consisting of letters, numbers, underscores or "
"hyphens."
msgstr ""
#: fields.py:742
msgid "Enter a valid URL."
msgstr ""
#: fields.py:755
#, python-brace-format
msgid "\"{value}\" is not a valid UUID."
msgstr ""
#: fields.py:791
msgid "Enter a valid IPv4 or IPv6 address."
msgstr ""
#: fields.py:816
msgid "A valid integer is required."
msgstr ""
#: fields.py:817 fields.py:852 fields.py:885
#, python-brace-format
msgid "Ensure this value is less than or equal to {max_value}."
msgstr ""
#: fields.py:818 fields.py:853 fields.py:886
#, python-brace-format
msgid "Ensure this value is greater than or equal to {min_value}."
msgstr ""
#: fields.py:819 fields.py:854 fields.py:890
msgid "String value too large."
msgstr ""
#: fields.py:851 fields.py:884
msgid "A valid number is required."
msgstr ""
#: fields.py:887
#, python-brace-format
msgid "Ensure that there are no more than {max_digits} digits in total."
msgstr ""
#: fields.py:888
#, python-brace-format
msgid ""
"Ensure that there are no more than {max_decimal_places} decimal places."
msgstr ""
#: fields.py:889
#, python-brace-format
msgid ""
"Ensure that there are no more than {max_whole_digits} digits before the "
"decimal point."
msgstr ""
#: fields.py:1004
#, python-brace-format
msgid "Datetime has wrong format. Use one of these formats instead: {format}."
msgstr ""
#: fields.py:1005
msgid "Expected a datetime but got a date."
msgstr ""
#: fields.py:1079
#, python-brace-format
msgid "Date has wrong format. Use one of these formats instead: {format}."
msgstr ""
#: fields.py:1080
msgid "Expected a date but got a datetime."
msgstr ""
#: fields.py:1148
#, python-brace-format
msgid "Time has wrong format. Use one of these formats instead: {format}."
msgstr ""
#: fields.py:1207
#, python-brace-format
msgid "Duration has wrong format. Use one of these formats instead: {format}."
msgstr ""
#: fields.py:1232 fields.py:1281
#, python-brace-format
msgid "\"{input}\" is not a valid choice."
msgstr ""
#: fields.py:1235 relations.py:62 relations.py:431
#, python-brace-format
msgid "More than {count} items..."
msgstr ""
#: fields.py:1282 fields.py:1429 relations.py:427 serializers.py:520
#, python-brace-format
msgid "Expected a list of items but got type \"{input_type}\"."
msgstr ""
#: fields.py:1283
msgid "This selection may not be empty."
msgstr ""
#: fields.py:1320
#, python-brace-format
msgid "\"{input}\" is not a valid path choice."
msgstr ""
#: fields.py:1339
msgid "No file was submitted."
msgstr ""
#: fields.py:1340
msgid ""
"The submitted data was not a file. Check the encoding type on the form."
msgstr ""
#: fields.py:1341
msgid "No filename could be determined."
msgstr ""
#: fields.py:1342
msgid "The submitted file is empty."
msgstr ""
#: fields.py:1343
#, python-brace-format
msgid ""
"Ensure this filename has at most {max_length} characters (it has {length})."
msgstr ""
#: fields.py:1391
msgid ""
"Upload a valid image. The file you uploaded was either not an image or a "
"corrupted image."
msgstr ""
#: fields.py:1430 relations.py:428 serializers.py:521
msgid "This list may not be empty."
msgstr ""
#: fields.py:1483
#, python-brace-format
msgid "Expected a dictionary of items but got type \"{input_type}\"."
msgstr ""
#: fields.py:1530
msgid "Value must be valid JSON."
msgstr ""
#: filters.py:35 templates/rest_framework/filters/django_filter.html:5
msgid "Submit"
msgstr ""
#: pagination.py:189
#, python-brace-format
msgid "Invalid page \"{page_number}\": {message}."
msgstr ""
#: pagination.py:407
msgid "Invalid cursor"
msgstr ""
#: relations.py:196
#, python-brace-format
msgid "Invalid pk \"{pk_value}\" - object does not exist."
msgstr ""
#: relations.py:197
#, python-brace-format
msgid "Incorrect type. Expected pk value, received {data_type}."
msgstr ""
#: relations.py:229
msgid "Invalid hyperlink - No URL match."
msgstr ""
#: relations.py:230
msgid "Invalid hyperlink - Incorrect URL match."
msgstr ""
#: relations.py:231
msgid "Invalid hyperlink - Object does not exist."
msgstr ""
#: relations.py:232
#, python-brace-format
msgid "Incorrect type. Expected URL string, received {data_type}."
msgstr ""
#: relations.py:391
#, python-brace-format
msgid "Object with {slug_name}={value} does not exist."
msgstr ""
#: relations.py:392
msgid "Invalid value."
msgstr ""
#: serializers.py:326
#, python-brace-format
msgid "Invalid data. Expected a dictionary, but got {datatype}."
msgstr ""
#: templates/rest_framework/admin.html:118
#: templates/rest_framework/base.html:128
msgid "Filters"
msgstr ""
#: templates/rest_framework/filters/django_filter.html:2
#: templates/rest_framework/filters/django_filter_crispyforms.html:4
msgid "Field filters"
msgstr ""
#: templates/rest_framework/filters/ordering.html:3
msgid "Ordering"
msgstr ""
#: templates/rest_framework/filters/search.html:2
msgid "Search"
msgstr ""
#: templates/rest_framework/horizontal/radio.html:2
#: templates/rest_framework/inline/radio.html:2
#: templates/rest_framework/vertical/radio.html:2
msgid "None"
msgstr ""
#: templates/rest_framework/horizontal/select_multiple.html:2
#: templates/rest_framework/inline/select_multiple.html:2
#: templates/rest_framework/vertical/select_multiple.html:2
msgid "No items to select."
msgstr ""
#: validators.py:24
msgid "This field must be unique."
msgstr ""
#: validators.py:78
#, python-brace-format
msgid "The fields {field_names} must make a unique set."
msgstr ""
#: validators.py:226
#, python-brace-format
msgid "This field must be unique for the \"{date_field}\" date."
msgstr ""
#: validators.py:241
#, python-brace-format
msgid "This field must be unique for the \"{date_field}\" month."
msgstr ""
#: validators.py:254
#, python-brace-format
msgid "This field must be unique for the \"{date_field}\" year."
msgstr ""
#: versioning.py:42
msgid "Invalid version in \"Accept\" header."
msgstr ""
#: versioning.py:73 versioning.py:115
msgid "Invalid version in URL path."
msgstr ""
#: versioning.py:144
msgid "Invalid version in hostname."
msgstr ""
#: versioning.py:166
msgid "Invalid version in query parameter."
msgstr ""
#: views.py:88
msgid "Permission denied."
msgstr ""

View File

@ -9,33 +9,33 @@ msgid ""
msgstr ""
"Project-Id-Version: Django REST framework\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-06-03 17:30+0100\n"
"PO-Revision-Date: 2015-06-03 16:30+0000\n"
"POT-Creation-Date: 2015-12-07 18:53+0100\n"
"PO-Revision-Date: 2015-12-07 17:55+0000\n"
"Last-Translator: Xavier Ordoquy <xordoquy@linovia.com>\n"
"Language-Team: Czech (http://www.transifex.com/projects/p/django-rest-framework/language/cs/)\n"
"Language-Team: Czech (http://www.transifex.com/django-rest-framework-1/django-rest-framework/language/cs/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: cs\n"
"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"
#: authentication.py:70
#: authentication.py:72
msgid "Invalid basic header. No credentials provided."
msgstr "Chybná hlavička. Nebyly poskytnuty přihlašovací údaje."
#: authentication.py:73
#: authentication.py:75
msgid "Invalid basic header. Credentials string should not contain spaces."
msgstr "Chybná hlavička. Přihlašovací údaje by neměly obsahovat mezery."
#: authentication.py:79
#: authentication.py:81
msgid "Invalid basic header. Credentials not correctly base64 encoded."
msgstr "Chybná hlavička. Přihlašovací údaje nebyly správně zakódovány pomocí base64."
#: authentication.py:97
#: authentication.py:98
msgid "Invalid username/password."
msgstr "Chybné uživatelské jméno nebo heslo."
#: authentication.py:100 authentication.py:182
#: authentication.py:101 authentication.py:188
msgid "User inactive or deleted."
msgstr "Uživatelský účet je neaktivní nebo byl smazán."
@ -47,7 +47,12 @@ msgstr "Chybná hlavička tokenu. Nebyly zadány přihlašovací údaje."
msgid "Invalid token header. Token string should not contain spaces."
msgstr "Chybná hlavička tokenu. Přihlašovací údaje by neměly obsahovat mezery."
#: authentication.py:179
#: authentication.py:176
msgid ""
"Invalid token header. Token string should not contain invalid characters."
msgstr ""
#: authentication.py:185
msgid "Invalid token."
msgstr "Chybný token."
@ -63,261 +68,309 @@ msgstr "Zadanými údaji se nebylo možné přihlásit."
msgid "Must include \"username\" and \"password\"."
msgstr "Musí obsahovat \"uživatelské jméno\" a \"heslo\"."
#: exceptions.py:38
#: exceptions.py:49
msgid "A server error occurred."
msgstr "Chyba na straně serveru."
#: exceptions.py:73
#: exceptions.py:84
msgid "Malformed request."
msgstr "Neplatný formát požadavku."
#: exceptions.py:78
#: exceptions.py:89
msgid "Incorrect authentication credentials."
msgstr "Chybné přihlašovací údaje."
#: exceptions.py:83
#: exceptions.py:94
msgid "Authentication credentials were not provided."
msgstr "Nebyly zadány přihlašovací údaje."
#: exceptions.py:88
#: exceptions.py:99
msgid "You do not have permission to perform this action."
msgstr "K této akci nemáte oprávnění."
#: exceptions.py:93 views.py:78
#: exceptions.py:104 views.py:81
msgid "Not found."
msgstr "Nenalezeno."
#: exceptions.py:98
#: exceptions.py:109
#, python-brace-format
msgid "Method \"{method}\" not allowed."
msgstr "Metoda \"{method}\" není povolena."
#: exceptions.py:109
#: exceptions.py:120
msgid "Could not satisfy the request Accept header."
msgstr "Nelze vyhovět požadavku v hlavičce Accept."
#: exceptions.py:121
#: exceptions.py:132
#, python-brace-format
msgid "Unsupported media type \"{media_type}\" in request."
msgstr "Nepodporovaný media type \"{media_type}\" v požadavku."
#: exceptions.py:134
#: exceptions.py:145
msgid "Request was throttled."
msgstr "Požadavek byl limitován kvůli omezení počtu požadavků za časovou periodu."
#: fields.py:162 relations.py:132 relations.py:156 validators.py:77
#: validators.py:160
#: fields.py:266 relations.py:195 relations.py:228 validators.py:79
#: validators.py:162
msgid "This field is required."
msgstr "Toto pole je vyžadováno."
#: fields.py:163
#: fields.py:267
msgid "This field may not be null."
msgstr "Toto pole nesmí být prázdné (null)."
#: fields.py:496 fields.py:524
#: fields.py:603 fields.py:634
#, python-brace-format
msgid "\"{input}\" is not a valid boolean."
msgstr "\"{input}\" nelze použít jako typ boolean."
#: fields.py:559
#: fields.py:669
msgid "This field may not be blank."
msgstr "Toto pole nesmí být prázdné."
#: fields.py:560 fields.py:1386
#: fields.py:670 fields.py:1656
#, python-brace-format
msgid "Ensure this field has no more than {max_length} characters."
msgstr "Zkontrolujte, že toto pole není delší než {max_length} znaků."
#: fields.py:561
#: fields.py:671
#, python-brace-format
msgid "Ensure this field has at least {min_length} characters."
msgstr "Zkontrolujte, že toto pole obsahuje alespoň {min_length} znaků."
#: fields.py:598
#: fields.py:708
msgid "Enter a valid email address."
msgstr "Vložte platnou e-mailovou adresu."
#: fields.py:609
#: fields.py:719
msgid "This value does not match the required pattern."
msgstr "Hodnota v tomto poli neodpovídá požadovanému formátu."
#: fields.py:620
#: fields.py:730
msgid ""
"Enter a valid \"slug\" consisting of letters, numbers, underscores or "
"hyphens."
msgstr "Vložte platnou \"zkrácenou formu\" obsahující pouze malá písmena, čísla, spojovník nebo podtržítko."
#: fields.py:632
#: fields.py:742
msgid "Enter a valid URL."
msgstr "Vložte platný odkaz."
#: fields.py:645
#: fields.py:755
#, python-brace-format
msgid "\"{value}\" is not a valid UUID."
msgstr "\"{value}\" není platné UUID."
#: fields.py:679
#: fields.py:791
msgid "Enter a valid IPv4 or IPv6 address."
msgstr ""
#: fields.py:816
msgid "A valid integer is required."
msgstr "Je vyžadováno celé číslo."
#: fields.py:680 fields.py:715 fields.py:748
#: fields.py:817 fields.py:852 fields.py:885
#, python-brace-format
msgid "Ensure this value is less than or equal to {max_value}."
msgstr "Zkontrolujte, že hodnota je menší nebo rovna {max_value}."
#: fields.py:681 fields.py:716 fields.py:749
#: fields.py:818 fields.py:853 fields.py:886
#, python-brace-format
msgid "Ensure this value is greater than or equal to {min_value}."
msgstr "Zkontrolujte, že hodnota je větší nebo rovna {min_value}."
#: fields.py:682 fields.py:717 fields.py:753
#: fields.py:819 fields.py:854 fields.py:890
msgid "String value too large."
msgstr "Řetězec je příliš dlouhý."
#: fields.py:714 fields.py:747
#: fields.py:851 fields.py:884
msgid "A valid number is required."
msgstr "Je vyžadováno číslo."
#: fields.py:750
#: fields.py:887
#, python-brace-format
msgid "Ensure that there are no more than {max_digits} digits in total."
msgstr "Zkontrolujte, že číslo neobsahuje více než {max_digits} čislic."
#: fields.py:751
#: fields.py:888
#, python-brace-format
msgid ""
"Ensure that there are no more than {max_decimal_places} decimal places."
msgstr "Zkontrolujte, že číslo nemá více než {max_decimal_places} desetinných míst."
#: fields.py:752
#: fields.py:889
#, python-brace-format
msgid ""
"Ensure that there are no more than {max_whole_digits} digits before the "
"decimal point."
msgstr "Zkontrolujte, že číslo neobsahuje více než {max_whole_digits} čislic před desetinnou čárkou."
#: fields.py:842
#: fields.py:1004
#, python-brace-format
msgid "Datetime has wrong format. Use one of these formats instead: {format}."
msgstr "Chybný formát data a času. Použijte jeden z těchto formátů: {format}."
#: fields.py:843
#: fields.py:1005
msgid "Expected a datetime but got a date."
msgstr "Bylo zadáno pouze datum bez času."
#: fields.py:907
#: fields.py:1079
#, python-brace-format
msgid "Date has wrong format. Use one of these formats instead: {format}."
msgstr "Chybný formát data. Použijte jeden z těchto formátů: {format}."
#: fields.py:908
#: fields.py:1080
msgid "Expected a date but got a datetime."
msgstr "Bylo zadáno datum a čas, místo samotného data."
#: fields.py:971
#: fields.py:1148
#, python-brace-format
msgid "Time has wrong format. Use one of these formats instead: {format}."
msgstr "Chybný formát času. Použijte jeden z těchto formátů: {format}."
#: fields.py:1025
#: fields.py:1207
#, python-brace-format
msgid "Duration has wrong format. Use one of these formats instead: {format}."
msgstr ""
#: fields.py:1050 fields.py:1094
#: fields.py:1232 fields.py:1281
#, python-brace-format
msgid "\"{input}\" is not a valid choice."
msgstr "\"{input}\" není platnou možností."
#: fields.py:1095 fields.py:1213 serializers.py:487
#: fields.py:1235 relations.py:62 relations.py:431
#, python-brace-format
msgid "More than {count} items..."
msgstr ""
#: fields.py:1282 fields.py:1429 relations.py:427 serializers.py:520
#, python-brace-format
msgid "Expected a list of items but got type \"{input_type}\"."
msgstr "Byl očekáván seznam položek ale nalezen \"{input_type}\"."
#: fields.py:1129
#: fields.py:1283
msgid "This selection may not be empty."
msgstr ""
#: fields.py:1320
#, python-brace-format
msgid "\"{input}\" is not a valid path choice."
msgstr ""
#: fields.py:1339
msgid "No file was submitted."
msgstr "Nebyl zaslán žádný soubor."
#: fields.py:1130
#: fields.py:1340
msgid ""
"The submitted data was not a file. Check the encoding type on the form."
msgstr "Zaslaná data neobsahují soubor. Zkontrolujte typ kódování ve formuláři."
#: fields.py:1131
#: fields.py:1341
msgid "No filename could be determined."
msgstr "Nebylo možné zjistit jméno souboru."
#: fields.py:1132
#: fields.py:1342
msgid "The submitted file is empty."
msgstr "Zaslaný soubor je prázdný."
#: fields.py:1133
#: fields.py:1343
#, python-brace-format
msgid ""
"Ensure this filename has at most {max_length} characters (it has {length})."
msgstr "Zajistěte, aby jméno souboru obsahovalo maximálně {max_length} znaků (teď má {length} znaků)."
#: fields.py:1175
#: fields.py:1391
msgid ""
"Upload a valid image. The file you uploaded was either not an image or a "
"corrupted image."
msgstr "Nahrajte platný obrázek. Nahraný soubor buď není obrázkem nebo je poškozen."
#: fields.py:1250
#: fields.py:1430 relations.py:428 serializers.py:521
msgid "This list may not be empty."
msgstr ""
#: fields.py:1483
#, python-brace-format
msgid "Expected a dictionary of items but got type \"{input_type}\"."
msgstr "Byl očekáván slovník položek ale nalezen \"{input_type}\"."
#: pagination.py:231
#: fields.py:1530
msgid "Value must be valid JSON."
msgstr ""
#: filters.py:35 templates/rest_framework/filters/django_filter.html:5
msgid "Submit"
msgstr ""
#: pagination.py:189
#, python-brace-format
msgid "Invalid page \"{page_number}\": {message}."
msgstr "Chybné čislo stránky \"{page_number}\": {message}."
#: pagination.py:492
#: pagination.py:407
msgid "Invalid cursor"
msgstr "Chybný kurzor."
#: relations.py:133
#: relations.py:196
#, python-brace-format
msgid "Invalid pk \"{pk_value}\" - object does not exist."
msgstr "Chybný primární klíč \"{pk_value}\" - objekt neexistuje."
#: relations.py:134
#: relations.py:197
#, python-brace-format
msgid "Incorrect type. Expected pk value, received {data_type}."
msgstr "Chybný typ. Byl přijat typ {data_type} místo hodnoty primárního klíče."
#: relations.py:157
#: relations.py:229
msgid "Invalid hyperlink - No URL match."
msgstr "Chybný odkaz - nebyla nalezena žádní shoda."
#: relations.py:158
#: relations.py:230
msgid "Invalid hyperlink - Incorrect URL match."
msgstr "Chybný odkaz - byla nalezena neplatná shoda."
#: relations.py:159
#: relations.py:231
msgid "Invalid hyperlink - Object does not exist."
msgstr "Chybný odkaz - objekt neexistuje."
#: relations.py:160
#: relations.py:232
#, python-brace-format
msgid "Incorrect type. Expected URL string, received {data_type}."
msgstr "Chybný typ. Byl přijat typ {data_type} místo očekávaného odkazu."
#: relations.py:302
#: relations.py:391
#, python-brace-format
msgid "Object with {slug_name}={value} does not exist."
msgstr "Objekt s {slug_name}={value} neexistuje."
#: relations.py:303
#: relations.py:392
msgid "Invalid value."
msgstr "Chybná hodnota."
#: serializers.py:304
#: serializers.py:326
#, python-brace-format
msgid "Invalid data. Expected a dictionary, but got {datatype}."
msgstr "Chybná data. Byl přijat typ {datatype} místo očekávaného slovníku."
#: templates/rest_framework/admin.html:118
#: templates/rest_framework/base.html:128
msgid "Filters"
msgstr ""
#: templates/rest_framework/filters/django_filter.html:2
#: templates/rest_framework/filters/django_filter_crispyforms.html:4
msgid "Field filters"
msgstr ""
#: templates/rest_framework/filters/ordering.html:3
msgid "Ordering"
msgstr ""
#: templates/rest_framework/filters/search.html:2
msgid "Search"
msgstr ""
#: templates/rest_framework/horizontal/radio.html:2
#: templates/rest_framework/inline/radio.html:2
#: templates/rest_framework/vertical/radio.html:2
@ -330,46 +383,46 @@ msgstr ""
msgid "No items to select."
msgstr ""
#: validators.py:22
#: validators.py:24
msgid "This field must be unique."
msgstr "Tato položka musí být unikátní."
#: validators.py:76
#: validators.py:78
#, python-brace-format
msgid "The fields {field_names} must make a unique set."
msgstr "Položka {field_names} musí tvořit unikátní množinu."
#: validators.py:224
#: validators.py:226
#, python-brace-format
msgid "This field must be unique for the \"{date_field}\" date."
msgstr "Tato položka musí být pro datum \"{date_field}\" unikátní."
#: validators.py:239
#: validators.py:241
#, python-brace-format
msgid "This field must be unique for the \"{date_field}\" month."
msgstr "Tato položka musí být pro měsíc \"{date_field}\" unikátní."
#: validators.py:252
#: validators.py:254
#, python-brace-format
msgid "This field must be unique for the \"{date_field}\" year."
msgstr "Tato položka musí být pro rok \"{date_field}\" unikátní."
#: versioning.py:39
#: versioning.py:42
msgid "Invalid version in \"Accept\" header."
msgstr "Chybné číslo verze v hlavičce Accept."
#: versioning.py:70 versioning.py:112
#: versioning.py:73 versioning.py:115
msgid "Invalid version in URL path."
msgstr "Chybné číslo verze v odkazu."
#: versioning.py:141
#: versioning.py:144
msgid "Invalid version in hostname."
msgstr "Chybné číslo verze v hostname."
#: versioning.py:163
#: versioning.py:166
msgid "Invalid version in query parameter."
msgstr "Chybné čislo verze v URL parametru."
#: views.py:85
#: views.py:88
msgid "Permission denied."
msgstr ""

View File

@ -3,38 +3,39 @@
# This file is distributed under the same license as the PACKAGE package.
#
# Translators:
# Mads Jensen <mje@inducks.org>, 2015
# Mikkel Munch Mortensen <3xm@detfalskested.dk>, 2015
msgid ""
msgstr ""
"Project-Id-Version: Django REST framework\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-06-03 17:30+0100\n"
"PO-Revision-Date: 2015-06-03 16:30+0000\n"
"POT-Creation-Date: 2015-12-07 18:53+0100\n"
"PO-Revision-Date: 2015-12-07 17:55+0000\n"
"Last-Translator: Xavier Ordoquy <xordoquy@linovia.com>\n"
"Language-Team: Danish (http://www.transifex.com/projects/p/django-rest-framework/language/da/)\n"
"Language-Team: Danish (http://www.transifex.com/django-rest-framework-1/django-rest-framework/language/da/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: da\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: authentication.py:70
#: authentication.py:72
msgid "Invalid basic header. No credentials provided."
msgstr "Ugyldig basic header. Ingen legitimation angivet."
#: authentication.py:73
#: authentication.py:75
msgid "Invalid basic header. Credentials string should not contain spaces."
msgstr "Ugyldig basic header. Legitimationsstrenge må ikke indeholde mellemrum."
#: authentication.py:79
#: authentication.py:81
msgid "Invalid basic header. Credentials not correctly base64 encoded."
msgstr "Ugyldig basic header. Legitimationen er ikke base64 encoded på korrekt vis."
#: authentication.py:97
#: authentication.py:98
msgid "Invalid username/password."
msgstr "Ugyldigt brugernavn/kodeord."
#: authentication.py:100 authentication.py:182
#: authentication.py:101 authentication.py:188
msgid "User inactive or deleted."
msgstr "Inaktiv eller slettet bruger."
@ -46,7 +47,12 @@ msgstr "Ugyldig token header."
msgid "Invalid token header. Token string should not contain spaces."
msgstr "Ugyldig token header. Token-strenge må ikke indeholde mellemrum."
#: authentication.py:179
#: authentication.py:176
msgid ""
"Invalid token header. Token string should not contain invalid characters."
msgstr "Ugyldig token header. Token streng bør ikke indeholde ugyldige karakterer."
#: authentication.py:185
msgid "Invalid token."
msgstr "Ugyldigt token."
@ -62,261 +68,309 @@ msgstr "Kunne ikke logge ind med den angivne legitimation."
msgid "Must include \"username\" and \"password\"."
msgstr "Skal indeholde \"username\" og \"password\"."
#: exceptions.py:38
#: exceptions.py:49
msgid "A server error occurred."
msgstr "Der er sket en serverfejl."
#: exceptions.py:73
#: exceptions.py:84
msgid "Malformed request."
msgstr "Misdannet forespørgsel."
#: exceptions.py:78
#: exceptions.py:89
msgid "Incorrect authentication credentials."
msgstr "Ugyldig legitimation til autentificering."
#: exceptions.py:83
#: exceptions.py:94
msgid "Authentication credentials were not provided."
msgstr "Legitimation til autentificering blev ikke angivet."
#: exceptions.py:88
#: exceptions.py:99
msgid "You do not have permission to perform this action."
msgstr "Du har ikke lov til at udføre denne handling."
#: exceptions.py:93 views.py:78
#: exceptions.py:104 views.py:81
msgid "Not found."
msgstr "Ikke fundet."
#: exceptions.py:98
#: exceptions.py:109
#, python-brace-format
msgid "Method \"{method}\" not allowed."
msgstr "Metoden \"{method}\" er ikke tilladt."
#: exceptions.py:109
#: exceptions.py:120
msgid "Could not satisfy the request Accept header."
msgstr "Kunne ikke efterkomme forespørgslens Accept header."
#: exceptions.py:121
#: exceptions.py:132
#, python-brace-format
msgid "Unsupported media type \"{media_type}\" in request."
msgstr "Forespørgslens media type, \"{media_type}\", er ikke understøttet."
#: exceptions.py:134
#: exceptions.py:145
msgid "Request was throttled."
msgstr "Forespørgslen blev neddroslet."
#: fields.py:162 relations.py:132 relations.py:156 validators.py:77
#: validators.py:160
#: fields.py:266 relations.py:195 relations.py:228 validators.py:79
#: validators.py:162
msgid "This field is required."
msgstr "Dette felt er påkrævet."
#: fields.py:163
#: fields.py:267
msgid "This field may not be null."
msgstr "Dette felt må ikke være null."
#: fields.py:496 fields.py:524
#: fields.py:603 fields.py:634
#, python-brace-format
msgid "\"{input}\" is not a valid boolean."
msgstr "\"{input}\" er ikke en tilladt boolsk værdi."
#: fields.py:559
#: fields.py:669
msgid "This field may not be blank."
msgstr "Dette felt må ikke være tomt."
#: fields.py:560 fields.py:1386
#: fields.py:670 fields.py:1656
#, python-brace-format
msgid "Ensure this field has no more than {max_length} characters."
msgstr "Tjek at dette felt ikke indeholder flere end {max_length} tegn."
#: fields.py:561
#: fields.py:671
#, python-brace-format
msgid "Ensure this field has at least {min_length} characters."
msgstr "Tjek at dette felt indeholder mindst {min_length} tegn."
#: fields.py:598
#: fields.py:708
msgid "Enter a valid email address."
msgstr "Angiv en gyldig e-mailadresse."
#: fields.py:609
#: fields.py:719
msgid "This value does not match the required pattern."
msgstr "Denne værdi passer ikke med det påkrævede mønster."
#: fields.py:620
#: fields.py:730
msgid ""
"Enter a valid \"slug\" consisting of letters, numbers, underscores or "
"hyphens."
msgstr "Indtast en gyldig \"slug\", bestående af bogstaver, tal, bund- og bindestreger."
#: fields.py:632
#: fields.py:742
msgid "Enter a valid URL."
msgstr "Indtast en gyldig URL."
#: fields.py:645
#: fields.py:755
#, python-brace-format
msgid "\"{value}\" is not a valid UUID."
msgstr "\"{value}\" er ikke et gyldigt UUID."
#: fields.py:679
#: fields.py:791
msgid "Enter a valid IPv4 or IPv6 address."
msgstr "Indtast en gyldig IPv4 eller IPv6 adresse."
#: fields.py:816
msgid "A valid integer is required."
msgstr "Et gyldigt heltal er påkrævet."
#: fields.py:680 fields.py:715 fields.py:748
#: fields.py:817 fields.py:852 fields.py:885
#, python-brace-format
msgid "Ensure this value is less than or equal to {max_value}."
msgstr "Tjek at værdien er mindre end eller lig med {max_value}."
#: fields.py:681 fields.py:716 fields.py:749
#: fields.py:818 fields.py:853 fields.py:886
#, python-brace-format
msgid "Ensure this value is greater than or equal to {min_value}."
msgstr "Tjek at værdien er større end eller lig med {min_value}."
#: fields.py:682 fields.py:717 fields.py:753
#: fields.py:819 fields.py:854 fields.py:890
msgid "String value too large."
msgstr "Strengværdien er for stor."
#: fields.py:714 fields.py:747
#: fields.py:851 fields.py:884
msgid "A valid number is required."
msgstr "Et gyldigt tal er påkrævet."
#: fields.py:750
#: fields.py:887
#, python-brace-format
msgid "Ensure that there are no more than {max_digits} digits in total."
msgstr "Tjek at der ikke er flere end {max_digits} cifre i alt."
#: fields.py:751
#: fields.py:888
#, python-brace-format
msgid ""
"Ensure that there are no more than {max_decimal_places} decimal places."
msgstr "Tjek at der ikke er flere end {max_decimal_places} cifre efter kommaet."
#: fields.py:752
#: fields.py:889
#, python-brace-format
msgid ""
"Ensure that there are no more than {max_whole_digits} digits before the "
"decimal point."
msgstr "Tjek at der ikke er flere end {max_whole_digits} cifre før kommaet."
#: fields.py:842
#: fields.py:1004
#, python-brace-format
msgid "Datetime has wrong format. Use one of these formats instead: {format}."
msgstr "Datotid har et forkert format. Brug i stedet et af disse formater: {format}."
#: fields.py:843
#: fields.py:1005
msgid "Expected a datetime but got a date."
msgstr "Forventede en datotid, men fik en dato."
#: fields.py:907
#: fields.py:1079
#, python-brace-format
msgid "Date has wrong format. Use one of these formats instead: {format}."
msgstr "Dato har et forkert format. Brug i stedet et af disse formater: {format}."
#: fields.py:908
#: fields.py:1080
msgid "Expected a date but got a datetime."
msgstr "Forventede en dato men fik en datotid."
#: fields.py:971
#: fields.py:1148
#, python-brace-format
msgid "Time has wrong format. Use one of these formats instead: {format}."
msgstr "Klokkeslæt har forkert format. Brug i stedet et af disse formater: {format}. "
#: fields.py:1025
#: fields.py:1207
#, python-brace-format
msgid "Duration has wrong format. Use one of these formats instead: {format}."
msgstr ""
msgstr "Varighed har forkert format. Brug istedet et af følgende formater: {format}."
#: fields.py:1050 fields.py:1094
#: fields.py:1232 fields.py:1281
#, python-brace-format
msgid "\"{input}\" is not a valid choice."
msgstr "\"{input}\" er ikke et gyldigt valg."
#: fields.py:1095 fields.py:1213 serializers.py:487
#: fields.py:1235 relations.py:62 relations.py:431
#, python-brace-format
msgid "More than {count} items..."
msgstr "Flere end {count} objekter..."
#: fields.py:1282 fields.py:1429 relations.py:427 serializers.py:520
#, python-brace-format
msgid "Expected a list of items but got type \"{input_type}\"."
msgstr "Forventede en liste, men fik noget af typen \"{input_type}\"."
#: fields.py:1129
#: fields.py:1283
msgid "This selection may not be empty."
msgstr "Dette valg kan være tomt."
#: fields.py:1320
#, python-brace-format
msgid "\"{input}\" is not a valid path choice."
msgstr "\"{input}\" er ikke et gyldigt valg af adresse."
#: fields.py:1339
msgid "No file was submitted."
msgstr "Ingen medsendt fil."
#: fields.py:1130
#: fields.py:1340
msgid ""
"The submitted data was not a file. Check the encoding type on the form."
msgstr "Det medsendte data var ikke en fil. Tjek typen af indkodning på formularen."
#: fields.py:1131
#: fields.py:1341
msgid "No filename could be determined."
msgstr "Filnavnet kunne ikke afgøres."
#: fields.py:1132
#: fields.py:1342
msgid "The submitted file is empty."
msgstr "Den medsendte fil er tom."
#: fields.py:1133
#: fields.py:1343
#, python-brace-format
msgid ""
"Ensure this filename has at most {max_length} characters (it has {length})."
msgstr "Sørg for at filnavnet er højst {max_length} langt (det er {length})."
#: fields.py:1175
#: fields.py:1391
msgid ""
"Upload a valid image. The file you uploaded was either not an image or a "
"corrupted image."
msgstr "Medsend et gyldigt billede. Den medsendte fil var enten ikke et billede eller billedfilen var ødelagt."
#: fields.py:1250
#: fields.py:1430 relations.py:428 serializers.py:521
msgid "This list may not be empty."
msgstr "Denne liste er muligvis ikke tom."
#: fields.py:1483
#, python-brace-format
msgid "Expected a dictionary of items but got type \"{input_type}\"."
msgstr "Forventede en dictionary, men fik noget af typen \"{input_type}\"."
#: pagination.py:231
#: fields.py:1530
msgid "Value must be valid JSON."
msgstr ""
#: filters.py:35 templates/rest_framework/filters/django_filter.html:5
msgid "Submit"
msgstr ""
#: pagination.py:189
#, python-brace-format
msgid "Invalid page \"{page_number}\": {message}."
msgstr "Ugyldig side \"{page_number}\": {message}."
#: pagination.py:492
#: pagination.py:407
msgid "Invalid cursor"
msgstr "Ugyldig cursor"
#: relations.py:133
#: relations.py:196
#, python-brace-format
msgid "Invalid pk \"{pk_value}\" - object does not exist."
msgstr "Ugyldig primærnøgle \"{pk_value}\" - objektet findes ikke."
#: relations.py:134
#: relations.py:197
#, python-brace-format
msgid "Incorrect type. Expected pk value, received {data_type}."
msgstr "Ugyldig type. Forventet værdi er primærnøgle, fik {data_type}."
#: relations.py:157
#: relations.py:229
msgid "Invalid hyperlink - No URL match."
msgstr "Ugyldigt hyperlink - intet URL match."
#: relations.py:158
#: relations.py:230
msgid "Invalid hyperlink - Incorrect URL match."
msgstr "Ugyldigt hyperlink - forkert URL match."
#: relations.py:159
#: relations.py:231
msgid "Invalid hyperlink - Object does not exist."
msgstr "Ugyldigt hyperlink - objektet findes ikke."
#: relations.py:160
#: relations.py:232
#, python-brace-format
msgid "Incorrect type. Expected URL string, received {data_type}."
msgstr "Forkert type. Forventede en URL-streng, fik {data_type}."
#: relations.py:302
#: relations.py:391
#, python-brace-format
msgid "Object with {slug_name}={value} does not exist."
msgstr "Object med {slug_name}={value} findes ikke."
#: relations.py:303
#: relations.py:392
msgid "Invalid value."
msgstr "Ugyldig værdi."
#: serializers.py:304
#: serializers.py:326
#, python-brace-format
msgid "Invalid data. Expected a dictionary, but got {datatype}."
msgstr "Ugyldig data. Forventede en dictionary, men fik {datatype}."
#: templates/rest_framework/admin.html:118
#: templates/rest_framework/base.html:128
msgid "Filters"
msgstr ""
#: templates/rest_framework/filters/django_filter.html:2
#: templates/rest_framework/filters/django_filter_crispyforms.html:4
msgid "Field filters"
msgstr ""
#: templates/rest_framework/filters/ordering.html:3
msgid "Ordering"
msgstr ""
#: templates/rest_framework/filters/search.html:2
msgid "Search"
msgstr ""
#: templates/rest_framework/horizontal/radio.html:2
#: templates/rest_framework/inline/radio.html:2
#: templates/rest_framework/vertical/radio.html:2
@ -329,46 +383,46 @@ msgstr "Ingen"
msgid "No items to select."
msgstr "Intet at vælge."
#: validators.py:22
#: validators.py:24
msgid "This field must be unique."
msgstr "Dette felt skal være unikt."
#: validators.py:76
#: validators.py:78
#, python-brace-format
msgid "The fields {field_names} must make a unique set."
msgstr "Felterne {field_names} skal udgøre et unikt sæt."
#: validators.py:224
#: validators.py:226
#, python-brace-format
msgid "This field must be unique for the \"{date_field}\" date."
msgstr "Dette felt skal være unikt for \"{date_field}\"-datoen."
#: validators.py:239
#: validators.py:241
#, python-brace-format
msgid "This field must be unique for the \"{date_field}\" month."
msgstr "Dette felt skal være unikt for \"{date_field}\"-måneden."
#: validators.py:252
#: validators.py:254
#, python-brace-format
msgid "This field must be unique for the \"{date_field}\" year."
msgstr "Dette felt skal være unikt for \"{date_field}\"-året."
#: versioning.py:39
#: versioning.py:42
msgid "Invalid version in \"Accept\" header."
msgstr "Ugyldig version i \"Accept\" headeren."
#: versioning.py:70 versioning.py:112
#: versioning.py:73 versioning.py:115
msgid "Invalid version in URL path."
msgstr "Ugyldig version i URL-stien."
#: versioning.py:141
#: versioning.py:144
msgid "Invalid version in hostname."
msgstr "Ugyldig version i hostname."
#: versioning.py:163
#: versioning.py:166
msgid "Invalid version in query parameter."
msgstr "Ugyldig version i forespørgselsparameteren."
#: views.py:85
#: views.py:88
msgid "Permission denied."
msgstr "Adgang nægtet."

Binary file not shown.

View File

@ -0,0 +1,426 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# Translators:
msgid ""
msgstr ""
"Project-Id-Version: Django REST framework\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-12-07 18:53+0100\n"
"PO-Revision-Date: 2015-12-07 17:55+0000\n"
"Last-Translator: Xavier Ordoquy <xordoquy@linovia.com>\n"
"Language-Team: Danish (Denmark) (http://www.transifex.com/django-rest-framework-1/django-rest-framework/language/da_DK/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: da_DK\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: authentication.py:72
msgid "Invalid basic header. No credentials provided."
msgstr ""
#: authentication.py:75
msgid "Invalid basic header. Credentials string should not contain spaces."
msgstr ""
#: authentication.py:81
msgid "Invalid basic header. Credentials not correctly base64 encoded."
msgstr ""
#: authentication.py:98
msgid "Invalid username/password."
msgstr ""
#: authentication.py:101 authentication.py:188
msgid "User inactive or deleted."
msgstr ""
#: authentication.py:167
msgid "Invalid token header. No credentials provided."
msgstr ""
#: authentication.py:170
msgid "Invalid token header. Token string should not contain spaces."
msgstr ""
#: authentication.py:176
msgid ""
"Invalid token header. Token string should not contain invalid characters."
msgstr ""
#: authentication.py:185
msgid "Invalid token."
msgstr ""
#: authtoken/serializers.py:20
msgid "User account is disabled."
msgstr ""
#: authtoken/serializers.py:23
msgid "Unable to log in with provided credentials."
msgstr ""
#: authtoken/serializers.py:26
msgid "Must include \"username\" and \"password\"."
msgstr ""
#: exceptions.py:49
msgid "A server error occurred."
msgstr ""
#: exceptions.py:84
msgid "Malformed request."
msgstr ""
#: exceptions.py:89
msgid "Incorrect authentication credentials."
msgstr ""
#: exceptions.py:94
msgid "Authentication credentials were not provided."
msgstr ""
#: exceptions.py:99
msgid "You do not have permission to perform this action."
msgstr ""
#: exceptions.py:104 views.py:81
msgid "Not found."
msgstr ""
#: exceptions.py:109
#, python-brace-format
msgid "Method \"{method}\" not allowed."
msgstr ""
#: exceptions.py:120
msgid "Could not satisfy the request Accept header."
msgstr ""
#: exceptions.py:132
#, python-brace-format
msgid "Unsupported media type \"{media_type}\" in request."
msgstr ""
#: exceptions.py:145
msgid "Request was throttled."
msgstr ""
#: fields.py:266 relations.py:195 relations.py:228 validators.py:79
#: validators.py:162
msgid "This field is required."
msgstr ""
#: fields.py:267
msgid "This field may not be null."
msgstr ""
#: fields.py:603 fields.py:634
#, python-brace-format
msgid "\"{input}\" is not a valid boolean."
msgstr ""
#: fields.py:669
msgid "This field may not be blank."
msgstr ""
#: fields.py:670 fields.py:1656
#, python-brace-format
msgid "Ensure this field has no more than {max_length} characters."
msgstr ""
#: fields.py:671
#, python-brace-format
msgid "Ensure this field has at least {min_length} characters."
msgstr ""
#: fields.py:708
msgid "Enter a valid email address."
msgstr ""
#: fields.py:719
msgid "This value does not match the required pattern."
msgstr ""
#: fields.py:730
msgid ""
"Enter a valid \"slug\" consisting of letters, numbers, underscores or "
"hyphens."
msgstr ""
#: fields.py:742
msgid "Enter a valid URL."
msgstr ""
#: fields.py:755
#, python-brace-format
msgid "\"{value}\" is not a valid UUID."
msgstr ""
#: fields.py:791
msgid "Enter a valid IPv4 or IPv6 address."
msgstr ""
#: fields.py:816
msgid "A valid integer is required."
msgstr ""
#: fields.py:817 fields.py:852 fields.py:885
#, python-brace-format
msgid "Ensure this value is less than or equal to {max_value}."
msgstr ""
#: fields.py:818 fields.py:853 fields.py:886
#, python-brace-format
msgid "Ensure this value is greater than or equal to {min_value}."
msgstr ""
#: fields.py:819 fields.py:854 fields.py:890
msgid "String value too large."
msgstr ""
#: fields.py:851 fields.py:884
msgid "A valid number is required."
msgstr ""
#: fields.py:887
#, python-brace-format
msgid "Ensure that there are no more than {max_digits} digits in total."
msgstr ""
#: fields.py:888
#, python-brace-format
msgid ""
"Ensure that there are no more than {max_decimal_places} decimal places."
msgstr ""
#: fields.py:889
#, python-brace-format
msgid ""
"Ensure that there are no more than {max_whole_digits} digits before the "
"decimal point."
msgstr ""
#: fields.py:1004
#, python-brace-format
msgid "Datetime has wrong format. Use one of these formats instead: {format}."
msgstr ""
#: fields.py:1005
msgid "Expected a datetime but got a date."
msgstr ""
#: fields.py:1079
#, python-brace-format
msgid "Date has wrong format. Use one of these formats instead: {format}."
msgstr ""
#: fields.py:1080
msgid "Expected a date but got a datetime."
msgstr ""
#: fields.py:1148
#, python-brace-format
msgid "Time has wrong format. Use one of these formats instead: {format}."
msgstr ""
#: fields.py:1207
#, python-brace-format
msgid "Duration has wrong format. Use one of these formats instead: {format}."
msgstr ""
#: fields.py:1232 fields.py:1281
#, python-brace-format
msgid "\"{input}\" is not a valid choice."
msgstr ""
#: fields.py:1235 relations.py:62 relations.py:431
#, python-brace-format
msgid "More than {count} items..."
msgstr ""
#: fields.py:1282 fields.py:1429 relations.py:427 serializers.py:520
#, python-brace-format
msgid "Expected a list of items but got type \"{input_type}\"."
msgstr ""
#: fields.py:1283
msgid "This selection may not be empty."
msgstr ""
#: fields.py:1320
#, python-brace-format
msgid "\"{input}\" is not a valid path choice."
msgstr ""
#: fields.py:1339
msgid "No file was submitted."
msgstr ""
#: fields.py:1340
msgid ""
"The submitted data was not a file. Check the encoding type on the form."
msgstr ""
#: fields.py:1341
msgid "No filename could be determined."
msgstr ""
#: fields.py:1342
msgid "The submitted file is empty."
msgstr ""
#: fields.py:1343
#, python-brace-format
msgid ""
"Ensure this filename has at most {max_length} characters (it has {length})."
msgstr ""
#: fields.py:1391
msgid ""
"Upload a valid image. The file you uploaded was either not an image or a "
"corrupted image."
msgstr ""
#: fields.py:1430 relations.py:428 serializers.py:521
msgid "This list may not be empty."
msgstr ""
#: fields.py:1483
#, python-brace-format
msgid "Expected a dictionary of items but got type \"{input_type}\"."
msgstr ""
#: fields.py:1530
msgid "Value must be valid JSON."
msgstr ""
#: filters.py:35 templates/rest_framework/filters/django_filter.html:5
msgid "Submit"
msgstr ""
#: pagination.py:189
#, python-brace-format
msgid "Invalid page \"{page_number}\": {message}."
msgstr ""
#: pagination.py:407
msgid "Invalid cursor"
msgstr ""
#: relations.py:196
#, python-brace-format
msgid "Invalid pk \"{pk_value}\" - object does not exist."
msgstr ""
#: relations.py:197
#, python-brace-format
msgid "Incorrect type. Expected pk value, received {data_type}."
msgstr ""
#: relations.py:229
msgid "Invalid hyperlink - No URL match."
msgstr ""
#: relations.py:230
msgid "Invalid hyperlink - Incorrect URL match."
msgstr ""
#: relations.py:231
msgid "Invalid hyperlink - Object does not exist."
msgstr ""
#: relations.py:232
#, python-brace-format
msgid "Incorrect type. Expected URL string, received {data_type}."
msgstr ""
#: relations.py:391
#, python-brace-format
msgid "Object with {slug_name}={value} does not exist."
msgstr ""
#: relations.py:392
msgid "Invalid value."
msgstr ""
#: serializers.py:326
#, python-brace-format
msgid "Invalid data. Expected a dictionary, but got {datatype}."
msgstr ""
#: templates/rest_framework/admin.html:118
#: templates/rest_framework/base.html:128
msgid "Filters"
msgstr ""
#: templates/rest_framework/filters/django_filter.html:2
#: templates/rest_framework/filters/django_filter_crispyforms.html:4
msgid "Field filters"
msgstr ""
#: templates/rest_framework/filters/ordering.html:3
msgid "Ordering"
msgstr ""
#: templates/rest_framework/filters/search.html:2
msgid "Search"
msgstr ""
#: templates/rest_framework/horizontal/radio.html:2
#: templates/rest_framework/inline/radio.html:2
#: templates/rest_framework/vertical/radio.html:2
msgid "None"
msgstr ""
#: templates/rest_framework/horizontal/select_multiple.html:2
#: templates/rest_framework/inline/select_multiple.html:2
#: templates/rest_framework/vertical/select_multiple.html:2
msgid "No items to select."
msgstr ""
#: validators.py:24
msgid "This field must be unique."
msgstr ""
#: validators.py:78
#, python-brace-format
msgid "The fields {field_names} must make a unique set."
msgstr ""
#: validators.py:226
#, python-brace-format
msgid "This field must be unique for the \"{date_field}\" date."
msgstr ""
#: validators.py:241
#, python-brace-format
msgid "This field must be unique for the \"{date_field}\" month."
msgstr ""
#: validators.py:254
#, python-brace-format
msgid "This field must be unique for the \"{date_field}\" year."
msgstr ""
#: versioning.py:42
msgid "Invalid version in \"Accept\" header."
msgstr ""
#: versioning.py:73 versioning.py:115
msgid "Invalid version in URL path."
msgstr ""
#: versioning.py:144
msgid "Invalid version in hostname."
msgstr ""
#: versioning.py:166
msgid "Invalid version in query parameter."
msgstr ""
#: views.py:88
msgid "Permission denied."
msgstr ""

View File

@ -4,39 +4,42 @@
#
# Translators:
# Fabian Büchler <fabian@buechler.io>, 2015
# Mads Jensen <mje@inducks.org>, 2015
# Niklas P <contact@niklasplessing.net>, 2015
# Thomas Tanner, 2015
# Tom Jaster <futur3.tom@googlemail.com>, 2015
# Xavier Ordoquy <xordoquy@linovia.com>, 2015
msgid ""
msgstr ""
"Project-Id-Version: Django REST framework\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-06-03 17:30+0100\n"
"PO-Revision-Date: 2015-06-03 16:30+0000\n"
"Last-Translator: Xavier Ordoquy <xordoquy@linovia.com>\n"
"Language-Team: German (http://www.transifex.com/projects/p/django-rest-framework/language/de/)\n"
"POT-Creation-Date: 2015-12-07 18:53+0100\n"
"PO-Revision-Date: 2015-12-08 18:25+0000\n"
"Last-Translator: Fabian Büchler <fabian@buechler.io>\n"
"Language-Team: German (http://www.transifex.com/django-rest-framework-1/django-rest-framework/language/de/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: de\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: authentication.py:70
#: authentication.py:72
msgid "Invalid basic header. No credentials provided."
msgstr "Ungültiger basic header. Keine Zugangsdaten angegeben."
#: authentication.py:73
#: authentication.py:75
msgid "Invalid basic header. Credentials string should not contain spaces."
msgstr "Ungültiger basic header. Zugangsdaten sollen keine Leerzeichen enthalten."
#: authentication.py:79
#: authentication.py:81
msgid "Invalid basic header. Credentials not correctly base64 encoded."
msgstr "Ungültiger basic header. Zugangsdaten sind nicht korrekt mit base64 kodiert."
#: authentication.py:97
#: authentication.py:98
msgid "Invalid username/password."
msgstr "Ungültiger Benutzername/Passwort"
#: authentication.py:100 authentication.py:182
#: authentication.py:101 authentication.py:188
msgid "User inactive or deleted."
msgstr "Benutzer inaktiv oder gelöscht."
@ -48,7 +51,12 @@ msgstr "Ungültiger token header. Keine Zugangsdaten angegeben."
msgid "Invalid token header. Token string should not contain spaces."
msgstr "Ungültiger token header. Zugangsdaten sollen keine Leerzeichen enthalten."
#: authentication.py:179
#: authentication.py:176
msgid ""
"Invalid token header. Token string should not contain invalid characters."
msgstr "Ungültiger Token Header. Tokens dürfen keine ungültigen Zeichen enthalten."
#: authentication.py:185
msgid "Invalid token."
msgstr "Ungültiges Token"
@ -64,313 +72,361 @@ msgstr "Kann nicht mit den angegeben Zugangsdaten anmelden."
msgid "Must include \"username\" and \"password\"."
msgstr "\"username\" und \"password\" sind erforderlich."
#: exceptions.py:38
#: exceptions.py:49
msgid "A server error occurred."
msgstr "Ein Serverfehler ist aufgetreten."
#: exceptions.py:73
#: exceptions.py:84
msgid "Malformed request."
msgstr "Fehlerhafte Anfrage."
#: exceptions.py:78
#: exceptions.py:89
msgid "Incorrect authentication credentials."
msgstr "Falsche Anmeldedaten."
#: exceptions.py:83
#: exceptions.py:94
msgid "Authentication credentials were not provided."
msgstr "Anmeldedaten fehlen."
#: exceptions.py:88
#: exceptions.py:99
msgid "You do not have permission to perform this action."
msgstr "Sie sind nicht berechtigt, diese Aktion durchzuführen."
#: exceptions.py:93 views.py:78
#: exceptions.py:104 views.py:81
msgid "Not found."
msgstr "Nicht gefunden."
#: exceptions.py:98
#: exceptions.py:109
#, python-brace-format
msgid "Method \"{method}\" not allowed."
msgstr "Methode \"{method}\" nicht erlaubt."
#: exceptions.py:109
#: exceptions.py:120
msgid "Could not satisfy the request Accept header."
msgstr "Kann die Accept Kopfzeile der Anfrage nicht erfüllen."
#: exceptions.py:121
#: exceptions.py:132
#, python-brace-format
msgid "Unsupported media type \"{media_type}\" in request."
msgstr "Nicht unterstützter Medientyp \"{media_type}\" in der Anfrage."
#: exceptions.py:134
#: exceptions.py:145
msgid "Request was throttled."
msgstr "Die Anfrage wurde gedrosselt."
#: fields.py:162 relations.py:132 relations.py:156 validators.py:77
#: validators.py:160
#: fields.py:266 relations.py:195 relations.py:228 validators.py:79
#: validators.py:162
msgid "This field is required."
msgstr "Dieses Feld ist erforderlich."
#: fields.py:163
#: fields.py:267
msgid "This field may not be null."
msgstr "Dieses Feld darf nicht Null sein."
#: fields.py:496 fields.py:524
#: fields.py:603 fields.py:634
#, python-brace-format
msgid "\"{input}\" is not a valid boolean."
msgstr "\"{input}\" ist kein gültiger Wahrheitswert."
#: fields.py:559
#: fields.py:669
msgid "This field may not be blank."
msgstr "Dieses Feld darf nicht leer sein."
#: fields.py:560 fields.py:1386
#: fields.py:670 fields.py:1656
#, python-brace-format
msgid "Ensure this field has no more than {max_length} characters."
msgstr "Stelle sicher, dass dieses Feld nicht mehr als {max_length} Zeichen lang ist."
#: fields.py:561
#: fields.py:671
#, python-brace-format
msgid "Ensure this field has at least {min_length} characters."
msgstr "Stelle sicher, dass dieses Feld mindestens {min_length} Zeichen lang ist."
#: fields.py:598
#: fields.py:708
msgid "Enter a valid email address."
msgstr "Gib eine gültige E-Mail Adresse an."
#: fields.py:609
#: fields.py:719
msgid "This value does not match the required pattern."
msgstr "Dieser Wert passt nicht zu dem erforderlichen Muster."
#: fields.py:620
#: fields.py:730
msgid ""
"Enter a valid \"slug\" consisting of letters, numbers, underscores or "
"hyphens."
msgstr "Gib ein gültiges \"slug\" aus Buchstaben, Ziffern, Unterstrichen und Minuszeichen ein."
#: fields.py:632
#: fields.py:742
msgid "Enter a valid URL."
msgstr "Gib eine gültige URL ein."
#: fields.py:645
#: fields.py:755
#, python-brace-format
msgid "\"{value}\" is not a valid UUID."
msgstr "\"{value}\" ist keine gültige UUID."
#: fields.py:679
#: fields.py:791
msgid "Enter a valid IPv4 or IPv6 address."
msgstr "Geben Sie eine gültige UPv4 oder IPv6 Adresse an"
#: fields.py:816
msgid "A valid integer is required."
msgstr "Eine gültige Ganzzahl ist erforderlich."
#: fields.py:680 fields.py:715 fields.py:748
#: fields.py:817 fields.py:852 fields.py:885
#, python-brace-format
msgid "Ensure this value is less than or equal to {max_value}."
msgstr "Stelle sicher, dass dieser Wert kleiner oder gleich {max_value} ist."
#: fields.py:681 fields.py:716 fields.py:749
#: fields.py:818 fields.py:853 fields.py:886
#, python-brace-format
msgid "Ensure this value is greater than or equal to {min_value}."
msgstr "Stelle sicher, dass dieser Wert größer oder gleich {min_value} ist."
#: fields.py:682 fields.py:717 fields.py:753
#: fields.py:819 fields.py:854 fields.py:890
msgid "String value too large."
msgstr "Zeichenkette zu lang."
#: fields.py:714 fields.py:747
#: fields.py:851 fields.py:884
msgid "A valid number is required."
msgstr "Eine gültige Zahl ist erforderlich."
#: fields.py:750
#: fields.py:887
#, python-brace-format
msgid "Ensure that there are no more than {max_digits} digits in total."
msgstr "Stelle sicher, dass es insgesamt nicht mehr als {max_digits} Ziffern lang ist."
#: fields.py:751
#: fields.py:888
#, python-brace-format
msgid ""
"Ensure that there are no more than {max_decimal_places} decimal places."
msgstr "Stelle sicher, dass es nicht mehr als {max_decimal_places} Nachkommastellen lang ist."
#: fields.py:752
#: fields.py:889
#, python-brace-format
msgid ""
"Ensure that there are no more than {max_whole_digits} digits before the "
"decimal point."
msgstr "Stelle sicher, dass es nicht mehr als {max_whole_digits} Stellen vor dem Komma lang ist."
#: fields.py:842
#: fields.py:1004
#, python-brace-format
msgid "Datetime has wrong format. Use one of these formats instead: {format}."
msgstr "Datums- und Zeitangabe hat das falsche Format. Nutze stattdessen eines dieser Formate: {format}."
#: fields.py:843
#: fields.py:1005
msgid "Expected a datetime but got a date."
msgstr "Erwarte eine Datums- und Zeitangabe, erhielt aber ein Datum."
#: fields.py:907
#: fields.py:1079
#, python-brace-format
msgid "Date has wrong format. Use one of these formats instead: {format}."
msgstr "Datum hat das falsche Format. Nutze stattdessen eines dieser Formate: {format}."
#: fields.py:908
#: fields.py:1080
msgid "Expected a date but got a datetime."
msgstr "Erwarte ein Datum, erhielt aber eine Datums- und Zeitangabe."
#: fields.py:971
#: fields.py:1148
#, python-brace-format
msgid "Time has wrong format. Use one of these formats instead: {format}."
msgstr "Zeitangabe hat das falsche Format. Nutze stattdessen eines dieser Formate: {format}."
#: fields.py:1025
#: fields.py:1207
#, python-brace-format
msgid "Duration has wrong format. Use one of these formats instead: {format}."
msgstr ""
msgstr "Laufzeit hat das falsche Format. Benutze stattdessen eines dieser Formate {format}."
#: fields.py:1050 fields.py:1094
#: fields.py:1232 fields.py:1281
#, python-brace-format
msgid "\"{input}\" is not a valid choice."
msgstr "\"{input}\" ist keine gültige Option."
#: fields.py:1095 fields.py:1213 serializers.py:487
#: fields.py:1235 relations.py:62 relations.py:431
#, python-brace-format
msgid "More than {count} items..."
msgstr "Mehr als {count} Ergebnisse"
#: fields.py:1282 fields.py:1429 relations.py:427 serializers.py:520
#, python-brace-format
msgid "Expected a list of items but got type \"{input_type}\"."
msgstr "Erwarte eine Liste von Elementen, erhielt aber den Typ \"{input_type}\"."
#: fields.py:1129
#: fields.py:1283
msgid "This selection may not be empty."
msgstr "Diese Auswahl darf nicht leer sein"
#: fields.py:1320
#, python-brace-format
msgid "\"{input}\" is not a valid path choice."
msgstr "\"{input}\" ist ein ungültiger Pfad Wahl."
#: fields.py:1339
msgid "No file was submitted."
msgstr "Es wurde keine Datei übermittelt."
#: fields.py:1130
#: fields.py:1340
msgid ""
"The submitted data was not a file. Check the encoding type on the form."
msgstr "Die übermittelten Daten stellen keine Datei dar. Prüfe den Kodierungstyp im Formular."
#: fields.py:1131
#: fields.py:1341
msgid "No filename could be determined."
msgstr "Der Dateiname konnte nicht ermittelt werden."
#: fields.py:1132
#: fields.py:1342
msgid "The submitted file is empty."
msgstr "Die übermittelte Datei ist leer."
#: fields.py:1133
#: fields.py:1343
#, python-brace-format
msgid ""
"Ensure this filename has at most {max_length} characters (it has {length})."
msgstr "Stelle sicher, dass dieser Dateiname höchstens {max_length} Zeichen lang ist (er hat {length})."
#: fields.py:1175
#: fields.py:1391
msgid ""
"Upload a valid image. The file you uploaded was either not an image or a "
"corrupted image."
msgstr "Lade ein gültiges Bild hoch. Die hochgeladene Datei ist entweder kein Bild oder ein beschädigtes Bild."
#: fields.py:1250
#: fields.py:1430 relations.py:428 serializers.py:521
msgid "This list may not be empty."
msgstr "Diese Liste darf nicht leer sein."
#: fields.py:1483
#, python-brace-format
msgid "Expected a dictionary of items but got type \"{input_type}\"."
msgstr "Erwarte ein Dictionary mit Elementen, erhielt aber den Typ \"{input_type}\"."
#: pagination.py:231
#: fields.py:1530
msgid "Value must be valid JSON."
msgstr "Wert muss gültiges JSON sein."
#: filters.py:35 templates/rest_framework/filters/django_filter.html:5
msgid "Submit"
msgstr "Abschicken"
#: pagination.py:189
#, python-brace-format
msgid "Invalid page \"{page_number}\": {message}."
msgstr "Ungültige Seite \"{page_number}\": {message}."
#: pagination.py:492
#: pagination.py:407
msgid "Invalid cursor"
msgstr "Ungültiger Zeiger"
#: relations.py:133
#: relations.py:196
#, python-brace-format
msgid "Invalid pk \"{pk_value}\" - object does not exist."
msgstr "Ungültiger pk \"{pk_value}\" - Object existiert nicht."
#: relations.py:134
#: relations.py:197
#, python-brace-format
msgid "Incorrect type. Expected pk value, received {data_type}."
msgstr "Falscher Typ. Erwarte pk Wert, erhielt aber {data_type}."
#: relations.py:157
#: relations.py:229
msgid "Invalid hyperlink - No URL match."
msgstr "Ungültiger Hyperlink - entspricht keiner URL."
#: relations.py:158
#: relations.py:230
msgid "Invalid hyperlink - Incorrect URL match."
msgstr "Ungültiger Hyperlink - URL stimmt nicht überein."
#: relations.py:159
#: relations.py:231
msgid "Invalid hyperlink - Object does not exist."
msgstr "Ungültiger Hyperlink - Objekt existiert nicht."
#: relations.py:160
#: relations.py:232
#, python-brace-format
msgid "Incorrect type. Expected URL string, received {data_type}."
msgstr "Falscher Typ. Erwarte URL Zeichenkette, erhielt aber {data_type}."
#: relations.py:302
#: relations.py:391
#, python-brace-format
msgid "Object with {slug_name}={value} does not exist."
msgstr "Objekt mit {slug_name}={value} existiert nicht."
#: relations.py:303
#: relations.py:392
msgid "Invalid value."
msgstr "Ungültiger Wert."
#: serializers.py:304
#: serializers.py:326
#, python-brace-format
msgid "Invalid data. Expected a dictionary, but got {datatype}."
msgstr "Ungültige Daten. Dictionary erwartet, aber {datatype} erhalten."
#: templates/rest_framework/admin.html:118
#: templates/rest_framework/base.html:128
msgid "Filters"
msgstr "Filter"
#: templates/rest_framework/filters/django_filter.html:2
#: templates/rest_framework/filters/django_filter_crispyforms.html:4
msgid "Field filters"
msgstr "Feldfilter"
#: templates/rest_framework/filters/ordering.html:3
msgid "Ordering"
msgstr "Sortierung"
#: templates/rest_framework/filters/search.html:2
msgid "Search"
msgstr "Suche"
#: templates/rest_framework/horizontal/radio.html:2
#: templates/rest_framework/inline/radio.html:2
#: templates/rest_framework/vertical/radio.html:2
msgid "None"
msgstr ""
msgstr "Nichts"
#: templates/rest_framework/horizontal/select_multiple.html:2
#: templates/rest_framework/inline/select_multiple.html:2
#: templates/rest_framework/vertical/select_multiple.html:2
msgid "No items to select."
msgstr ""
msgstr "Keine Elemente zum Auswählen."
#: validators.py:22
#: validators.py:24
msgid "This field must be unique."
msgstr "Dieses Feld muss eindeutig sein."
#: validators.py:76
#: validators.py:78
#, python-brace-format
msgid "The fields {field_names} must make a unique set."
msgstr "Die Felder {field_names} müssen eine eindeutige Menge bilden."
#: validators.py:224
#: validators.py:226
#, python-brace-format
msgid "This field must be unique for the \"{date_field}\" date."
msgstr "Dieses Feld muss bezüglich des \"{date_field}\" Datums eindeutig sein."
#: validators.py:239
#: validators.py:241
#, python-brace-format
msgid "This field must be unique for the \"{date_field}\" month."
msgstr "Dieses Feld muss bezüglich des \"{date_field}\" Monats eindeutig sein."
#: validators.py:252
#: validators.py:254
#, python-brace-format
msgid "This field must be unique for the \"{date_field}\" year."
msgstr "Dieses Feld muss bezüglich des \"{date_field}\" Jahrs eindeutig sein."
#: versioning.py:39
#: versioning.py:42
msgid "Invalid version in \"Accept\" header."
msgstr "Ungültige Version in der \"Accept\" Kopfzeile."
#: versioning.py:70 versioning.py:112
#: versioning.py:73 versioning.py:115
msgid "Invalid version in URL path."
msgstr "Ungültige Version im URL Pfad."
#: versioning.py:141
#: versioning.py:144
msgid "Invalid version in hostname."
msgstr "Ungültige Version im Hostname."
#: versioning.py:163
#: versioning.py:166
msgid "Invalid version in query parameter."
msgstr "Ungültige Version im Anfrageparameter."
#: views.py:85
#: views.py:88
msgid "Permission denied."
msgstr ""
msgstr "Zugriff verweigert."

View File

@ -7,33 +7,33 @@ msgid ""
msgstr ""
"Project-Id-Version: Django REST framework\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-06-03 17:30+0100\n"
"PO-Revision-Date: 2015-06-03 16:30+0000\n"
"POT-Creation-Date: 2015-12-07 18:53+0100\n"
"PO-Revision-Date: 2015-12-07 17:55+0000\n"
"Last-Translator: Xavier Ordoquy <xordoquy@linovia.com>\n"
"Language-Team: English (http://www.transifex.com/projects/p/django-rest-framework/language/en/)\n"
"Language-Team: English (http://www.transifex.com/django-rest-framework-1/django-rest-framework/language/en/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: en\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: authentication.py:70
#: authentication.py:72
msgid "Invalid basic header. No credentials provided."
msgstr "Invalid basic header. No credentials provided."
#: authentication.py:73
#: authentication.py:75
msgid "Invalid basic header. Credentials string should not contain spaces."
msgstr "Invalid basic header. Credentials string should not contain spaces."
#: authentication.py:79
#: authentication.py:81
msgid "Invalid basic header. Credentials not correctly base64 encoded."
msgstr "Invalid basic header. Credentials not correctly base64 encoded."
#: authentication.py:97
#: authentication.py:98
msgid "Invalid username/password."
msgstr "Invalid username/password."
#: authentication.py:100 authentication.py:182
#: authentication.py:101 authentication.py:188
msgid "User inactive or deleted."
msgstr "User inactive or deleted."
@ -45,7 +45,12 @@ msgstr "Invalid token header. No credentials provided."
msgid "Invalid token header. Token string should not contain spaces."
msgstr "Invalid token header. Token string should not contain spaces."
#: authentication.py:179
#: authentication.py:176
msgid ""
"Invalid token header. Token string should not contain invalid characters."
msgstr "Invalid token header. Token string should not contain invalid characters."
#: authentication.py:185
msgid "Invalid token."
msgstr "Invalid token."
@ -61,261 +66,309 @@ msgstr "Unable to log in with provided credentials."
msgid "Must include \"username\" and \"password\"."
msgstr "Must include \"username\" and \"password\"."
#: exceptions.py:38
#: exceptions.py:49
msgid "A server error occurred."
msgstr "A server error occurred."
#: exceptions.py:73
#: exceptions.py:84
msgid "Malformed request."
msgstr "Malformed request."
#: exceptions.py:78
#: exceptions.py:89
msgid "Incorrect authentication credentials."
msgstr "Incorrect authentication credentials."
#: exceptions.py:83
#: exceptions.py:94
msgid "Authentication credentials were not provided."
msgstr "Authentication credentials were not provided."
#: exceptions.py:88
#: exceptions.py:99
msgid "You do not have permission to perform this action."
msgstr "You do not have permission to perform this action."
#: exceptions.py:93 views.py:78
#: exceptions.py:104 views.py:81
msgid "Not found."
msgstr "Not found."
#: exceptions.py:98
#: exceptions.py:109
#, python-brace-format
msgid "Method \"{method}\" not allowed."
msgstr "Method \"{method}\" not allowed."
#: exceptions.py:109
#: exceptions.py:120
msgid "Could not satisfy the request Accept header."
msgstr "Could not satisfy the request Accept header."
#: exceptions.py:121
#: exceptions.py:132
#, python-brace-format
msgid "Unsupported media type \"{media_type}\" in request."
msgstr "Unsupported media type \"{media_type}\" in request."
#: exceptions.py:134
#: exceptions.py:145
msgid "Request was throttled."
msgstr "Request was throttled."
#: fields.py:162 relations.py:132 relations.py:156 validators.py:77
#: validators.py:160
#: fields.py:266 relations.py:195 relations.py:228 validators.py:79
#: validators.py:162
msgid "This field is required."
msgstr "This field is required."
#: fields.py:163
#: fields.py:267
msgid "This field may not be null."
msgstr "This field may not be null."
#: fields.py:496 fields.py:524
#: fields.py:603 fields.py:634
#, python-brace-format
msgid "\"{input}\" is not a valid boolean."
msgstr "\"{input}\" is not a valid boolean."
#: fields.py:559
#: fields.py:669
msgid "This field may not be blank."
msgstr "This field may not be blank."
#: fields.py:560 fields.py:1386
#: fields.py:670 fields.py:1656
#, python-brace-format
msgid "Ensure this field has no more than {max_length} characters."
msgstr "Ensure this field has no more than {max_length} characters."
#: fields.py:561
#: fields.py:671
#, python-brace-format
msgid "Ensure this field has at least {min_length} characters."
msgstr "Ensure this field has at least {min_length} characters."
#: fields.py:598
#: fields.py:708
msgid "Enter a valid email address."
msgstr "Enter a valid email address."
#: fields.py:609
#: fields.py:719
msgid "This value does not match the required pattern."
msgstr "This value does not match the required pattern."
#: fields.py:620
#: fields.py:730
msgid ""
"Enter a valid \"slug\" consisting of letters, numbers, underscores or "
"hyphens."
msgstr "Enter a valid \"slug\" consisting of letters, numbers, underscores or hyphens."
#: fields.py:632
#: fields.py:742
msgid "Enter a valid URL."
msgstr "Enter a valid URL."
#: fields.py:645
#: fields.py:755
#, python-brace-format
msgid "\"{value}\" is not a valid UUID."
msgstr "\"{value}\" is not a valid UUID."
#: fields.py:679
#: fields.py:791
msgid "Enter a valid IPv4 or IPv6 address."
msgstr "Enter a valid IPv4 or IPv6 address."
#: fields.py:816
msgid "A valid integer is required."
msgstr "A valid integer is required."
#: fields.py:680 fields.py:715 fields.py:748
#: fields.py:817 fields.py:852 fields.py:885
#, python-brace-format
msgid "Ensure this value is less than or equal to {max_value}."
msgstr "Ensure this value is less than or equal to {max_value}."
#: fields.py:681 fields.py:716 fields.py:749
#: fields.py:818 fields.py:853 fields.py:886
#, python-brace-format
msgid "Ensure this value is greater than or equal to {min_value}."
msgstr "Ensure this value is greater than or equal to {min_value}."
#: fields.py:682 fields.py:717 fields.py:753
#: fields.py:819 fields.py:854 fields.py:890
msgid "String value too large."
msgstr "String value too large."
#: fields.py:714 fields.py:747
#: fields.py:851 fields.py:884
msgid "A valid number is required."
msgstr "A valid number is required."
#: fields.py:750
#: fields.py:887
#, python-brace-format
msgid "Ensure that there are no more than {max_digits} digits in total."
msgstr "Ensure that there are no more than {max_digits} digits in total."
#: fields.py:751
#: fields.py:888
#, python-brace-format
msgid ""
"Ensure that there are no more than {max_decimal_places} decimal places."
msgstr "Ensure that there are no more than {max_decimal_places} decimal places."
#: fields.py:752
#: fields.py:889
#, python-brace-format
msgid ""
"Ensure that there are no more than {max_whole_digits} digits before the "
"decimal point."
msgstr "Ensure that there are no more than {max_whole_digits} digits before the decimal point."
#: fields.py:842
#: fields.py:1004
#, python-brace-format
msgid "Datetime has wrong format. Use one of these formats instead: {format}."
msgstr "Datetime has wrong format. Use one of these formats instead: {format}."
#: fields.py:843
#: fields.py:1005
msgid "Expected a datetime but got a date."
msgstr "Expected a datetime but got a date."
#: fields.py:907
#: fields.py:1079
#, python-brace-format
msgid "Date has wrong format. Use one of these formats instead: {format}."
msgstr "Date has wrong format. Use one of these formats instead: {format}."
#: fields.py:908
#: fields.py:1080
msgid "Expected a date but got a datetime."
msgstr "Expected a date but got a datetime."
#: fields.py:971
#: fields.py:1148
#, python-brace-format
msgid "Time has wrong format. Use one of these formats instead: {format}."
msgstr "Time has wrong format. Use one of these formats instead: {format}."
#: fields.py:1025
#: fields.py:1207
#, python-brace-format
msgid "Duration has wrong format. Use one of these formats instead: {format}."
msgstr "Duration has wrong format. Use one of these formats instead: {format}."
#: fields.py:1050 fields.py:1094
#: fields.py:1232 fields.py:1281
#, python-brace-format
msgid "\"{input}\" is not a valid choice."
msgstr "\"{input}\" is not a valid choice."
#: fields.py:1095 fields.py:1213 serializers.py:487
#: fields.py:1235 relations.py:62 relations.py:431
#, python-brace-format
msgid "More than {count} items..."
msgstr "More than {count} items..."
#: fields.py:1282 fields.py:1429 relations.py:427 serializers.py:520
#, python-brace-format
msgid "Expected a list of items but got type \"{input_type}\"."
msgstr "Expected a list of items but got type \"{input_type}\"."
#: fields.py:1129
#: fields.py:1283
msgid "This selection may not be empty."
msgstr "This selection may not be empty."
#: fields.py:1320
#, python-brace-format
msgid "\"{input}\" is not a valid path choice."
msgstr "\"{input}\" is not a valid path choice."
#: fields.py:1339
msgid "No file was submitted."
msgstr "No file was submitted."
#: fields.py:1130
#: fields.py:1340
msgid ""
"The submitted data was not a file. Check the encoding type on the form."
msgstr "The submitted data was not a file. Check the encoding type on the form."
#: fields.py:1131
#: fields.py:1341
msgid "No filename could be determined."
msgstr "No filename could be determined."
#: fields.py:1132
#: fields.py:1342
msgid "The submitted file is empty."
msgstr "The submitted file is empty."
#: fields.py:1133
#: fields.py:1343
#, python-brace-format
msgid ""
"Ensure this filename has at most {max_length} characters (it has {length})."
msgstr "Ensure this filename has at most {max_length} characters (it has {length})."
#: fields.py:1175
#: fields.py:1391
msgid ""
"Upload a valid image. The file you uploaded was either not an image or a "
"corrupted image."
msgstr "Upload a valid image. The file you uploaded was either not an image or a corrupted image."
#: fields.py:1250
#: fields.py:1430 relations.py:428 serializers.py:521
msgid "This list may not be empty."
msgstr "This list may not be empty."
#: fields.py:1483
#, python-brace-format
msgid "Expected a dictionary of items but got type \"{input_type}\"."
msgstr "Expected a dictionary of items but got type \"{input_type}\"."
#: pagination.py:231
#: fields.py:1530
msgid "Value must be valid JSON."
msgstr "Value must be valid JSON."
#: filters.py:35 templates/rest_framework/filters/django_filter.html:5
msgid "Submit"
msgstr "Submit"
#: pagination.py:189
#, python-brace-format
msgid "Invalid page \"{page_number}\": {message}."
msgstr "Invalid page \"{page_number}\": {message}."
#: pagination.py:492
#: pagination.py:407
msgid "Invalid cursor"
msgstr "Invalid cursor"
#: relations.py:133
#: relations.py:196
#, python-brace-format
msgid "Invalid pk \"{pk_value}\" - object does not exist."
msgstr "Invalid pk \"{pk_value}\" - object does not exist."
#: relations.py:134
#: relations.py:197
#, python-brace-format
msgid "Incorrect type. Expected pk value, received {data_type}."
msgstr "Incorrect type. Expected pk value, received {data_type}."
#: relations.py:157
#: relations.py:229
msgid "Invalid hyperlink - No URL match."
msgstr "Invalid hyperlink - No URL match."
#: relations.py:158
#: relations.py:230
msgid "Invalid hyperlink - Incorrect URL match."
msgstr "Invalid hyperlink - Incorrect URL match."
#: relations.py:159
#: relations.py:231
msgid "Invalid hyperlink - Object does not exist."
msgstr "Invalid hyperlink - Object does not exist."
#: relations.py:160
#: relations.py:232
#, python-brace-format
msgid "Incorrect type. Expected URL string, received {data_type}."
msgstr "Incorrect type. Expected URL string, received {data_type}."
#: relations.py:302
#: relations.py:391
#, python-brace-format
msgid "Object with {slug_name}={value} does not exist."
msgstr "Object with {slug_name}={value} does not exist."
#: relations.py:303
#: relations.py:392
msgid "Invalid value."
msgstr "Invalid value."
#: serializers.py:304
#: serializers.py:326
#, python-brace-format
msgid "Invalid data. Expected a dictionary, but got {datatype}."
msgstr "Invalid data. Expected a dictionary, but got {datatype}."
#: templates/rest_framework/admin.html:118
#: templates/rest_framework/base.html:128
msgid "Filters"
msgstr "Filters"
#: templates/rest_framework/filters/django_filter.html:2
#: templates/rest_framework/filters/django_filter_crispyforms.html:4
msgid "Field filters"
msgstr "Field filters"
#: templates/rest_framework/filters/ordering.html:3
msgid "Ordering"
msgstr "Ordering"
#: templates/rest_framework/filters/search.html:2
msgid "Search"
msgstr "Search"
#: templates/rest_framework/horizontal/radio.html:2
#: templates/rest_framework/inline/radio.html:2
#: templates/rest_framework/vertical/radio.html:2
@ -328,46 +381,46 @@ msgstr "None"
msgid "No items to select."
msgstr "No items to select."
#: validators.py:22
#: validators.py:24
msgid "This field must be unique."
msgstr "This field must be unique."
#: validators.py:76
#: validators.py:78
#, python-brace-format
msgid "The fields {field_names} must make a unique set."
msgstr "The fields {field_names} must make a unique set."
#: validators.py:224
#: validators.py:226
#, python-brace-format
msgid "This field must be unique for the \"{date_field}\" date."
msgstr "This field must be unique for the \"{date_field}\" date."
#: validators.py:239
#: validators.py:241
#, python-brace-format
msgid "This field must be unique for the \"{date_field}\" month."
msgstr "This field must be unique for the \"{date_field}\" month."
#: validators.py:252
#: validators.py:254
#, python-brace-format
msgid "This field must be unique for the \"{date_field}\" year."
msgstr "This field must be unique for the \"{date_field}\" year."
#: versioning.py:39
#: versioning.py:42
msgid "Invalid version in \"Accept\" header."
msgstr "Invalid version in \"Accept\" header."
#: versioning.py:70 versioning.py:112
#: versioning.py:73 versioning.py:115
msgid "Invalid version in URL path."
msgstr "Invalid version in URL path."
#: versioning.py:141
#: versioning.py:144
msgid "Invalid version in hostname."
msgstr "Invalid version in hostname."
#: versioning.py:163
#: versioning.py:166
msgid "Invalid version in query parameter."
msgstr "Invalid version in query parameter."
#: views.py:85
#: views.py:88
msgid "Permission denied."
msgstr "Permission denied."

Binary file not shown.

View File

@ -0,0 +1,426 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# Translators:
msgid ""
msgstr ""
"Project-Id-Version: Django REST framework\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-12-07 18:53+0100\n"
"PO-Revision-Date: 2015-12-07 17:55+0000\n"
"Last-Translator: Xavier Ordoquy <xordoquy@linovia.com>\n"
"Language-Team: English (Australia) (http://www.transifex.com/django-rest-framework-1/django-rest-framework/language/en_AU/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: en_AU\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: authentication.py:72
msgid "Invalid basic header. No credentials provided."
msgstr ""
#: authentication.py:75
msgid "Invalid basic header. Credentials string should not contain spaces."
msgstr ""
#: authentication.py:81
msgid "Invalid basic header. Credentials not correctly base64 encoded."
msgstr ""
#: authentication.py:98
msgid "Invalid username/password."
msgstr ""
#: authentication.py:101 authentication.py:188
msgid "User inactive or deleted."
msgstr ""
#: authentication.py:167
msgid "Invalid token header. No credentials provided."
msgstr ""
#: authentication.py:170
msgid "Invalid token header. Token string should not contain spaces."
msgstr ""
#: authentication.py:176
msgid ""
"Invalid token header. Token string should not contain invalid characters."
msgstr ""
#: authentication.py:185
msgid "Invalid token."
msgstr ""
#: authtoken/serializers.py:20
msgid "User account is disabled."
msgstr ""
#: authtoken/serializers.py:23
msgid "Unable to log in with provided credentials."
msgstr ""
#: authtoken/serializers.py:26
msgid "Must include \"username\" and \"password\"."
msgstr ""
#: exceptions.py:49
msgid "A server error occurred."
msgstr ""
#: exceptions.py:84
msgid "Malformed request."
msgstr ""
#: exceptions.py:89
msgid "Incorrect authentication credentials."
msgstr ""
#: exceptions.py:94
msgid "Authentication credentials were not provided."
msgstr ""
#: exceptions.py:99
msgid "You do not have permission to perform this action."
msgstr ""
#: exceptions.py:104 views.py:81
msgid "Not found."
msgstr ""
#: exceptions.py:109
#, python-brace-format
msgid "Method \"{method}\" not allowed."
msgstr ""
#: exceptions.py:120
msgid "Could not satisfy the request Accept header."
msgstr ""
#: exceptions.py:132
#, python-brace-format
msgid "Unsupported media type \"{media_type}\" in request."
msgstr ""
#: exceptions.py:145
msgid "Request was throttled."
msgstr ""
#: fields.py:266 relations.py:195 relations.py:228 validators.py:79
#: validators.py:162
msgid "This field is required."
msgstr ""
#: fields.py:267
msgid "This field may not be null."
msgstr ""
#: fields.py:603 fields.py:634
#, python-brace-format
msgid "\"{input}\" is not a valid boolean."
msgstr ""
#: fields.py:669
msgid "This field may not be blank."
msgstr ""
#: fields.py:670 fields.py:1656
#, python-brace-format
msgid "Ensure this field has no more than {max_length} characters."
msgstr ""
#: fields.py:671
#, python-brace-format
msgid "Ensure this field has at least {min_length} characters."
msgstr ""
#: fields.py:708
msgid "Enter a valid email address."
msgstr ""
#: fields.py:719
msgid "This value does not match the required pattern."
msgstr ""
#: fields.py:730
msgid ""
"Enter a valid \"slug\" consisting of letters, numbers, underscores or "
"hyphens."
msgstr ""
#: fields.py:742
msgid "Enter a valid URL."
msgstr ""
#: fields.py:755
#, python-brace-format
msgid "\"{value}\" is not a valid UUID."
msgstr ""
#: fields.py:791
msgid "Enter a valid IPv4 or IPv6 address."
msgstr ""
#: fields.py:816
msgid "A valid integer is required."
msgstr ""
#: fields.py:817 fields.py:852 fields.py:885
#, python-brace-format
msgid "Ensure this value is less than or equal to {max_value}."
msgstr ""
#: fields.py:818 fields.py:853 fields.py:886
#, python-brace-format
msgid "Ensure this value is greater than or equal to {min_value}."
msgstr ""
#: fields.py:819 fields.py:854 fields.py:890
msgid "String value too large."
msgstr ""
#: fields.py:851 fields.py:884
msgid "A valid number is required."
msgstr ""
#: fields.py:887
#, python-brace-format
msgid "Ensure that there are no more than {max_digits} digits in total."
msgstr ""
#: fields.py:888
#, python-brace-format
msgid ""
"Ensure that there are no more than {max_decimal_places} decimal places."
msgstr ""
#: fields.py:889
#, python-brace-format
msgid ""
"Ensure that there are no more than {max_whole_digits} digits before the "
"decimal point."
msgstr ""
#: fields.py:1004
#, python-brace-format
msgid "Datetime has wrong format. Use one of these formats instead: {format}."
msgstr ""
#: fields.py:1005
msgid "Expected a datetime but got a date."
msgstr ""
#: fields.py:1079
#, python-brace-format
msgid "Date has wrong format. Use one of these formats instead: {format}."
msgstr ""
#: fields.py:1080
msgid "Expected a date but got a datetime."
msgstr ""
#: fields.py:1148
#, python-brace-format
msgid "Time has wrong format. Use one of these formats instead: {format}."
msgstr ""
#: fields.py:1207
#, python-brace-format
msgid "Duration has wrong format. Use one of these formats instead: {format}."
msgstr ""
#: fields.py:1232 fields.py:1281
#, python-brace-format
msgid "\"{input}\" is not a valid choice."
msgstr ""
#: fields.py:1235 relations.py:62 relations.py:431
#, python-brace-format
msgid "More than {count} items..."
msgstr ""
#: fields.py:1282 fields.py:1429 relations.py:427 serializers.py:520
#, python-brace-format
msgid "Expected a list of items but got type \"{input_type}\"."
msgstr ""
#: fields.py:1283
msgid "This selection may not be empty."
msgstr ""
#: fields.py:1320
#, python-brace-format
msgid "\"{input}\" is not a valid path choice."
msgstr ""
#: fields.py:1339
msgid "No file was submitted."
msgstr ""
#: fields.py:1340
msgid ""
"The submitted data was not a file. Check the encoding type on the form."
msgstr ""
#: fields.py:1341
msgid "No filename could be determined."
msgstr ""
#: fields.py:1342
msgid "The submitted file is empty."
msgstr ""
#: fields.py:1343
#, python-brace-format
msgid ""
"Ensure this filename has at most {max_length} characters (it has {length})."
msgstr ""
#: fields.py:1391
msgid ""
"Upload a valid image. The file you uploaded was either not an image or a "
"corrupted image."
msgstr ""
#: fields.py:1430 relations.py:428 serializers.py:521
msgid "This list may not be empty."
msgstr ""
#: fields.py:1483
#, python-brace-format
msgid "Expected a dictionary of items but got type \"{input_type}\"."
msgstr ""
#: fields.py:1530
msgid "Value must be valid JSON."
msgstr ""
#: filters.py:35 templates/rest_framework/filters/django_filter.html:5
msgid "Submit"
msgstr ""
#: pagination.py:189
#, python-brace-format
msgid "Invalid page \"{page_number}\": {message}."
msgstr ""
#: pagination.py:407
msgid "Invalid cursor"
msgstr ""
#: relations.py:196
#, python-brace-format
msgid "Invalid pk \"{pk_value}\" - object does not exist."
msgstr ""
#: relations.py:197
#, python-brace-format
msgid "Incorrect type. Expected pk value, received {data_type}."
msgstr ""
#: relations.py:229
msgid "Invalid hyperlink - No URL match."
msgstr ""
#: relations.py:230
msgid "Invalid hyperlink - Incorrect URL match."
msgstr ""
#: relations.py:231
msgid "Invalid hyperlink - Object does not exist."
msgstr ""
#: relations.py:232
#, python-brace-format
msgid "Incorrect type. Expected URL string, received {data_type}."
msgstr ""
#: relations.py:391
#, python-brace-format
msgid "Object with {slug_name}={value} does not exist."
msgstr ""
#: relations.py:392
msgid "Invalid value."
msgstr ""
#: serializers.py:326
#, python-brace-format
msgid "Invalid data. Expected a dictionary, but got {datatype}."
msgstr ""
#: templates/rest_framework/admin.html:118
#: templates/rest_framework/base.html:128
msgid "Filters"
msgstr ""
#: templates/rest_framework/filters/django_filter.html:2
#: templates/rest_framework/filters/django_filter_crispyforms.html:4
msgid "Field filters"
msgstr ""
#: templates/rest_framework/filters/ordering.html:3
msgid "Ordering"
msgstr ""
#: templates/rest_framework/filters/search.html:2
msgid "Search"
msgstr ""
#: templates/rest_framework/horizontal/radio.html:2
#: templates/rest_framework/inline/radio.html:2
#: templates/rest_framework/vertical/radio.html:2
msgid "None"
msgstr ""
#: templates/rest_framework/horizontal/select_multiple.html:2
#: templates/rest_framework/inline/select_multiple.html:2
#: templates/rest_framework/vertical/select_multiple.html:2
msgid "No items to select."
msgstr ""
#: validators.py:24
msgid "This field must be unique."
msgstr ""
#: validators.py:78
#, python-brace-format
msgid "The fields {field_names} must make a unique set."
msgstr ""
#: validators.py:226
#, python-brace-format
msgid "This field must be unique for the \"{date_field}\" date."
msgstr ""
#: validators.py:241
#, python-brace-format
msgid "This field must be unique for the \"{date_field}\" month."
msgstr ""
#: validators.py:254
#, python-brace-format
msgid "This field must be unique for the \"{date_field}\" year."
msgstr ""
#: versioning.py:42
msgid "Invalid version in \"Accept\" header."
msgstr ""
#: versioning.py:73 versioning.py:115
msgid "Invalid version in URL path."
msgstr ""
#: versioning.py:144
msgid "Invalid version in hostname."
msgstr ""
#: versioning.py:166
msgid "Invalid version in query parameter."
msgstr ""
#: views.py:88
msgid "Permission denied."
msgstr ""

Binary file not shown.

View File

@ -0,0 +1,426 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# Translators:
msgid ""
msgstr ""
"Project-Id-Version: Django REST framework\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-12-07 18:53+0100\n"
"PO-Revision-Date: 2015-12-07 17:55+0000\n"
"Last-Translator: Xavier Ordoquy <xordoquy@linovia.com>\n"
"Language-Team: English (Canada) (http://www.transifex.com/django-rest-framework-1/django-rest-framework/language/en_CA/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: en_CA\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: authentication.py:72
msgid "Invalid basic header. No credentials provided."
msgstr ""
#: authentication.py:75
msgid "Invalid basic header. Credentials string should not contain spaces."
msgstr ""
#: authentication.py:81
msgid "Invalid basic header. Credentials not correctly base64 encoded."
msgstr ""
#: authentication.py:98
msgid "Invalid username/password."
msgstr ""
#: authentication.py:101 authentication.py:188
msgid "User inactive or deleted."
msgstr ""
#: authentication.py:167
msgid "Invalid token header. No credentials provided."
msgstr ""
#: authentication.py:170
msgid "Invalid token header. Token string should not contain spaces."
msgstr ""
#: authentication.py:176
msgid ""
"Invalid token header. Token string should not contain invalid characters."
msgstr ""
#: authentication.py:185
msgid "Invalid token."
msgstr ""
#: authtoken/serializers.py:20
msgid "User account is disabled."
msgstr ""
#: authtoken/serializers.py:23
msgid "Unable to log in with provided credentials."
msgstr ""
#: authtoken/serializers.py:26
msgid "Must include \"username\" and \"password\"."
msgstr ""
#: exceptions.py:49
msgid "A server error occurred."
msgstr ""
#: exceptions.py:84
msgid "Malformed request."
msgstr ""
#: exceptions.py:89
msgid "Incorrect authentication credentials."
msgstr ""
#: exceptions.py:94
msgid "Authentication credentials were not provided."
msgstr ""
#: exceptions.py:99
msgid "You do not have permission to perform this action."
msgstr ""
#: exceptions.py:104 views.py:81
msgid "Not found."
msgstr ""
#: exceptions.py:109
#, python-brace-format
msgid "Method \"{method}\" not allowed."
msgstr ""
#: exceptions.py:120
msgid "Could not satisfy the request Accept header."
msgstr ""
#: exceptions.py:132
#, python-brace-format
msgid "Unsupported media type \"{media_type}\" in request."
msgstr ""
#: exceptions.py:145
msgid "Request was throttled."
msgstr ""
#: fields.py:266 relations.py:195 relations.py:228 validators.py:79
#: validators.py:162
msgid "This field is required."
msgstr ""
#: fields.py:267
msgid "This field may not be null."
msgstr ""
#: fields.py:603 fields.py:634
#, python-brace-format
msgid "\"{input}\" is not a valid boolean."
msgstr ""
#: fields.py:669
msgid "This field may not be blank."
msgstr ""
#: fields.py:670 fields.py:1656
#, python-brace-format
msgid "Ensure this field has no more than {max_length} characters."
msgstr ""
#: fields.py:671
#, python-brace-format
msgid "Ensure this field has at least {min_length} characters."
msgstr ""
#: fields.py:708
msgid "Enter a valid email address."
msgstr ""
#: fields.py:719
msgid "This value does not match the required pattern."
msgstr ""
#: fields.py:730
msgid ""
"Enter a valid \"slug\" consisting of letters, numbers, underscores or "
"hyphens."
msgstr ""
#: fields.py:742
msgid "Enter a valid URL."
msgstr ""
#: fields.py:755
#, python-brace-format
msgid "\"{value}\" is not a valid UUID."
msgstr ""
#: fields.py:791
msgid "Enter a valid IPv4 or IPv6 address."
msgstr ""
#: fields.py:816
msgid "A valid integer is required."
msgstr ""
#: fields.py:817 fields.py:852 fields.py:885
#, python-brace-format
msgid "Ensure this value is less than or equal to {max_value}."
msgstr ""
#: fields.py:818 fields.py:853 fields.py:886
#, python-brace-format
msgid "Ensure this value is greater than or equal to {min_value}."
msgstr ""
#: fields.py:819 fields.py:854 fields.py:890
msgid "String value too large."
msgstr ""
#: fields.py:851 fields.py:884
msgid "A valid number is required."
msgstr ""
#: fields.py:887
#, python-brace-format
msgid "Ensure that there are no more than {max_digits} digits in total."
msgstr ""
#: fields.py:888
#, python-brace-format
msgid ""
"Ensure that there are no more than {max_decimal_places} decimal places."
msgstr ""
#: fields.py:889
#, python-brace-format
msgid ""
"Ensure that there are no more than {max_whole_digits} digits before the "
"decimal point."
msgstr ""
#: fields.py:1004
#, python-brace-format
msgid "Datetime has wrong format. Use one of these formats instead: {format}."
msgstr ""
#: fields.py:1005
msgid "Expected a datetime but got a date."
msgstr ""
#: fields.py:1079
#, python-brace-format
msgid "Date has wrong format. Use one of these formats instead: {format}."
msgstr ""
#: fields.py:1080
msgid "Expected a date but got a datetime."
msgstr ""
#: fields.py:1148
#, python-brace-format
msgid "Time has wrong format. Use one of these formats instead: {format}."
msgstr ""
#: fields.py:1207
#, python-brace-format
msgid "Duration has wrong format. Use one of these formats instead: {format}."
msgstr ""
#: fields.py:1232 fields.py:1281
#, python-brace-format
msgid "\"{input}\" is not a valid choice."
msgstr ""
#: fields.py:1235 relations.py:62 relations.py:431
#, python-brace-format
msgid "More than {count} items..."
msgstr ""
#: fields.py:1282 fields.py:1429 relations.py:427 serializers.py:520
#, python-brace-format
msgid "Expected a list of items but got type \"{input_type}\"."
msgstr ""
#: fields.py:1283
msgid "This selection may not be empty."
msgstr ""
#: fields.py:1320
#, python-brace-format
msgid "\"{input}\" is not a valid path choice."
msgstr ""
#: fields.py:1339
msgid "No file was submitted."
msgstr ""
#: fields.py:1340
msgid ""
"The submitted data was not a file. Check the encoding type on the form."
msgstr ""
#: fields.py:1341
msgid "No filename could be determined."
msgstr ""
#: fields.py:1342
msgid "The submitted file is empty."
msgstr ""
#: fields.py:1343
#, python-brace-format
msgid ""
"Ensure this filename has at most {max_length} characters (it has {length})."
msgstr ""
#: fields.py:1391
msgid ""
"Upload a valid image. The file you uploaded was either not an image or a "
"corrupted image."
msgstr ""
#: fields.py:1430 relations.py:428 serializers.py:521
msgid "This list may not be empty."
msgstr ""
#: fields.py:1483
#, python-brace-format
msgid "Expected a dictionary of items but got type \"{input_type}\"."
msgstr ""
#: fields.py:1530
msgid "Value must be valid JSON."
msgstr ""
#: filters.py:35 templates/rest_framework/filters/django_filter.html:5
msgid "Submit"
msgstr ""
#: pagination.py:189
#, python-brace-format
msgid "Invalid page \"{page_number}\": {message}."
msgstr ""
#: pagination.py:407
msgid "Invalid cursor"
msgstr ""
#: relations.py:196
#, python-brace-format
msgid "Invalid pk \"{pk_value}\" - object does not exist."
msgstr ""
#: relations.py:197
#, python-brace-format
msgid "Incorrect type. Expected pk value, received {data_type}."
msgstr ""
#: relations.py:229
msgid "Invalid hyperlink - No URL match."
msgstr ""
#: relations.py:230
msgid "Invalid hyperlink - Incorrect URL match."
msgstr ""
#: relations.py:231
msgid "Invalid hyperlink - Object does not exist."
msgstr ""
#: relations.py:232
#, python-brace-format
msgid "Incorrect type. Expected URL string, received {data_type}."
msgstr ""
#: relations.py:391
#, python-brace-format
msgid "Object with {slug_name}={value} does not exist."
msgstr ""
#: relations.py:392
msgid "Invalid value."
msgstr ""
#: serializers.py:326
#, python-brace-format
msgid "Invalid data. Expected a dictionary, but got {datatype}."
msgstr ""
#: templates/rest_framework/admin.html:118
#: templates/rest_framework/base.html:128
msgid "Filters"
msgstr ""
#: templates/rest_framework/filters/django_filter.html:2
#: templates/rest_framework/filters/django_filter_crispyforms.html:4
msgid "Field filters"
msgstr ""
#: templates/rest_framework/filters/ordering.html:3
msgid "Ordering"
msgstr ""
#: templates/rest_framework/filters/search.html:2
msgid "Search"
msgstr ""
#: templates/rest_framework/horizontal/radio.html:2
#: templates/rest_framework/inline/radio.html:2
#: templates/rest_framework/vertical/radio.html:2
msgid "None"
msgstr ""
#: templates/rest_framework/horizontal/select_multiple.html:2
#: templates/rest_framework/inline/select_multiple.html:2
#: templates/rest_framework/vertical/select_multiple.html:2
msgid "No items to select."
msgstr ""
#: validators.py:24
msgid "This field must be unique."
msgstr ""
#: validators.py:78
#, python-brace-format
msgid "The fields {field_names} must make a unique set."
msgstr ""
#: validators.py:226
#, python-brace-format
msgid "This field must be unique for the \"{date_field}\" date."
msgstr ""
#: validators.py:241
#, python-brace-format
msgid "This field must be unique for the \"{date_field}\" month."
msgstr ""
#: validators.py:254
#, python-brace-format
msgid "This field must be unique for the \"{date_field}\" year."
msgstr ""
#: versioning.py:42
msgid "Invalid version in \"Accept\" header."
msgstr ""
#: versioning.py:73 versioning.py:115
msgid "Invalid version in URL path."
msgstr ""
#: versioning.py:144
msgid "Invalid version in hostname."
msgstr ""
#: versioning.py:166
msgid "Invalid version in query parameter."
msgstr ""
#: views.py:88
msgid "Permission denied."
msgstr ""

View File

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-06-03 17:30+0100\n"
"POT-Creation-Date: 2015-12-07 18:53+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -17,23 +17,23 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: authentication.py:70
#: authentication.py:72
msgid "Invalid basic header. No credentials provided."
msgstr ""
#: authentication.py:73
#: authentication.py:75
msgid "Invalid basic header. Credentials string should not contain spaces."
msgstr ""
#: authentication.py:79
#: authentication.py:81
msgid "Invalid basic header. Credentials not correctly base64 encoded."
msgstr ""
#: authentication.py:97
#: authentication.py:98
msgid "Invalid username/password."
msgstr ""
#: authentication.py:100 authentication.py:182
#: authentication.py:101 authentication.py:188
msgid "User inactive or deleted."
msgstr ""
@ -45,7 +45,12 @@ msgstr ""
msgid "Invalid token header. Token string should not contain spaces."
msgstr ""
#: authentication.py:179
#: authentication.py:176
msgid ""
"Invalid token header. Token string should not contain invalid characters."
msgstr ""
#: authentication.py:185
msgid "Invalid token."
msgstr ""
@ -61,259 +66,307 @@ msgstr ""
msgid "Must include \"username\" and \"password\"."
msgstr ""
#: exceptions.py:38
#: exceptions.py:49
msgid "A server error occurred."
msgstr ""
#: exceptions.py:73
#: exceptions.py:84
msgid "Malformed request."
msgstr ""
#: exceptions.py:78
#: exceptions.py:89
msgid "Incorrect authentication credentials."
msgstr ""
#: exceptions.py:83
#: exceptions.py:94
msgid "Authentication credentials were not provided."
msgstr ""
#: exceptions.py:88
#: exceptions.py:99
msgid "You do not have permission to perform this action."
msgstr ""
#: exceptions.py:93 views.py:78
#: exceptions.py:104 views.py:81
msgid "Not found."
msgstr ""
#: exceptions.py:98
#: exceptions.py:109
#, python-brace-format
msgid "Method \"{method}\" not allowed."
msgstr ""
#: exceptions.py:109
#: exceptions.py:120
msgid "Could not satisfy the request Accept header."
msgstr ""
#: exceptions.py:121
#: exceptions.py:132
#, python-brace-format
msgid "Unsupported media type \"{media_type}\" in request."
msgstr ""
#: exceptions.py:134
#: exceptions.py:145
msgid "Request was throttled."
msgstr ""
#: fields.py:162 relations.py:132 relations.py:156 validators.py:77
#: validators.py:160
#: fields.py:266 relations.py:195 relations.py:228 validators.py:79
#: validators.py:162
msgid "This field is required."
msgstr ""
#: fields.py:163
#: fields.py:267
msgid "This field may not be null."
msgstr ""
#: fields.py:496 fields.py:524
#: fields.py:603 fields.py:634
#, python-brace-format
msgid "\"{input}\" is not a valid boolean."
msgstr ""
#: fields.py:559
#: fields.py:669
msgid "This field may not be blank."
msgstr ""
#: fields.py:560 fields.py:1386
#: fields.py:670 fields.py:1656
#, python-brace-format
msgid "Ensure this field has no more than {max_length} characters."
msgstr ""
#: fields.py:561
#: fields.py:671
#, python-brace-format
msgid "Ensure this field has at least {min_length} characters."
msgstr ""
#: fields.py:598
#: fields.py:708
msgid "Enter a valid email address."
msgstr ""
#: fields.py:609
#: fields.py:719
msgid "This value does not match the required pattern."
msgstr ""
#: fields.py:620
#: fields.py:730
msgid ""
"Enter a valid \"slug\" consisting of letters, numbers, underscores or "
"hyphens."
msgstr ""
#: fields.py:632
#: fields.py:742
msgid "Enter a valid URL."
msgstr ""
#: fields.py:645
#: fields.py:755
#, python-brace-format
msgid "\"{value}\" is not a valid UUID."
msgstr ""
#: fields.py:679
#: fields.py:791
msgid "Enter a valid IPv4 or IPv6 address."
msgstr ""
#: fields.py:816
msgid "A valid integer is required."
msgstr ""
#: fields.py:680 fields.py:715 fields.py:748
#: fields.py:817 fields.py:852 fields.py:885
#, python-brace-format
msgid "Ensure this value is less than or equal to {max_value}."
msgstr ""
#: fields.py:681 fields.py:716 fields.py:749
#: fields.py:818 fields.py:853 fields.py:886
#, python-brace-format
msgid "Ensure this value is greater than or equal to {min_value}."
msgstr ""
#: fields.py:682 fields.py:717 fields.py:753
#: fields.py:819 fields.py:854 fields.py:890
msgid "String value too large."
msgstr ""
#: fields.py:714 fields.py:747
#: fields.py:851 fields.py:884
msgid "A valid number is required."
msgstr ""
#: fields.py:750
#: fields.py:887
#, python-brace-format
msgid "Ensure that there are no more than {max_digits} digits in total."
msgstr ""
#: fields.py:751
#: fields.py:888
#, python-brace-format
msgid "Ensure that there are no more than {max_decimal_places} decimal places."
msgstr ""
#: fields.py:752
#: fields.py:889
#, python-brace-format
msgid ""
"Ensure that there are no more than {max_whole_digits} digits before the "
"decimal point."
msgstr ""
#: fields.py:842
#: fields.py:1004
#, python-brace-format
msgid "Datetime has wrong format. Use one of these formats instead: {format}."
msgstr ""
#: fields.py:843
#: fields.py:1005
msgid "Expected a datetime but got a date."
msgstr ""
#: fields.py:907
#: fields.py:1079
#, python-brace-format
msgid "Date has wrong format. Use one of these formats instead: {format}."
msgstr ""
#: fields.py:908
#: fields.py:1080
msgid "Expected a date but got a datetime."
msgstr ""
#: fields.py:971
#: fields.py:1148
#, python-brace-format
msgid "Time has wrong format. Use one of these formats instead: {format}."
msgstr ""
#: fields.py:1025
#: fields.py:1207
#, python-brace-format
msgid "Duration has wrong format. Use one of these formats instead: {format}."
msgstr ""
#: fields.py:1050 fields.py:1094
#: fields.py:1232 fields.py:1281
#, python-brace-format
msgid "\"{input}\" is not a valid choice."
msgstr ""
#: fields.py:1095 fields.py:1213 serializers.py:487
#: fields.py:1235 relations.py:62 relations.py:431
#, python-brace-format
msgid "More than {count} items..."
msgstr ""
#: fields.py:1282 fields.py:1429 relations.py:427 serializers.py:520
#, python-brace-format
msgid "Expected a list of items but got type \"{input_type}\"."
msgstr ""
#: fields.py:1129
#: fields.py:1283
msgid "This selection may not be empty."
msgstr ""
#: fields.py:1320
#, python-brace-format
msgid "\"{input}\" is not a valid path choice."
msgstr ""
#: fields.py:1339
msgid "No file was submitted."
msgstr ""
#: fields.py:1130
#: fields.py:1340
msgid "The submitted data was not a file. Check the encoding type on the form."
msgstr ""
#: fields.py:1131
#: fields.py:1341
msgid "No filename could be determined."
msgstr ""
#: fields.py:1132
#: fields.py:1342
msgid "The submitted file is empty."
msgstr ""
#: fields.py:1133
#: fields.py:1343
#, python-brace-format
msgid ""
"Ensure this filename has at most {max_length} characters (it has {length})."
msgstr ""
#: fields.py:1175
#: fields.py:1391
msgid ""
"Upload a valid image. The file you uploaded was either not an image or a "
"corrupted image."
msgstr ""
#: fields.py:1250
#: fields.py:1430 relations.py:428 serializers.py:521
msgid "This list may not be empty."
msgstr ""
#: fields.py:1483
#, python-brace-format
msgid "Expected a dictionary of items but got type \"{input_type}\"."
msgstr ""
#: pagination.py:231
#: fields.py:1530
msgid "Value must be valid JSON."
msgstr ""
#: filters.py:35 templates/rest_framework/filters/django_filter.html:5
msgid "Submit"
msgstr ""
#: pagination.py:189
#, python-brace-format
msgid "Invalid page \"{page_number}\": {message}."
msgstr ""
#: pagination.py:492
#: pagination.py:407
msgid "Invalid cursor"
msgstr ""
#: relations.py:133
#: relations.py:196
#, python-brace-format
msgid "Invalid pk \"{pk_value}\" - object does not exist."
msgstr ""
#: relations.py:134
#: relations.py:197
#, python-brace-format
msgid "Incorrect type. Expected pk value, received {data_type}."
msgstr ""
#: relations.py:157
#: relations.py:229
msgid "Invalid hyperlink - No URL match."
msgstr ""
#: relations.py:158
#: relations.py:230
msgid "Invalid hyperlink - Incorrect URL match."
msgstr ""
#: relations.py:159
#: relations.py:231
msgid "Invalid hyperlink - Object does not exist."
msgstr ""
#: relations.py:160
#: relations.py:232
#, python-brace-format
msgid "Incorrect type. Expected URL string, received {data_type}."
msgstr ""
#: relations.py:302
#: relations.py:391
#, python-brace-format
msgid "Object with {slug_name}={value} does not exist."
msgstr ""
#: relations.py:303
#: relations.py:392
msgid "Invalid value."
msgstr ""
#: serializers.py:304
#: serializers.py:326
#, python-brace-format
msgid "Invalid data. Expected a dictionary, but got {datatype}."
msgstr ""
#: templates/rest_framework/admin.html:118
#: templates/rest_framework/base.html:128
msgid "Filters"
msgstr ""
#: templates/rest_framework/filters/django_filter.html:2
#: templates/rest_framework/filters/django_filter_crispyforms.html:4
msgid "Field filters"
msgstr ""
#: templates/rest_framework/filters/ordering.html:3
msgid "Ordering"
msgstr ""
#: templates/rest_framework/filters/search.html:2
msgid "Search"
msgstr ""
#: templates/rest_framework/horizontal/radio.html:2
#: templates/rest_framework/inline/radio.html:2
#: templates/rest_framework/vertical/radio.html:2
@ -326,46 +379,46 @@ msgstr ""
msgid "No items to select."
msgstr ""
#: validators.py:22
#: validators.py:24
msgid "This field must be unique."
msgstr ""
#: validators.py:76
#: validators.py:78
#, python-brace-format
msgid "The fields {field_names} must make a unique set."
msgstr ""
#: validators.py:224
#: validators.py:226
#, python-brace-format
msgid "This field must be unique for the \"{date_field}\" date."
msgstr ""
#: validators.py:239
#: validators.py:241
#, python-brace-format
msgid "This field must be unique for the \"{date_field}\" month."
msgstr ""
#: validators.py:252
#: validators.py:254
#, python-brace-format
msgid "This field must be unique for the \"{date_field}\" year."
msgstr ""
#: versioning.py:39
#: versioning.py:42
msgid "Invalid version in \"Accept\" header."
msgstr ""
#: versioning.py:70 versioning.py:112
#: versioning.py:73 versioning.py:115
msgid "Invalid version in URL path."
msgstr ""
#: versioning.py:141
#: versioning.py:144
msgid "Invalid version in hostname."
msgstr ""
#: versioning.py:163
#: versioning.py:166
msgid "Invalid version in query parameter."
msgstr ""
#: views.py:85
#: views.py:88
msgid "Permission denied."
msgstr ""

View File

@ -6,38 +6,39 @@
# nnrcschmdt <e.rico.schmidt@gmail.com>, 2015
# José Padilla <jpadilla@webapplicate.com>, 2015
# Miguel González <migonzalvar@gmail.com>, 2015
# Miguel González <migonzalvar@gmail.com>, 2015
# Sergio Infante <rsinfante@gmail.com>, 2015
msgid ""
msgstr ""
"Project-Id-Version: Django REST framework\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-06-03 17:30+0100\n"
"PO-Revision-Date: 2015-06-03 16:30+0000\n"
"Last-Translator: Xavier Ordoquy <xordoquy@linovia.com>\n"
"Language-Team: Spanish (http://www.transifex.com/projects/p/django-rest-framework/language/es/)\n"
"POT-Creation-Date: 2015-12-07 18:53+0100\n"
"PO-Revision-Date: 2015-12-08 15:54+0000\n"
"Last-Translator: Miguel González <migonzalvar@gmail.com>\n"
"Language-Team: Spanish (http://www.transifex.com/django-rest-framework-1/django-rest-framework/language/es/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: es\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: authentication.py:70
#: authentication.py:72
msgid "Invalid basic header. No credentials provided."
msgstr "Cabecera básica inválida. Las credenciales no fueron suministradas."
#: authentication.py:73
#: authentication.py:75
msgid "Invalid basic header. Credentials string should not contain spaces."
msgstr "Cabecera básica inválida. La cadena con las credenciales no debe contener espacios."
#: authentication.py:79
#: authentication.py:81
msgid "Invalid basic header. Credentials not correctly base64 encoded."
msgstr "Cabecera básica inválida. Las credenciales incorrectamente codificadas en base64."
#: authentication.py:97
#: authentication.py:98
msgid "Invalid username/password."
msgstr "Nombre de usuario/contraseña inválidos."
#: authentication.py:100 authentication.py:182
#: authentication.py:101 authentication.py:188
msgid "User inactive or deleted."
msgstr "Usuario inactivo o borrado."
@ -49,7 +50,12 @@ msgstr "Cabecera token inválida. Las credenciales no fueron suministradas."
msgid "Invalid token header. Token string should not contain spaces."
msgstr "Cabecera token inválida. La cadena token no debe contener espacios."
#: authentication.py:179
#: authentication.py:176
msgid ""
"Invalid token header. Token string should not contain invalid characters."
msgstr "Cabecera token inválida. La cadena token no debe contener caracteres inválidos."
#: authentication.py:185
msgid "Invalid token."
msgstr "Token inválido."
@ -65,261 +71,309 @@ msgstr "No puede iniciar sesión con las credenciales proporcionadas."
msgid "Must include \"username\" and \"password\"."
msgstr "Debe incluir \"username\" y \"password\"."
#: exceptions.py:38
#: exceptions.py:49
msgid "A server error occurred."
msgstr "Se ha producido un error en el servidor."
#: exceptions.py:73
#: exceptions.py:84
msgid "Malformed request."
msgstr "Solicitud con formato incorrecto."
#: exceptions.py:78
#: exceptions.py:89
msgid "Incorrect authentication credentials."
msgstr "Credenciales de autenticación incorrectas."
#: exceptions.py:83
#: exceptions.py:94
msgid "Authentication credentials were not provided."
msgstr "Las credenciales de autenticación no se proveyeron."
#: exceptions.py:88
#: exceptions.py:99
msgid "You do not have permission to perform this action."
msgstr "Usted no tiene permiso para realizar esta acción."
#: exceptions.py:93 views.py:78
#: exceptions.py:104 views.py:81
msgid "Not found."
msgstr "No encontrado."
#: exceptions.py:98
#: exceptions.py:109
#, python-brace-format
msgid "Method \"{method}\" not allowed."
msgstr "Método \"{method}\" no permitido."
#: exceptions.py:109
#: exceptions.py:120
msgid "Could not satisfy the request Accept header."
msgstr "No se ha podido satisfacer la solicitud de cabecera de Accept."
#: exceptions.py:121
#: exceptions.py:132
#, python-brace-format
msgid "Unsupported media type \"{media_type}\" in request."
msgstr "Tipo de medio \"{media_type}\" incompatible en la solicitud."
#: exceptions.py:134
#: exceptions.py:145
msgid "Request was throttled."
msgstr "Solicitud fue regulada (throttled)."
#: fields.py:162 relations.py:132 relations.py:156 validators.py:77
#: validators.py:160
#: fields.py:266 relations.py:195 relations.py:228 validators.py:79
#: validators.py:162
msgid "This field is required."
msgstr "Este campo es requerido."
#: fields.py:163
#: fields.py:267
msgid "This field may not be null."
msgstr "Este campo no puede ser nulo."
#: fields.py:496 fields.py:524
#: fields.py:603 fields.py:634
#, python-brace-format
msgid "\"{input}\" is not a valid boolean."
msgstr "\"{input}\" no es un booleano válido."
#: fields.py:559
#: fields.py:669
msgid "This field may not be blank."
msgstr "Este campo no puede estar en blanco."
#: fields.py:560 fields.py:1386
#: fields.py:670 fields.py:1656
#, python-brace-format
msgid "Ensure this field has no more than {max_length} characters."
msgstr "Asegúrese de que este campo no tenga más de {max_length} caracteres."
#: fields.py:561
#: fields.py:671
#, python-brace-format
msgid "Ensure this field has at least {min_length} characters."
msgstr "Asegúrese de que este campo tenga al menos {min_length} caracteres."
#: fields.py:598
#: fields.py:708
msgid "Enter a valid email address."
msgstr "Introduzca una dirección de correo electrónico válida."
#: fields.py:609
#: fields.py:719
msgid "This value does not match the required pattern."
msgstr "Este valor no coincide con el patrón requerido."
#: fields.py:620
#: fields.py:730
msgid ""
"Enter a valid \"slug\" consisting of letters, numbers, underscores or "
"hyphens."
msgstr "Introduzca un \"slug\" válido consistente en letras, números, guiones o guiones bajos."
#: fields.py:632
#: fields.py:742
msgid "Enter a valid URL."
msgstr "Introduzca una URL válida."
#: fields.py:645
#: fields.py:755
#, python-brace-format
msgid "\"{value}\" is not a valid UUID."
msgstr "\"{value}\" no es un UUID válido."
#: fields.py:679
#: fields.py:791
msgid "Enter a valid IPv4 or IPv6 address."
msgstr "Introduzca una dirección IPv4 o IPv6 válida."
#: fields.py:816
msgid "A valid integer is required."
msgstr "Introduzca un número entero válido."
#: fields.py:680 fields.py:715 fields.py:748
#: fields.py:817 fields.py:852 fields.py:885
#, python-brace-format
msgid "Ensure this value is less than or equal to {max_value}."
msgstr "Asegúrese de que este valor es menor o igual a {max_value}."
#: fields.py:681 fields.py:716 fields.py:749
#: fields.py:818 fields.py:853 fields.py:886
#, python-brace-format
msgid "Ensure this value is greater than or equal to {min_value}."
msgstr "Asegúrese de que este valor es mayor o igual a {min_value}."
#: fields.py:682 fields.py:717 fields.py:753
#: fields.py:819 fields.py:854 fields.py:890
msgid "String value too large."
msgstr "Cadena demasiado larga."
#: fields.py:714 fields.py:747
#: fields.py:851 fields.py:884
msgid "A valid number is required."
msgstr "Se requiere un número válido."
#: fields.py:750
#: fields.py:887
#, python-brace-format
msgid "Ensure that there are no more than {max_digits} digits in total."
msgstr "Asegúrese de que no haya más de {max_digits} dígitos en total."
#: fields.py:751
#: fields.py:888
#, python-brace-format
msgid ""
"Ensure that there are no more than {max_decimal_places} decimal places."
msgstr "Asegúrese de que no haya más de {max_decimal_places} decimales."
#: fields.py:752
#: fields.py:889
#, python-brace-format
msgid ""
"Ensure that there are no more than {max_whole_digits} digits before the "
"decimal point."
msgstr "Asegúrese de que no haya más de {max_whole_digits} dígitos en la parte entera."
#: fields.py:842
#: fields.py:1004
#, python-brace-format
msgid "Datetime has wrong format. Use one of these formats instead: {format}."
msgstr "Fecha/hora con formato erróneo. Use uno de los siguientes formatos en su lugar: {format}."
#: fields.py:843
#: fields.py:1005
msgid "Expected a datetime but got a date."
msgstr "Se esperaba un fecha/hora en vez de una fecha."
#: fields.py:907
#: fields.py:1079
#, python-brace-format
msgid "Date has wrong format. Use one of these formats instead: {format}."
msgstr "Fecha con formato erróneo. Use uno de los siguientes formatos en su lugar: {format}."
#: fields.py:908
#: fields.py:1080
msgid "Expected a date but got a datetime."
msgstr "Se esperaba una fecha en vez de una fecha/hora."
#: fields.py:971
#: fields.py:1148
#, python-brace-format
msgid "Time has wrong format. Use one of these formats instead: {format}."
msgstr "Hora con formato erróneo. Use uno de los siguientes formatos en su lugar: {format}."
#: fields.py:1025
#: fields.py:1207
#, python-brace-format
msgid "Duration has wrong format. Use one of these formats instead: {format}."
msgstr ""
msgstr "Duración con formato erróneo. Use uno de los siguientes formatos en su lugar: {format}."
#: fields.py:1050 fields.py:1094
#: fields.py:1232 fields.py:1281
#, python-brace-format
msgid "\"{input}\" is not a valid choice."
msgstr "\"{input}\" no es una elección válida."
#: fields.py:1095 fields.py:1213 serializers.py:487
#: fields.py:1235 relations.py:62 relations.py:431
#, python-brace-format
msgid "More than {count} items..."
msgstr "Más de {count} elementos..."
#: fields.py:1282 fields.py:1429 relations.py:427 serializers.py:520
#, python-brace-format
msgid "Expected a list of items but got type \"{input_type}\"."
msgstr "Se esperaba una lista de elementos en vez del tipo \"{input_type}\"."
#: fields.py:1129
#: fields.py:1283
msgid "This selection may not be empty."
msgstr "Esta selección no puede estar vacía."
#: fields.py:1320
#, python-brace-format
msgid "\"{input}\" is not a valid path choice."
msgstr "\"{input}\" no es una elección de ruta válida."
#: fields.py:1339
msgid "No file was submitted."
msgstr "No se envió ningún archivo."
#: fields.py:1130
#: fields.py:1340
msgid ""
"The submitted data was not a file. Check the encoding type on the form."
msgstr "La información enviada no era un archivo. Compruebe el tipo de codificación del formulario."
#: fields.py:1131
#: fields.py:1341
msgid "No filename could be determined."
msgstr "No se pudo determinar un nombre de archivo."
#: fields.py:1132
#: fields.py:1342
msgid "The submitted file is empty."
msgstr "El archivo enviado está vació."
#: fields.py:1133
#: fields.py:1343
#, python-brace-format
msgid ""
"Ensure this filename has at most {max_length} characters (it has {length})."
msgstr "Asegúrese de que el nombre de archivo no tenga más de {max_length} caracteres (tiene {length})."
#: fields.py:1175
#: fields.py:1391
msgid ""
"Upload a valid image. The file you uploaded was either not an image or a "
"corrupted image."
msgstr "Adjunte una imagen válida. El archivo adjunto o bien no es una imagen o bien está dañado."
#: fields.py:1250
#: fields.py:1430 relations.py:428 serializers.py:521
msgid "This list may not be empty."
msgstr "Esta lista no puede estar vacía."
#: fields.py:1483
#, python-brace-format
msgid "Expected a dictionary of items but got type \"{input_type}\"."
msgstr "Se esperaba un diccionario de elementos en vez del tipo \"{input_type}\"."
#: pagination.py:231
#: fields.py:1530
msgid "Value must be valid JSON."
msgstr "El valor debe ser JSON válido."
#: filters.py:35 templates/rest_framework/filters/django_filter.html:5
msgid "Submit"
msgstr "Enviar"
#: pagination.py:189
#, python-brace-format
msgid "Invalid page \"{page_number}\": {message}."
msgstr "Página \"{page_number}\" inválida: {message}."
#: pagination.py:492
#: pagination.py:407
msgid "Invalid cursor"
msgstr "Cursor inválido"
#: relations.py:133
#: relations.py:196
#, python-brace-format
msgid "Invalid pk \"{pk_value}\" - object does not exist."
msgstr "Clave primaria \"{pk_value}\" inválida - objeto no existe."
#: relations.py:134
#: relations.py:197
#, python-brace-format
msgid "Incorrect type. Expected pk value, received {data_type}."
msgstr "Tipo incorrecto. Se esperaba valor de clave primaria y se recibió {data_type}."
#: relations.py:157
#: relations.py:229
msgid "Invalid hyperlink - No URL match."
msgstr "Hiperenlace inválido - No hay URL coincidentes."
#: relations.py:158
#: relations.py:230
msgid "Invalid hyperlink - Incorrect URL match."
msgstr "Hiperenlace inválido - Coincidencia incorrecta de la URL."
#: relations.py:159
#: relations.py:231
msgid "Invalid hyperlink - Object does not exist."
msgstr "Hiperenlace inválido - Objeto no existe."
#: relations.py:160
#: relations.py:232
#, python-brace-format
msgid "Incorrect type. Expected URL string, received {data_type}."
msgstr "Tipo incorrecto. Se esperaba una URL y se recibió {data_type}."
#: relations.py:302
#: relations.py:391
#, python-brace-format
msgid "Object with {slug_name}={value} does not exist."
msgstr "Objeto con {slug_name}={value} no existe."
#: relations.py:303
#: relations.py:392
msgid "Invalid value."
msgstr "Valor inválido."
#: serializers.py:304
#: serializers.py:326
#, python-brace-format
msgid "Invalid data. Expected a dictionary, but got {datatype}."
msgstr "Datos inválidos. Se esperaba un diccionario pero es un {datatype}."
#: templates/rest_framework/admin.html:118
#: templates/rest_framework/base.html:128
msgid "Filters"
msgstr "Filtros"
#: templates/rest_framework/filters/django_filter.html:2
#: templates/rest_framework/filters/django_filter_crispyforms.html:4
msgid "Field filters"
msgstr "Filtros de campo"
#: templates/rest_framework/filters/ordering.html:3
msgid "Ordering"
msgstr "Ordenamiento"
#: templates/rest_framework/filters/search.html:2
msgid "Search"
msgstr "Buscar"
#: templates/rest_framework/horizontal/radio.html:2
#: templates/rest_framework/inline/radio.html:2
#: templates/rest_framework/vertical/radio.html:2
@ -332,46 +386,46 @@ msgstr "Ninguno"
msgid "No items to select."
msgstr "No hay elementos para seleccionar."
#: validators.py:22
#: validators.py:24
msgid "This field must be unique."
msgstr "Este campo debe ser único."
#: validators.py:76
#: validators.py:78
#, python-brace-format
msgid "The fields {field_names} must make a unique set."
msgstr "Los campos {field_names} deben formar un conjunto único."
#: validators.py:224
#: validators.py:226
#, python-brace-format
msgid "This field must be unique for the \"{date_field}\" date."
msgstr "Este campo debe ser único para el día \"{date_field}\"."
#: validators.py:239
#: validators.py:241
#, python-brace-format
msgid "This field must be unique for the \"{date_field}\" month."
msgstr "Este campo debe ser único para el mes \"{date_field}\"."
#: validators.py:252
#: validators.py:254
#, python-brace-format
msgid "This field must be unique for the \"{date_field}\" year."
msgstr "Este campo debe ser único para el año \"{date_field}\"."
#: versioning.py:39
#: versioning.py:42
msgid "Invalid version in \"Accept\" header."
msgstr "Versión inválida en la cabecera \"Accept\"."
#: versioning.py:70 versioning.py:112
#: versioning.py:73 versioning.py:115
msgid "Invalid version in URL path."
msgstr "Versión inválida en la ruta de la URL."
#: versioning.py:141
#: versioning.py:144
msgid "Invalid version in hostname."
msgstr "Versión inválida en el nombre de host."
#: versioning.py:163
#: versioning.py:166
msgid "Invalid version in query parameter."
msgstr "Versión inválida en el parámetro de consulta."
#: views.py:85
#: views.py:88
msgid "Permission denied."
msgstr "Permiso denegado."

Some files were not shown because too many files have changed in this diff Show More