mirror of
https://github.com/encode/django-rest-framework.git
synced 2024-11-11 04:07:39 +03:00
Merge branch 'master' of github.com:tomchristie/django-rest-framework
This commit is contained in:
commit
0a91999d6a
|
@ -1,4 +1,4 @@
|
||||||
<a class="github" href="validators.py"></a>
|
source: validators.py
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,8 @@
|
||||||
|
|
||||||
**Note**: This is the documentation for the **version 3.0** of REST framework. Documentation for [version 2.4](http://tomchristie.github.io/rest-framework-2-docs/) is also available.
|
**Note**: This is the documentation for the **version 3.0** 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.0 release notes][3.0-announcement].
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
|
@ -201,6 +203,7 @@ General guides to using REST framework.
|
||||||
* [2.2 Announcement][2.2-announcement]
|
* [2.2 Announcement][2.2-announcement]
|
||||||
* [2.3 Announcement][2.3-announcement]
|
* [2.3 Announcement][2.3-announcement]
|
||||||
* [2.4 Announcement][2.4-announcement]
|
* [2.4 Announcement][2.4-announcement]
|
||||||
|
* [3.0 Announcement][3.0-announcement]
|
||||||
* [Kickstarter Announcement][kickstarter-announcement]
|
* [Kickstarter Announcement][kickstarter-announcement]
|
||||||
* [Release Notes][release-notes]
|
* [Release Notes][release-notes]
|
||||||
* [Credits][credits]
|
* [Credits][credits]
|
||||||
|
@ -319,6 +322,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
[2.2-announcement]: topics/2.2-announcement.md
|
[2.2-announcement]: topics/2.2-announcement.md
|
||||||
[2.3-announcement]: topics/2.3-announcement.md
|
[2.3-announcement]: topics/2.3-announcement.md
|
||||||
[2.4-announcement]: topics/2.4-announcement.md
|
[2.4-announcement]: topics/2.4-announcement.md
|
||||||
|
[3.0-announcement]: topics/3.0-announcement.md
|
||||||
[kickstarter-announcement]: topics/kickstarter-announcement.md
|
[kickstarter-announcement]: topics/kickstarter-announcement.md
|
||||||
[release-notes]: topics/release-notes.md
|
[release-notes]: topics/release-notes.md
|
||||||
[credits]: topics/credits.md
|
[credits]: topics/credits.md
|
||||||
|
|
|
@ -1,14 +1,16 @@
|
||||||
# REST framework 3.0
|
# Django REST framework 3.0
|
||||||
|
|
||||||
The 3.0 release of Django REST framework is the result of almost four years of iteration and refinement. It comprehensively addresses some of the previous remaining design issues in serializers, fields and the generic views.
|
The 3.0 release of Django REST framework is the result of almost four years of iteration and refinement. It comprehensively addresses some of the previous remaining design issues in serializers, fields and the generic views.
|
||||||
|
|
||||||
This release is incremental in nature. There *are* some breaking API changes, and upgrading *will* require you to read the release notes carefully, but the migration path should otherwise be relatively straightforward.
|
**This release is incremental in nature. There *are* some breaking API changes, and upgrading *will* require you to read the release notes carefully, but the migration path should otherwise be relatively straightforward.**
|
||||||
|
|
||||||
The difference in quality of the REST framework API and implementation should make writing, maintaining and debugging your application far easier.
|
The difference in quality of the REST framework API and implementation should make writing, maintaining and debugging your application far easier.
|
||||||
|
|
||||||
3.0 is the first of three releases that have been funded by our recent [Kickstarter campaign](kickstarter.com/projects/tomchristie/django-rest-framework-3).
|
3.0 is the first of three releases that have been funded by our recent [Kickstarter campaign][kickstarter].
|
||||||
|
|
||||||
As ever, a huge thank you to our many [wonderful sponsors](sponsors). If you're looking for a Django gig, and want to work with smart community-minded folks, you should probably check out that list and see who's hiring.
|
As ever, a huge thank you to our many [wonderful sponsors][sponsors]. If you're looking for a Django gig, and want to work with smart community-minded folks, you should probably check out that list and see who's hiring.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## New features
|
## New features
|
||||||
|
|
||||||
|
@ -51,6 +53,8 @@ Instead of passing the files argument separately:
|
||||||
|
|
||||||
The usage of `request.QUERY_PARAMS` is now pending deprecation in favor of the lowercased `request.query_params`.
|
The usage of `request.QUERY_PARAMS` is now pending deprecation in favor of the lowercased `request.query_params`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Serializers
|
## Serializers
|
||||||
|
|
||||||
#### Single-step object creation.
|
#### Single-step object creation.
|
||||||
|
@ -149,7 +153,7 @@ Previously `serializers.ValidationError` error was simply a synonym for `django.
|
||||||
|
|
||||||
The reason behind this is that Django's `ValidationError` class is intended for use with HTML forms and its API makes using it slightly awkward with nested validation errors that can occur in serializers.
|
The reason behind this is that Django's `ValidationError` class is intended for use with HTML forms and its API makes using it slightly awkward with nested validation errors that can occur in serializers.
|
||||||
|
|
||||||
For most users this change shouldn't require any updates to your codebase, but it is worth ensuring that whenever raising validation errors you are always using the `serializers.ValidationError` exception class, and not Django's built-in exception.
|
For most users this change shouldn't require any updates to your codebase, but it is worth ensuring that whenever raising validation errors you should prefer using the `serializers.ValidationError` exception class, and not Django's built-in exception.
|
||||||
|
|
||||||
We strongly recommend that you use the namespaced import style of `import serializers` and not `from serializers import ValidationError` in order to avoid any potential confusion.
|
We strongly recommend that you use the namespaced import style of `import serializers` and not `from serializers import ValidationError` in order to avoid any potential confusion.
|
||||||
|
|
||||||
|
@ -218,7 +222,18 @@ If you absolutely need to preserve `transform_<field_name>` behavior, for exampl
|
||||||
|
|
||||||
This change also means that we no longer use the `.full_clean()` method on model instances, but instead perform all validation explicitly on the serializer. This gives a cleaner separation, and ensures that there's no automatic validation behavior on `ModelSerializer` classes that can't also be easily replicated on regular `Serializer` classes.
|
This change also means that we no longer use the `.full_clean()` method on model instances, but instead perform all validation explicitly on the serializer. This gives a cleaner separation, and ensures that there's no automatic validation behavior on `ModelSerializer` classes that can't also be easily replicated on regular `Serializer` classes.
|
||||||
|
|
||||||
It's important to note that this change also means that the model `.clean()` method will not be called as part of serializer validation, as it would be if using a `ModelForm`. Use the serializer `.validate()` method to perform a final validation step on incoming data where required.
|
For the most part this change should be transparent. Field validation and uniqueness checks will still be run as normal, but the implementation is a little different.
|
||||||
|
|
||||||
|
The one difference that you do need to note is that the `.clean()` method will not be called as part of serializer validation, as it would be if using a `ModelForm`. Use the serializer `.validate()` method to perform a final validation step on incoming data where required.
|
||||||
|
|
||||||
|
There may be some cases where you really do need to keep validation logic in the model `.clean()` method, and cannot instead separate it into the serializer `.validate()`. You can do so by explicitly instantiating a model instance in the `.validate()` method.
|
||||||
|
|
||||||
|
def validate(self, attrs):
|
||||||
|
instance = ExampleModel(**attrs)
|
||||||
|
instance.clean()
|
||||||
|
return attrs
|
||||||
|
|
||||||
|
Again, you really should look at properly separating the validation logic out of the model method if possible, but the above might be useful in some backwards compatibility cases, or for an easy migration path.
|
||||||
|
|
||||||
#### Writable nested serialization.
|
#### Writable nested serialization.
|
||||||
|
|
||||||
|
@ -524,6 +539,8 @@ The following class is an example of a generic serializer that can handle coerci
|
||||||
# Force anything else to its string representation.
|
# Force anything else to its string representation.
|
||||||
output[attribute_name] = str(attribute)
|
output[attribute_name] = str(attribute)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Serializer fields
|
## Serializer fields
|
||||||
|
|
||||||
#### The `Field` and `ReadOnly` field classes.
|
#### The `Field` and `ReadOnly` field classes.
|
||||||
|
@ -540,22 +557,22 @@ We now use the following:
|
||||||
* `Field` is the base class for all fields. It does not include any default implementation for either serializing or deserializing data.
|
* `Field` is the base class for all fields. It does not include any default implementation for either serializing or deserializing data.
|
||||||
* `ReadOnlyField` is a concrete implementation for read-only fields that simply returns the attribute value without modification.
|
* `ReadOnlyField` is a concrete implementation for read-only fields that simply returns the attribute value without modification.
|
||||||
|
|
||||||
#### The `required`, `allow_none`, `allow_blank` and `default` arguments.
|
#### The `required`, `allow_null`, `allow_blank` and `default` arguments.
|
||||||
|
|
||||||
REST framework now has more explicit and clear control over validating empty values for fields.
|
REST framework now has more explicit and clear control over validating empty values for fields.
|
||||||
|
|
||||||
Previously the meaning of the `required=False` keyword argument was underspecified. In practice its use meant that a field could either be not included in the input, or it could be included, but be `None` or the empty string.
|
Previously the meaning of the `required=False` keyword argument was underspecified. In practice its use meant that a field could either be not included in the input, or it could be included, but be `None` or the empty string.
|
||||||
|
|
||||||
We now have a better separation, with separate `required`, `allow_none` and `allow_blank` arguments.
|
We now have a better separation, with separate `required`, `allow_null` and `allow_blank` arguments.
|
||||||
|
|
||||||
The following set of arguments are used to control validation of empty values:
|
The following set of arguments are used to control validation of empty values:
|
||||||
|
|
||||||
* `required=False`: The value does not need to be present in the input, and will not be passed to `.create()` or `.update()` if it is not seen.
|
* `required=False`: The value does not need to be present in the input, and will not be passed to `.create()` or `.update()` if it is not seen.
|
||||||
* `default=<value>`: The value does not need to be present in the input, and a default value will be passed to `.create()` or `.update()` if it is not seen.
|
* `default=<value>`: The value does not need to be present in the input, and a default value will be passed to `.create()` or `.update()` if it is not seen.
|
||||||
* `allow_none=True`: `None` is a valid input.
|
* `allow_null=True`: `None` is a valid input.
|
||||||
* `allow_blank=True`: `''` is valid input. For `CharField` and subclasses only.
|
* `allow_blank=True`: `''` is valid input. For `CharField` and subclasses only.
|
||||||
|
|
||||||
Typically you'll want to use `required=False` if the corresponding model field has a default value, and additionally set either `allow_none=True` or `allow_blank=True` if required.
|
Typically you'll want to use `required=False` if the corresponding model field has a default value, and additionally set either `allow_null=True` or `allow_blank=True` if required.
|
||||||
|
|
||||||
The `default` argument is also available and always implies that the field is not required to be in the input. It is unnecessary to use the `required` argument when a default is specified, and doing so will result in an error.
|
The `default` argument is also available and always implies that the field is not required to be in the input. It is unnecessary to use the `required` argument when a default is specified, and doing so will result in an error.
|
||||||
|
|
||||||
|
@ -710,10 +727,11 @@ The `UniqueTogetherValidator` should be applied to a serializer, and takes a `qu
|
||||||
position = serializers.IntegerField()
|
position = serializers.IntegerField()
|
||||||
name = serializers.CharField(max_length=100)
|
name = serializers.CharField(max_length=100)
|
||||||
|
|
||||||
default_validators = [UniqueTogetherValidator(
|
class Meta:
|
||||||
queryset=RaceResult.objects.all(),
|
validators = [UniqueTogetherValidator(
|
||||||
fields=('category', 'position')
|
queryset=RaceResult.objects.all(),
|
||||||
)]
|
fields=('category', 'position')
|
||||||
|
)]
|
||||||
|
|
||||||
#### The `UniqueForDateValidator` classes.
|
#### The `UniqueForDateValidator` classes.
|
||||||
|
|
||||||
|
@ -721,6 +739,8 @@ REST framework also now includes explicit validator classes for validating the `
|
||||||
|
|
||||||
These classes are documented in the [Validators](../api-guide/validators.md) section of the documentation.
|
These classes are documented in the [Validators](../api-guide/validators.md) section of the documentation.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Generic views
|
## Generic views
|
||||||
|
|
||||||
#### Simplification of view logic.
|
#### Simplification of view logic.
|
||||||
|
@ -769,12 +789,16 @@ The generic views now raise `ValidationFailed` exception for invalid data. This
|
||||||
|
|
||||||
This change means that you can now easily customize the style of error responses across your entire API, without having to modify any of the generic views.
|
This change means that you can now easily customize the style of error responses across your entire API, without having to modify any of the generic views.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## The metadata API
|
## The metadata API
|
||||||
|
|
||||||
Behavior for dealing with `OPTIONS` requests was previously built directly into the class based views. This has now been properly separated out into a Metadata API that allows the same pluggable style as other API policies in REST framework.
|
Behavior for dealing with `OPTIONS` requests was previously built directly into the class based views. This has now been properly separated out into a Metadata API that allows the same pluggable style as other API policies in REST framework.
|
||||||
|
|
||||||
This makes it far easier to use a different style for `OPTIONS` responses throughout your API, and makes it possible to create third-party metadata policies.
|
This makes it far easier to use a different style for `OPTIONS` responses throughout your API, and makes it possible to create third-party metadata policies.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Serializers as HTML forms
|
## Serializers as HTML forms
|
||||||
|
|
||||||
REST framework 3.0 includes templated HTML form rendering for serializers.
|
REST framework 3.0 includes templated HTML form rendering for serializers.
|
||||||
|
@ -806,6 +830,8 @@ Similarly, to use a radio button control instead of the default `select` control
|
||||||
|
|
||||||
This API should be considered provisional, and there may be minor alterations with the incoming 3.1 release.
|
This API should be considered provisional, and there may be minor alterations with the incoming 3.1 release.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## API style
|
## API style
|
||||||
|
|
||||||
There are some improvements in the default style we use in our API responses.
|
There are some improvements in the default style we use in our API responses.
|
||||||
|
@ -899,12 +925,16 @@ Or modify it on an individual serializer field, using the `coerce_to_string` key
|
||||||
|
|
||||||
The default JSON renderer will return float objects for un-coerced `Decimal` instances. This allows you to easily switch between string or float representations for decimals depending on your API design needs.
|
The default JSON renderer will return float objects for un-coerced `Decimal` instances. This allows you to easily switch between string or float representations for decimals depending on your API design needs.
|
||||||
|
|
||||||
## Miscellaneous notes.
|
---
|
||||||
|
|
||||||
|
## Miscellaneous notes
|
||||||
|
|
||||||
* 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.
|
* 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.
|
* 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.
|
||||||
|
|
||||||
## What's coming next.
|
---
|
||||||
|
|
||||||
|
## What's coming next
|
||||||
|
|
||||||
3.0 is an incremental release, and there are several upcoming features that will build on the baseline improvements that it makes.
|
3.0 is an incremental release, and there are several upcoming features that will build on the baseline improvements that it makes.
|
||||||
|
|
||||||
|
@ -919,5 +949,6 @@ The 3.2 release is planned to introduce an alternative admin-style interface to
|
||||||
|
|
||||||
You can follow development on the GitHub site, where we use [milestones to indicate planning timescales](https://github.com/tomchristie/django-rest-framework/milestones).
|
You can follow development on the GitHub site, where we use [milestones to indicate planning timescales](https://github.com/tomchristie/django-rest-framework/milestones).
|
||||||
|
|
||||||
|
[kickstarter]: http://kickstarter.com/projects/tomchristie/django-rest-framework-3
|
||||||
[sponsors]: http://www.django-rest-framework.org/topics/kickstarter-announcement/#sponsors
|
[sponsors]: http://www.django-rest-framework.org/topics/kickstarter-announcement/#sponsors
|
||||||
[mixins.py]: https://github.com/tomchristie/django-rest-framework/blob/master/rest_framework/mixins.py
|
[mixins.py]: https://github.com/tomchristie/django-rest-framework/blob/master/rest_framework/mixins.py
|
||||||
|
|
|
@ -50,6 +50,7 @@ pages:
|
||||||
- ['topics/2.2-announcement.md', 'Topics', '2.2 Announcement']
|
- ['topics/2.2-announcement.md', 'Topics', '2.2 Announcement']
|
||||||
- ['topics/2.3-announcement.md', 'Topics', '2.3 Announcement']
|
- ['topics/2.3-announcement.md', 'Topics', '2.3 Announcement']
|
||||||
- ['topics/2.4-announcement.md', 'Topics', '2.4 Announcement']
|
- ['topics/2.4-announcement.md', 'Topics', '2.4 Announcement']
|
||||||
|
- ['topics/3.0-announcement.md', 'Topics', '3.0 Announcement']
|
||||||
- ['topics/kickstarter-announcement.md', 'Topics', 'Kickstarter Announcement']
|
- ['topics/kickstarter-announcement.md', 'Topics', 'Kickstarter Announcement']
|
||||||
- ['topics/release-notes.md', 'Topics', 'Release Notes']
|
- ['topics/release-notes.md', 'Topics', 'Release Notes']
|
||||||
- ['topics/credits.md', 'Topics', 'Credits']
|
- ['topics/credits.md', 'Topics', 'Credits']
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Django>=1.4.2
|
Django>=1.4.11
|
||||||
|
|
|
@ -11,6 +11,7 @@ python primitives.
|
||||||
response content is handled by parsers and renderers.
|
response content is handled by parsers and renderers.
|
||||||
"""
|
"""
|
||||||
from django.core.exceptions import ImproperlyConfigured
|
from django.core.exceptions import ImproperlyConfigured
|
||||||
|
from django.core.exceptions import ValidationError as DjangoValidationError
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.db.models.fields import FieldDoesNotExist
|
from django.db.models.fields import FieldDoesNotExist
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
|
@ -330,6 +331,14 @@ class Serializer(BaseSerializer):
|
||||||
raise ValidationError({
|
raise ValidationError({
|
||||||
api_settings.NON_FIELD_ERRORS_KEY: [exc.detail]
|
api_settings.NON_FIELD_ERRORS_KEY: [exc.detail]
|
||||||
})
|
})
|
||||||
|
except DjangoValidationError as exc:
|
||||||
|
# Normally you should raise `serializers.ValidationError`
|
||||||
|
# inside your codebase, but we handle Django's validation
|
||||||
|
# exception class as well for simpler compat.
|
||||||
|
# Eg. Calling Model.clean() explictily inside Serializer.validate()
|
||||||
|
raise ValidationError({
|
||||||
|
api_settings.NON_FIELD_ERRORS_KEY: list(exc.messages)
|
||||||
|
})
|
||||||
|
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
@ -353,6 +362,8 @@ class Serializer(BaseSerializer):
|
||||||
validated_value = validate_method(validated_value)
|
validated_value = validate_method(validated_value)
|
||||||
except ValidationError as exc:
|
except ValidationError as exc:
|
||||||
errors[field.field_name] = exc.detail
|
errors[field.field_name] = exc.detail
|
||||||
|
except DjangoValidationError as exc:
|
||||||
|
errors[field.field_name] = list(exc.messages)
|
||||||
except SkipField:
|
except SkipField:
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
|
@ -554,6 +565,14 @@ class ModelSerializer(Serializer):
|
||||||
* A set of default fields are automatically populated.
|
* A set of default fields are automatically populated.
|
||||||
* A set of default validators are automatically populated.
|
* A set of default validators are automatically populated.
|
||||||
* Default `.create()` and `.update()` implementations are provided.
|
* Default `.create()` and `.update()` implementations are provided.
|
||||||
|
|
||||||
|
The process of automatically determining a set of serializer fields
|
||||||
|
based on the model fields is reasonably complex, but you almost certainly
|
||||||
|
don't need to dig into the implemention.
|
||||||
|
|
||||||
|
If the `ModelSerializer` class *doesn't* generate the set of fields that
|
||||||
|
you need you should either declare the extra/differing fields explicitly on
|
||||||
|
the serializer class, or simply use a `Serializer` class.
|
||||||
"""
|
"""
|
||||||
_field_mapping = ClassLookupDict({
|
_field_mapping = ClassLookupDict({
|
||||||
models.AutoField: IntegerField,
|
models.AutoField: IntegerField,
|
||||||
|
@ -582,6 +601,26 @@ class ModelSerializer(Serializer):
|
||||||
_related_class = PrimaryKeyRelatedField
|
_related_class = PrimaryKeyRelatedField
|
||||||
|
|
||||||
def create(self, validated_attrs):
|
def create(self, validated_attrs):
|
||||||
|
"""
|
||||||
|
We have a bit of extra checking around this in order to provide
|
||||||
|
descriptive messages when something goes wrong, but this method is
|
||||||
|
essentially just:
|
||||||
|
|
||||||
|
return ExampleModel.objects.create(**validated_attrs)
|
||||||
|
|
||||||
|
If there are many to many fields present on the instance then they
|
||||||
|
cannot be set until the model is instantiated, in which case the
|
||||||
|
implementation is like so:
|
||||||
|
|
||||||
|
example_relationship = validated_attrs.pop('example_relationship')
|
||||||
|
instance = ExampleModel.objects.create(**validated_attrs)
|
||||||
|
instance.example_relationship = example_relationship
|
||||||
|
return instance
|
||||||
|
|
||||||
|
The default implementation also does not handle nested relationships.
|
||||||
|
If you want to support writable nested relationships you'll need
|
||||||
|
to write an explicit `.create()` method.
|
||||||
|
"""
|
||||||
# Check that the user isn't trying to handle a writable nested field.
|
# Check that the user isn't trying to handle a writable nested field.
|
||||||
# If we don't do this explicitly they'd likely get a confusing
|
# If we don't do this explicitly they'd likely get a confusing
|
||||||
# error at the point of calling `Model.objects.create()`.
|
# error at the point of calling `Model.objects.create()`.
|
||||||
|
@ -632,14 +671,19 @@ class ModelSerializer(Serializer):
|
||||||
return instance
|
return instance
|
||||||
|
|
||||||
def get_validators(self):
|
def get_validators(self):
|
||||||
|
# If the validators have been declared explicitly then use that.
|
||||||
|
validators = getattr(getattr(self, 'Meta', None), 'validators', None)
|
||||||
|
if validators is not None:
|
||||||
|
return validators
|
||||||
|
|
||||||
|
# Determine the default set of validators.
|
||||||
|
validators = []
|
||||||
|
model_class = self.Meta.model
|
||||||
field_names = set([
|
field_names = set([
|
||||||
field.source for field in self.fields.values()
|
field.source for field in self.fields.values()
|
||||||
if (field.source != '*') and ('.' not in field.source)
|
if (field.source != '*') and ('.' not in field.source)
|
||||||
])
|
])
|
||||||
|
|
||||||
validators = getattr(getattr(self, 'Meta', None), 'validators', [])
|
|
||||||
model_class = self.Meta.model
|
|
||||||
|
|
||||||
# Note that we make sure to check `unique_together` both on the
|
# Note that we make sure to check `unique_together` both on the
|
||||||
# base model class, but also on any parent classes.
|
# base model class, but also on any parent classes.
|
||||||
for parent_class in [model_class] + list(model_class._meta.parents.keys()):
|
for parent_class in [model_class] + list(model_class._meta.parents.keys()):
|
||||||
|
|
Loading…
Reference in New Issue
Block a user