|
@ -14,3 +14,4 @@ MANIFEST
|
|||
|
||||
!.gitignore
|
||||
!.travis.yml
|
||||
!.isort.cfg
|
||||
|
|
|
@ -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
|
31
.travis.yml
|
@ -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
|
||||
|
|
|
@ -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?
|
||||
|
|
17
README.md
|
@ -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 you’ve 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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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/
|
||||
|
|
|
@ -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 = ''
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
||||
---
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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')
|
||||
|
||||
---
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ source: versioning.py
|
|||
# Versioning
|
||||
|
||||
> Versioning an interface is just a "polite" way to kill deployed clients.
|
||||
>
|
||||
>
|
||||
> — [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'
|
||||
)
|
||||
|
|
|
@ -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()
|
||||
|
|
After Width: | Height: | Size: 55 KiB |
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 47 KiB |
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 8.1 KiB |
After Width: | Height: | Size: 18 KiB |
After Width: | Height: | Size: 8.9 KiB |
After Width: | Height: | Size: 12 KiB |
|
@ -1,17 +1,18 @@
|
|||
<p class="badges" height=20px>
|
||||
<iframe src="http://ghbtns.com/github-btn.html?user=tomchristie&repo=django-rest-framework&type=watch&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&repo=django-rest-framework&type=watch&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/
|
||||
|
|
|
@ -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.
|
||||
|
||||
---
|
||||
|
||||
|
|
|
@ -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.
|
|
@ -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
|
|
@ -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.
|
||||
|
|
|
@ -4,58 +4,36 @@
|
|||
>
|
||||
> — [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
|
||||
|
|
|
@ -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 improve.
|
||||
|
||||
If you are using REST framework as an full-time employee, consider recommending that your company takes out a [corporate 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 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 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.
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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`...
|
||||
|
|
|
@ -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">« previous</a>
|
||||
<a class="btn btn-mini btn-primary" style="float: right; margin-right: 8px; width: 60px;">next »</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>
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
# PyTest for running the tests.
|
||||
pytest==2.6.4
|
||||
pytest-django==2.8.0
|
||||
pytest-cov==1.8.1
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
from django.contrib import admin
|
||||
|
||||
from rest_framework.authtoken.models import Token
|
||||
|
||||
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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']
|
|
@ -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']
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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):
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
||||
|
|
|
@ -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')
|
||||
"""
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -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 ""
|
|
@ -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 ""
|
||||
|
|
|
@ -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 ""
|
||||
|
|
|
@ -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."
|
|
@ -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 ""
|
|
@ -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 ""
|
||||
|
|
|
@ -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."
|
||||
|
|
|
@ -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 ""
|
|
@ -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."
|
||||
|
|
|
@ -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."
|
||||
|
|
|
@ -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 ""
|
|
@ -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 ""
|
|
@ -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 ""
|
||||
|
|
|
@ -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."
|
||||
|
|