mirror of
https://github.com/encode/django-rest-framework.git
synced 2024-11-23 01:57:00 +03:00
Merge branch 'master' of github.com:tomchristie/django-rest-framework
This commit is contained in:
commit
7ecd4f7813
|
@ -363,7 +363,7 @@ HTTP Signature (currently a [IETF draft][http-signature-ietf-draft]) provides a
|
||||||
[oauth]: http://oauth.net/2/
|
[oauth]: http://oauth.net/2/
|
||||||
[permission]: permissions.md
|
[permission]: permissions.md
|
||||||
[throttling]: throttling.md
|
[throttling]: throttling.md
|
||||||
[csrf-ajax]: https://docs.djangoproject.com/en/dev/ref/csrf/#ajax
|
[csrf-ajax]: https://docs.djangoproject.com/en/stable/ref/csrf/#ajax
|
||||||
[mod_wsgi_official]: http://code.google.com/p/modwsgi/wiki/ConfigurationDirectives#WSGIPassAuthorization
|
[mod_wsgi_official]: http://code.google.com/p/modwsgi/wiki/ConfigurationDirectives#WSGIPassAuthorization
|
||||||
[django-oauth-toolkit-getting-started]: https://django-oauth-toolkit.readthedocs.io/en/latest/rest-framework/getting_started.html
|
[django-oauth-toolkit-getting-started]: https://django-oauth-toolkit.readthedocs.io/en/latest/rest-framework/getting_started.html
|
||||||
[django-rest-framework-oauth]: http://jpadilla.github.io/django-rest-framework-oauth/
|
[django-rest-framework-oauth]: http://jpadilla.github.io/django-rest-framework-oauth/
|
||||||
|
|
|
@ -261,7 +261,7 @@ Corresponds to `django.db.models.fields.DecimalField`.
|
||||||
|
|
||||||
**Signature**: `DecimalField(max_digits, decimal_places, coerce_to_string=None, max_value=None, min_value=None)`
|
**Signature**: `DecimalField(max_digits, decimal_places, coerce_to_string=None, max_value=None, min_value=None)`
|
||||||
|
|
||||||
- `max_digits` The maximum number of digits allowed in the number. Note that this number must be greater than or equal to decimal_places.
|
- `max_digits` The maximum number of digits allowed in the number. It must be either `None` or an integer greater than or equal to `decimal_places`.
|
||||||
- `decimal_places` The number of decimal places to store with the number.
|
- `decimal_places` The number of decimal places to store with the number.
|
||||||
- `coerce_to_string` Set to `True` if string values should be returned for the representation, or `False` if `Decimal` objects should be returned. Defaults to the same value as the `COERCE_DECIMAL_TO_STRING` settings key, which will be `True` unless overridden. If `Decimal` objects are returned by the serializer, then the final output format will be determined by the renderer. Note that setting `localize` will force the value to `True`.
|
- `coerce_to_string` Set to `True` if string values should be returned for the representation, or `False` if `Decimal` objects should be returned. Defaults to the same value as the `COERCE_DECIMAL_TO_STRING` settings key, which will be `True` unless overridden. If `Decimal` objects are returned by the serializer, then the final output format will be determined by the renderer. Note that setting `localize` will force the value to `True`.
|
||||||
- `max_value` Validate that the number provided is no greater than this value.
|
- `max_value` Validate that the number provided is no greater than this value.
|
||||||
|
@ -665,12 +665,12 @@ 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.
|
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
|
[cite]: https://docs.djangoproject.com/en/stable/ref/forms/api/#django.forms.Form.cleaned_data
|
||||||
[html-and-forms]: ../topics/html-and-forms.md
|
[html-and-forms]: ../topics/html-and-forms.md
|
||||||
[FILE_UPLOAD_HANDLERS]: https://docs.djangoproject.com/en/dev/ref/settings/#std:setting-FILE_UPLOAD_HANDLERS
|
[FILE_UPLOAD_HANDLERS]: https://docs.djangoproject.com/en/stable/ref/settings/#std:setting-FILE_UPLOAD_HANDLERS
|
||||||
[ecma262]: http://ecma-international.org/ecma-262/5.1/#sec-15.9.1.15
|
[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
|
[strftime]: https://docs.python.org/3/library/datetime.html#strftime-and-strptime-behavior
|
||||||
[django-widgets]: https://docs.djangoproject.com/en/dev/ref/forms/widgets/
|
[django-widgets]: https://docs.djangoproject.com/en/stable/ref/forms/widgets/
|
||||||
[iso8601]: http://www.w3.org/TR/NOTE-datetime
|
[iso8601]: http://www.w3.org/TR/NOTE-datetime
|
||||||
[drf-compound-fields]: https://drf-compound-fields.readthedocs.io
|
[drf-compound-fields]: https://drf-compound-fields.readthedocs.io
|
||||||
[drf-extra-fields]: https://github.com/Hipo/drf-extra-fields
|
[drf-extra-fields]: https://github.com/Hipo/drf-extra-fields
|
||||||
|
|
|
@ -455,14 +455,14 @@ The [djangorestframework-word-filter][django-rest-framework-word-search-filter]
|
||||||
|
|
||||||
[drf-url-filter][drf-url-filter] is a simple Django app to apply filters on drf `ModelViewSet`'s `Queryset` in a clean, simple and configurable way. It also supports validations on incoming query params and their values. A beautiful python package `Voluptuous` is being used for validations on the incoming query parameters. The best part about voluptuous is you can define your own validations as per your query params requirements.
|
[drf-url-filter][drf-url-filter] is a simple Django app to apply filters on drf `ModelViewSet`'s `Queryset` in a clean, simple and configurable way. It also supports validations on incoming query params and their values. A beautiful python package `Voluptuous` is being used for validations on the incoming query parameters. The best part about voluptuous is you can define your own validations as per your query params requirements.
|
||||||
|
|
||||||
[cite]: https://docs.djangoproject.com/en/dev/topics/db/queries/#retrieving-specific-objects-with-filters
|
[cite]: https://docs.djangoproject.com/en/stable/topics/db/queries/#retrieving-specific-objects-with-filters
|
||||||
[django-filter]: https://github.com/alex/django-filter
|
[django-filter]: https://github.com/alex/django-filter
|
||||||
[django-filter-docs]: https://django-filter.readthedocs.io/en/latest/index.html
|
[django-filter-docs]: https://django-filter.readthedocs.io/en/latest/index.html
|
||||||
[guardian]: https://django-guardian.readthedocs.io/
|
[guardian]: https://django-guardian.readthedocs.io/
|
||||||
[view-permissions]: https://django-guardian.readthedocs.io/en/latest/userguide/assign.html
|
[view-permissions]: https://django-guardian.readthedocs.io/en/latest/userguide/assign.html
|
||||||
[view-permissions-blogpost]: http://blog.nyaruka.com/adding-a-view-permission-to-django-models
|
[view-permissions-blogpost]: http://blog.nyaruka.com/adding-a-view-permission-to-django-models
|
||||||
[nullbooleanselect]: https://github.com/django/django/blob/master/django/forms/widgets.py
|
[nullbooleanselect]: https://github.com/django/django/blob/master/django/forms/widgets.py
|
||||||
[search-django-admin]: https://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.search_fields
|
[search-django-admin]: https://docs.djangoproject.com/en/stable/ref/contrib/admin/#django.contrib.admin.ModelAdmin.search_fields
|
||||||
[django-rest-framework-filters]: https://github.com/philipn/django-rest-framework-filters
|
[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-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
|
[django-url-filter]: https://github.com/miki725/django-url-filter
|
||||||
|
|
|
@ -382,7 +382,7 @@ The [django-rest-framework-bulk package][django-rest-framework-bulk] implements
|
||||||
[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.
|
[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
|
[cite]: https://docs.djangoproject.com/en/stable/ref/class-based-views/#base-vs-generic-views
|
||||||
[GenericAPIView]: #genericapiview
|
[GenericAPIView]: #genericapiview
|
||||||
[ListModelMixin]: #listmodelmixin
|
[ListModelMixin]: #listmodelmixin
|
||||||
[CreateModelMixin]: #createmodelmixin
|
[CreateModelMixin]: #createmodelmixin
|
||||||
|
|
|
@ -325,7 +325,7 @@ The [`DRF-extensions` package][drf-extensions] includes a [`PaginateByMaxMixin`
|
||||||
|
|
||||||
The [`drf-proxy-pagination` package][drf-proxy-pagination] includes a `ProxyPagination` class which allows to choose pagination class with a query parameter.
|
The [`drf-proxy-pagination` package][drf-proxy-pagination] includes a `ProxyPagination` class which allows to choose pagination class with a query parameter.
|
||||||
|
|
||||||
[cite]: https://docs.djangoproject.com/en/dev/topics/pagination/
|
[cite]: https://docs.djangoproject.com/en/stable/topics/pagination/
|
||||||
[github-link-pagination]: https://developer.github.com/guides/traversing-with-pagination/
|
[github-link-pagination]: https://developer.github.com/guides/traversing-with-pagination/
|
||||||
[link-header]: ../img/link-header-pagination.png
|
[link-header]: ../img/link-header-pagination.png
|
||||||
[drf-extensions]: http://chibisov.github.io/drf-extensions/docs/
|
[drf-extensions]: http://chibisov.github.io/drf-extensions/docs/
|
||||||
|
|
|
@ -224,7 +224,7 @@ Modify your REST framework settings.
|
||||||
|
|
||||||
[jquery-ajax]: http://api.jquery.com/jQuery.ajax/
|
[jquery-ajax]: http://api.jquery.com/jQuery.ajax/
|
||||||
[cite]: https://groups.google.com/d/topic/django-developers/dxI4qVzrBY4/discussion
|
[cite]: https://groups.google.com/d/topic/django-developers/dxI4qVzrBY4/discussion
|
||||||
[upload-handlers]: https://docs.djangoproject.com/en/dev/topics/http/file-uploads/#upload-handlers
|
[upload-handlers]: https://docs.djangoproject.com/en/stable/topics/http/file-uploads/#upload-handlers
|
||||||
[rest-framework-yaml]: http://jpadilla.github.io/django-rest-framework-yaml/
|
[rest-framework-yaml]: http://jpadilla.github.io/django-rest-framework-yaml/
|
||||||
[rest-framework-xml]: http://jpadilla.github.io/django-rest-framework-xml/
|
[rest-framework-xml]: http://jpadilla.github.io/django-rest-framework-xml/
|
||||||
[yaml]: http://www.yaml.org/
|
[yaml]: http://www.yaml.org/
|
||||||
|
|
|
@ -164,7 +164,7 @@ As with `DjangoModelPermissions`, this permission must only be applied to views
|
||||||
|
|
||||||
Note that `DjangoObjectPermissions` **does not** require the `django-guardian` package, and should support other object-level backends equally well.
|
Note that `DjangoObjectPermissions` **does not** require the `django-guardian` package, and should support other object-level backends equally well.
|
||||||
|
|
||||||
As with `DjangoModelPermissions` you can use custom model permissions by overriding `DjangoModelPermissions` and setting the `.perms_map` property. Refer to the source code for details.
|
As with `DjangoModelPermissions` you can use custom model permissions by overriding `DjangoObjectPermissions` and setting the `.perms_map` property. Refer to the source code for details.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
@ -269,8 +269,8 @@ The [Django Rest Framework Roles][django-rest-framework-roles] package makes it
|
||||||
[authentication]: authentication.md
|
[authentication]: authentication.md
|
||||||
[throttling]: throttling.md
|
[throttling]: throttling.md
|
||||||
[filtering]: filtering.md
|
[filtering]: filtering.md
|
||||||
[contribauth]: https://docs.djangoproject.com/en/dev/topics/auth/customizing/#custom-permissions
|
[contribauth]: https://docs.djangoproject.com/en/stable/topics/auth/customizing/#custom-permissions
|
||||||
[objectpermissions]: https://docs.djangoproject.com/en/dev/topics/auth/customizing/#handling-object-permissions
|
[objectpermissions]: https://docs.djangoproject.com/en/stable/topics/auth/customizing/#handling-object-permissions
|
||||||
[guardian]: https://github.com/lukaszb/django-guardian
|
[guardian]: https://github.com/lukaszb/django-guardian
|
||||||
[get_objects_for_user]: http://pythonhosted.org/django-guardian/api/guardian.shortcuts.html#get-objects-for-user
|
[get_objects_for_user]: http://pythonhosted.org/django-guardian/api/guardian.shortcuts.html#get-objects-for-user
|
||||||
[2.2-announcement]: ../topics/2.2-announcement.md
|
[2.2-announcement]: ../topics/2.2-announcement.md
|
||||||
|
|
|
@ -505,7 +505,7 @@ For example, given the following model for a tag, which has a generic relationsh
|
||||||
"""
|
"""
|
||||||
Tags arbitrary model instances using a generic relation.
|
Tags arbitrary model instances using a generic relation.
|
||||||
|
|
||||||
See: https://docs.djangoproject.com/en/dev/ref/contrib/contenttypes/
|
See: https://docs.djangoproject.com/en/stable/ref/contrib/contenttypes/
|
||||||
"""
|
"""
|
||||||
tag_name = models.SlugField()
|
tag_name = models.SlugField()
|
||||||
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
|
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
|
||||||
|
@ -593,9 +593,9 @@ The [drf-nested-routers package][drf-nested-routers] provides routers and relati
|
||||||
The [rest-framework-generic-relations][drf-nested-relations] library provides read/write serialization for generic foreign keys.
|
The [rest-framework-generic-relations][drf-nested-relations] library provides read/write serialization for generic foreign keys.
|
||||||
|
|
||||||
[cite]: http://lwn.net/Articles/193245/
|
[cite]: http://lwn.net/Articles/193245/
|
||||||
[reverse-relationships]: https://docs.djangoproject.com/en/dev/topics/db/queries/#following-relationships-backward
|
[reverse-relationships]: https://docs.djangoproject.com/en/stable/topics/db/queries/#following-relationships-backward
|
||||||
[routers]: http://www.django-rest-framework.org/api-guide/routers#defaultrouter
|
[routers]: http://www.django-rest-framework.org/api-guide/routers#defaultrouter
|
||||||
[generic-relations]: https://docs.djangoproject.com/en/dev/ref/contrib/contenttypes/#id1
|
[generic-relations]: https://docs.djangoproject.com/en/stable/ref/contrib/contenttypes/#id1
|
||||||
[2.2-announcement]: ../topics/2.2-announcement.md
|
[2.2-announcement]: ../topics/2.2-announcement.md
|
||||||
[drf-nested-routers]: https://github.com/alanjds/drf-nested-routers
|
[drf-nested-routers]: https://github.com/alanjds/drf-nested-routers
|
||||||
[drf-nested-relations]: https://github.com/Ian-Foote/rest-framework-generic-relations
|
[drf-nested-relations]: https://github.com/Ian-Foote/rest-framework-generic-relations
|
||||||
|
|
|
@ -123,6 +123,8 @@ You can use `TemplateHTMLRenderer` either to return regular HTML pages using RES
|
||||||
|
|
||||||
If you're building websites that use `TemplateHTMLRenderer` along with other renderer classes, you should consider listing `TemplateHTMLRenderer` as the first class in the `renderer_classes` list, so that it will be prioritised first even for browsers that send poorly formed `ACCEPT:` headers.
|
If you're building websites that use `TemplateHTMLRenderer` along with other renderer classes, you should consider listing `TemplateHTMLRenderer` as the first class in the `renderer_classes` list, so that it will be prioritised first even for browsers that send poorly formed `ACCEPT:` headers.
|
||||||
|
|
||||||
|
See the [_HTML & Forms_ Topic Page][html-and-forms] for further examples of `TemplateHTMLRenderer` usage.
|
||||||
|
|
||||||
**.media_type**: `text/html`
|
**.media_type**: `text/html`
|
||||||
|
|
||||||
**.format**: `'.html'`
|
**.format**: `'.html'`
|
||||||
|
@ -476,7 +478,7 @@ Comma-separated values are a plain-text tabular data format, that can be easily
|
||||||
[Rest Framework Latex] provides a renderer that outputs PDFs using Laulatex. It is maintained by [Pebble (S/F Software)][mypebble].
|
[Rest Framework Latex] provides a renderer that outputs PDFs using Laulatex. It is maintained by [Pebble (S/F Software)][mypebble].
|
||||||
|
|
||||||
|
|
||||||
[cite]: https://docs.djangoproject.com/en/dev/ref/template-response/#the-rendering-process
|
[cite]: https://docs.djangoproject.com/en/stable/stable/template-response/#the-rendering-process
|
||||||
[conneg]: content-negotiation.md
|
[conneg]: content-negotiation.md
|
||||||
[html-and-forms]: ../topics/html-and-forms.md
|
[html-and-forms]: ../topics/html-and-forms.md
|
||||||
[browser-accept-headers]: http://www.gethifi.com/blog/browser-rest-http-accept-headers
|
[browser-accept-headers]: http://www.gethifi.com/blog/browser-rest-http-accept-headers
|
||||||
|
@ -485,7 +487,7 @@ Comma-separated values are a plain-text tabular data format, that can be easily
|
||||||
[quote]: http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven
|
[quote]: http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven
|
||||||
[application/vnd.github+json]: http://developer.github.com/v3/media/
|
[application/vnd.github+json]: http://developer.github.com/v3/media/
|
||||||
[application/vnd.collection+json]: http://www.amundsen.com/media-types/collection/
|
[application/vnd.collection+json]: http://www.amundsen.com/media-types/collection/
|
||||||
[django-error-views]: https://docs.djangoproject.com/en/dev/topics/http/views/#customizing-error-views
|
[django-error-views]: https://docs.djangoproject.com/en/stable/topics/http/views/#customizing-error-views
|
||||||
[rest-framework-jsonp]: http://jpadilla.github.io/django-rest-framework-jsonp/
|
[rest-framework-jsonp]: http://jpadilla.github.io/django-rest-framework-jsonp/
|
||||||
[cors]: http://www.w3.org/TR/cors/
|
[cors]: http://www.w3.org/TR/cors/
|
||||||
[cors-docs]: http://www.django-rest-framework.org/topics/ajax-csrf-cors/
|
[cors-docs]: http://www.django-rest-framework.org/topics/ajax-csrf-cors/
|
||||||
|
|
|
@ -91,5 +91,5 @@ As with any other `TemplateResponse`, this method is called to render the serial
|
||||||
|
|
||||||
You won't typically need to call `.render()` yourself, as it's handled by Django's standard response cycle.
|
You won't typically need to call `.render()` yourself, as it's handled by Django's standard response cycle.
|
||||||
|
|
||||||
[cite]: https://docs.djangoproject.com/en/dev/ref/template-response/
|
[cite]: https://docs.djangoproject.com/en/stable/stable/template-response/
|
||||||
[statuscodes]: status-codes.md
|
[statuscodes]: status-codes.md
|
||||||
|
|
|
@ -51,5 +51,5 @@ As with the `reverse` function, you should **include the request as a keyword ar
|
||||||
api_root = reverse_lazy('api-root', request=request)
|
api_root = reverse_lazy('api-root', request=request)
|
||||||
|
|
||||||
[cite]: http://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm#sec_5_1_5
|
[cite]: http://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm#sec_5_1_5
|
||||||
[reverse]: https://docs.djangoproject.com/en/dev/topics/http/urls/#reverse
|
[reverse]: https://docs.djangoproject.com/en/stable/topics/http/urls/#reverse
|
||||||
[reverse-lazy]: https://docs.djangoproject.com/en/dev/topics/http/urls/#reverse-lazy
|
[reverse-lazy]: https://docs.djangoproject.com/en/stable/topics/http/urls/#reverse-lazy
|
||||||
|
|
|
@ -541,5 +541,5 @@ A short description of the meaning and intended usage of the input field.
|
||||||
[open-api]: https://openapis.org/
|
[open-api]: https://openapis.org/
|
||||||
[json-hyperschema]: http://json-schema.org/latest/json-schema-hypermedia.html
|
[json-hyperschema]: http://json-schema.org/latest/json-schema-hypermedia.html
|
||||||
[api-blueprint]: https://apiblueprint.org/
|
[api-blueprint]: https://apiblueprint.org/
|
||||||
[static-files]: https://docs.djangoproject.com/en/dev/howto/static-files/
|
[static-files]: https://docs.djangoproject.com/en/stable/howto/static-files/
|
||||||
[named-arguments]: https://docs.djangoproject.com/en/dev/topics/http/urls/#named-groups
|
[named-arguments]: https://docs.djangoproject.com/en/stable/topics/http/urls/#named-groups
|
||||||
|
|
|
@ -1118,7 +1118,7 @@ The [html-json-forms][html-json-forms] package provides an algorithm and seriali
|
||||||
|
|
||||||
[cite]: https://groups.google.com/d/topic/django-users/sVFaOfQi4wY/discussion
|
[cite]: https://groups.google.com/d/topic/django-users/sVFaOfQi4wY/discussion
|
||||||
[relations]: relations.md
|
[relations]: relations.md
|
||||||
[model-managers]: https://docs.djangoproject.com/en/dev/topics/db/managers/
|
[model-managers]: https://docs.djangoproject.com/en/stable/topics/db/managers/
|
||||||
[encapsulation-blogpost]: http://www.dabapps.com/blog/django-models-and-encapsulation/
|
[encapsulation-blogpost]: http://www.dabapps.com/blog/django-models-and-encapsulation/
|
||||||
[django-rest-marshmallow]: http://tomchristie.github.io/django-rest-marshmallow/
|
[django-rest-marshmallow]: http://tomchristie.github.io/django-rest-marshmallow/
|
||||||
[marshmallow]: https://marshmallow.readthedocs.io/en/latest/
|
[marshmallow]: https://marshmallow.readthedocs.io/en/latest/
|
||||||
|
|
|
@ -456,7 +456,7 @@ An integer of 0 or more, that may be used to specify the number of application p
|
||||||
|
|
||||||
Default: `None`
|
Default: `None`
|
||||||
|
|
||||||
[cite]: http://www.python.org/dev/peps/pep-0020/
|
[cite]: https://www.python.org/dev/peps/pep-0020/
|
||||||
[rfc4627]: http://www.ietf.org/rfc/rfc4627.txt
|
[rfc4627]: http://www.ietf.org/rfc/rfc4627.txt
|
||||||
[heroku-minified-json]: https://github.com/interagent/http-api-design#keep-json-minified-in-all-responses
|
[heroku-minified-json]: https://github.com/interagent/http-api-design#keep-json-minified-in-all-responses
|
||||||
[strftime]: http://docs.python.org/2/library/time.html#time.strftime
|
[strftime]: https://docs.python.org/3/library/time.html#time.strftime
|
||||||
|
|
|
@ -373,6 +373,6 @@ For example, to add support for using `format='html'` in test requests, you migh
|
||||||
}
|
}
|
||||||
|
|
||||||
[cite]: http://jacobian.org/writing/django-apps-with-buildout/#s-create-a-test-wrapper
|
[cite]: http://jacobian.org/writing/django-apps-with-buildout/#s-create-a-test-wrapper
|
||||||
[client]: https://docs.djangoproject.com/en/dev/topics/testing/tools/#the-test-client
|
[client]: https://docs.djangoproject.com/en/stable/topics/testing/tools/#the-test-client
|
||||||
[requestfactory]: https://docs.djangoproject.com/en/dev/topics/testing/advanced/#django.test.client.RequestFactory
|
[requestfactory]: https://docs.djangoproject.com/en/stable/topics/testing/advanced/#django.test.client.RequestFactory
|
||||||
[configuration]: #configuration
|
[configuration]: #configuration
|
||||||
|
|
|
@ -193,5 +193,5 @@ The following is an example of a rate throttle, that will randomly throttle 1 in
|
||||||
[cite]: https://dev.twitter.com/docs/error-codes-responses
|
[cite]: https://dev.twitter.com/docs/error-codes-responses
|
||||||
[permissions]: permissions.md
|
[permissions]: permissions.md
|
||||||
[identifing-clients]: http://oxpedia.org/wiki/index.php?title=AppSuite:Grizzly#Multiple_Proxies_in_front_of_the_cluster
|
[identifing-clients]: http://oxpedia.org/wiki/index.php?title=AppSuite:Grizzly#Multiple_Proxies_in_front_of_the_cluster
|
||||||
[cache-setting]: https://docs.djangoproject.com/en/dev/ref/settings/#caches
|
[cache-setting]: https://docs.djangoproject.com/en/stable/ref/settings/#caches
|
||||||
[cache-docs]: https://docs.djangoproject.com/en/dev/topics/cache/#setting-up-the-cache
|
[cache-docs]: https://docs.djangoproject.com/en/stable/topics/cache/#setting-up-the-cache
|
||||||
|
|
|
@ -300,4 +300,4 @@ In some advanced cases you might want a validator to be passed the serializer fi
|
||||||
# In `__call__` we can then use that information to modify the validation behavior.
|
# In `__call__` we can then use that information to modify the validation behavior.
|
||||||
self.is_update = serializer_field.parent.instance is not None
|
self.is_update = serializer_field.parent.instance is not None
|
||||||
|
|
||||||
[cite]: https://docs.djangoproject.com/en/dev/ref/validators/
|
[cite]: https://docs.djangoproject.com/en/stable/ref/validators/
|
||||||
|
|
|
@ -147,10 +147,10 @@ When using a serializer with a `HyperlinkedRelatedField` or `HyperlinkedIdentity
|
||||||
From version 2.2 onwards, serializers with hyperlinked relationships *always* require a `'request'` key to be supplied in the context dictionary. The implicit behavior will continue to function, but its use will raise a `PendingDeprecationWarning`.
|
From version 2.2 onwards, serializers with hyperlinked relationships *always* require a `'request'` key to be supplied in the context dictionary. The implicit behavior will continue to function, but its use will raise a `PendingDeprecationWarning`.
|
||||||
|
|
||||||
[xordoquy]: https://github.com/xordoquy
|
[xordoquy]: https://github.com/xordoquy
|
||||||
[django-python-3]: https://docs.djangoproject.com/en/dev/faq/install/#can-i-use-django-with-python-3
|
[django-python-3]: https://docs.djangoproject.com/en/stable/faq/install/#can-i-use-django-with-python-3
|
||||||
[porting-python-3]: https://docs.djangoproject.com/en/dev/topics/python3/
|
[porting-python-3]: https://docs.djangoproject.com/en/stable/topics/python3/
|
||||||
[python-compat]: https://docs.djangoproject.com/en/dev/releases/1.5/#python-compatibility
|
[python-compat]: https://docs.djangoproject.com/en/stable/releases/1.5/#python-compatibility
|
||||||
[django-deprecation-policy]: https://docs.djangoproject.com/en/dev/internals/release-process/#internal-release-deprecation-policy
|
[django-deprecation-policy]: https://docs.djangoproject.com/en/stable/internals/release-process/#internal-release-deprecation-policy
|
||||||
[credits]: http://www.django-rest-framework.org/topics/credits
|
[credits]: http://www.django-rest-framework.org/topics/credits
|
||||||
[mailing-list]: https://groups.google.com/forum/?fromgroups#!forum/django-rest-framework
|
[mailing-list]: https://groups.google.com/forum/?fromgroups#!forum/django-rest-framework
|
||||||
[django-rest-framework-docs]: https://github.com/marcgibbons/django-rest-framework-docs
|
[django-rest-framework-docs]: https://github.com/marcgibbons/django-rest-framework-docs
|
||||||
|
|
|
@ -162,7 +162,7 @@ The next planned release will be 3.0, featuring an improved and simplified seria
|
||||||
|
|
||||||
Once again, many thanks to all the generous [backers and sponsors][kickstarter-sponsors] who've helped make this possible!
|
Once again, many thanks to all the generous [backers and sponsors][kickstarter-sponsors] who've helped make this possible!
|
||||||
|
|
||||||
[lts-releases]: https://docs.djangoproject.com/en/dev/internals/release-process/#long-term-support-lts-releases
|
[lts-releases]: https://docs.djangoproject.com/en/stable/internals/release-process/#long-term-support-lts-releases
|
||||||
[2-4-release-notes]: release-notes#240
|
[2-4-release-notes]: release-notes#240
|
||||||
[view-name-and-description-settings]: ../api-guide/settings#view-names-and-descriptions
|
[view-name-and-description-settings]: ../api-guide/settings#view-names-and-descriptions
|
||||||
[client-ip-identification]: ../api-guide/throttling#how-clients-are-identified
|
[client-ip-identification]: ../api-guide/throttling#how-clients-are-identified
|
||||||
|
|
|
@ -870,7 +870,7 @@ The `COMPACT_JSON` setting has been added, and can be used to revert this behavi
|
||||||
|
|
||||||
#### File fields as URLs
|
#### File fields as URLs
|
||||||
|
|
||||||
The `FileField` and `ImageField` classes are now represented as URLs by default. You should ensure you set Django's [standard `MEDIA_URL` setting](https://docs.djangoproject.com/en/dev/ref/settings/#std:setting-MEDIA_URL) appropriately, and ensure your application [serves the uploaded files](https://docs.djangoproject.com/en/dev/howto/static-files/#serving-uploaded-files-in-development).
|
The `FileField` and `ImageField` classes are now represented as URLs by default. You should ensure you set Django's [standard `MEDIA_URL` setting](https://docs.djangoproject.com/en/stable/ref/settings/#std:setting-MEDIA_URL) appropriately, and ensure your application [serves the uploaded files](https://docs.djangoproject.com/en/stable/howto/static-files/#serving-uploaded-files-in-development).
|
||||||
|
|
||||||
You can revert this behavior, and display filenames in the representation by using the `UPLOADED_FILES_USE_URL` settings key:
|
You can revert this behavior, and display filenames in the representation by using the `UPLOADED_FILES_USE_URL` settings key:
|
||||||
|
|
||||||
|
@ -962,4 +962,4 @@ You can follow development on the GitHub site, where we use [milestones to indic
|
||||||
[kickstarter]: http://kickstarter.com/projects/tomchristie/django-rest-framework-3
|
[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
|
||||||
[django-localization]: https://docs.djangoproject.com/en/dev/topics/i18n/translation/#localization-how-to-create-language-files
|
[django-localization]: https://docs.djangoproject.com/en/stable/topics/i18n/translation/#localization-how-to-create-language-files
|
||||||
|
|
|
@ -35,7 +35,7 @@ The best way to deal with CORS in REST framework is to add the required response
|
||||||
|
|
||||||
[cite]: http://www.codinghorror.com/blog/2008/10/preventing-csrf-and-xsrf-attacks.html
|
[cite]: http://www.codinghorror.com/blog/2008/10/preventing-csrf-and-xsrf-attacks.html
|
||||||
[csrf]: https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)
|
[csrf]: https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)
|
||||||
[csrf-ajax]: https://docs.djangoproject.com/en/dev/ref/csrf/#ajax
|
[csrf-ajax]: https://docs.djangoproject.com/en/stable/ref/csrf/#ajax
|
||||||
[cors]: http://www.w3.org/TR/cors/
|
[cors]: http://www.w3.org/TR/cors/
|
||||||
[ottoyiu]: https://github.com/ottoyiu/
|
[ottoyiu]: https://github.com/ottoyiu/
|
||||||
[django-cors-headers]: https://github.com/ottoyiu/django-cors-headers/
|
[django-cors-headers]: https://github.com/ottoyiu/django-cors-headers/
|
||||||
|
|
|
@ -598,7 +598,7 @@ For older release notes, [please see the version 2.x documentation][old-release-
|
||||||
|
|
||||||
[cite]: http://www.catb.org/~esr/writings/cathedral-bazaar/cathedral-bazaar/ar01s04.html
|
[cite]: http://www.catb.org/~esr/writings/cathedral-bazaar/cathedral-bazaar/ar01s04.html
|
||||||
[deprecation-policy]: #deprecation-policy
|
[deprecation-policy]: #deprecation-policy
|
||||||
[django-deprecation-policy]: https://docs.djangoproject.com/en/dev/internals/release-process/#internal-release-deprecation-policy
|
[django-deprecation-policy]: https://docs.djangoproject.com/en/stable/internals/release-process/#internal-release-deprecation-policy
|
||||||
[defusedxml-announce]: http://blog.python.org/2013/02/announcing-defusedxml-fixes-for-xml.html
|
[defusedxml-announce]: http://blog.python.org/2013/02/announcing-defusedxml-fixes-for-xml.html
|
||||||
[743]: https://github.com/tomchristie/django-rest-framework/pull/743
|
[743]: https://github.com/tomchristie/django-rest-framework/pull/743
|
||||||
[staticfiles14]: https://docs.djangoproject.com/en/1.4/howto/static-files/#with-a-template-tag
|
[staticfiles14]: https://docs.djangoproject.com/en/1.4/howto/static-files/#with-a-template-tag
|
||||||
|
|
|
@ -118,7 +118,9 @@ We'd also like to set a few global settings. We'd like to turn on pagination, a
|
||||||
)
|
)
|
||||||
|
|
||||||
REST_FRAMEWORK = {
|
REST_FRAMEWORK = {
|
||||||
'DEFAULT_PERMISSION_CLASSES': ('rest_framework.permissions.IsAdminUser',),
|
'DEFAULT_PERMISSION_CLASSES': [
|
||||||
|
'rest_framework.permissions.IsAdminUser',
|
||||||
|
],
|
||||||
'PAGE_SIZE': 10
|
'PAGE_SIZE': 10
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,16 +26,19 @@ class DropdownWithAuthTests(TestCase):
|
||||||
def test_name_shown_when_logged_in(self):
|
def test_name_shown_when_logged_in(self):
|
||||||
self.client.login(username=self.username, password=self.password)
|
self.client.login(username=self.username, password=self.password)
|
||||||
response = self.client.get('/')
|
response = self.client.get('/')
|
||||||
self.assertContains(response, 'john')
|
content = response.content.decode('utf8')
|
||||||
|
assert 'john' in content
|
||||||
|
|
||||||
def test_logout_shown_when_logged_in(self):
|
def test_logout_shown_when_logged_in(self):
|
||||||
self.client.login(username=self.username, password=self.password)
|
self.client.login(username=self.username, password=self.password)
|
||||||
response = self.client.get('/')
|
response = self.client.get('/')
|
||||||
self.assertContains(response, '>Log out<')
|
content = response.content.decode('utf8')
|
||||||
|
assert '>Log out<' in content
|
||||||
|
|
||||||
def test_login_shown_when_logged_out(self):
|
def test_login_shown_when_logged_out(self):
|
||||||
response = self.client.get('/')
|
response = self.client.get('/')
|
||||||
self.assertContains(response, '>Log in<')
|
content = response.content.decode('utf8')
|
||||||
|
assert '>Log in<' in content
|
||||||
|
|
||||||
|
|
||||||
@override_settings(ROOT_URLCONF='tests.browsable_api.no_auth_urls')
|
@override_settings(ROOT_URLCONF='tests.browsable_api.no_auth_urls')
|
||||||
|
@ -58,13 +61,16 @@ class NoDropdownWithoutAuthTests(TestCase):
|
||||||
def test_name_shown_when_logged_in(self):
|
def test_name_shown_when_logged_in(self):
|
||||||
self.client.login(username=self.username, password=self.password)
|
self.client.login(username=self.username, password=self.password)
|
||||||
response = self.client.get('/')
|
response = self.client.get('/')
|
||||||
self.assertContains(response, 'john')
|
content = response.content.decode('utf8')
|
||||||
|
assert 'john' in content
|
||||||
|
|
||||||
def test_dropdown_not_shown_when_logged_in(self):
|
def test_dropdown_not_shown_when_logged_in(self):
|
||||||
self.client.login(username=self.username, password=self.password)
|
self.client.login(username=self.username, password=self.password)
|
||||||
response = self.client.get('/')
|
response = self.client.get('/')
|
||||||
self.assertNotContains(response, '<li class="dropdown">')
|
content = response.content.decode('utf8')
|
||||||
|
assert '<li class="dropdown">' not in content
|
||||||
|
|
||||||
def test_dropdown_not_shown_when_logged_out(self):
|
def test_dropdown_not_shown_when_logged_out(self):
|
||||||
response = self.client.get('/')
|
response = self.client.get('/')
|
||||||
self.assertNotContains(response, '<li class="dropdown">')
|
content = response.content.decode('utf8')
|
||||||
|
assert '<li class="dropdown">' not in content
|
||||||
|
|
|
@ -35,8 +35,8 @@ class DropdownWithAuthTests(TestCase):
|
||||||
@override_settings(ROOT_URLCONF='tests.browsable_api.test_browsable_nested_api')
|
@override_settings(ROOT_URLCONF='tests.browsable_api.test_browsable_nested_api')
|
||||||
def test_login(self):
|
def test_login(self):
|
||||||
response = self.client.get('/api/')
|
response = self.client.get('/api/')
|
||||||
self.assertEqual(200, response.status_code)
|
assert 200 == response.status_code
|
||||||
content = response.content.decode('utf-8')
|
content = response.content.decode('utf-8')
|
||||||
self.assertIn('form action="/api/"', content)
|
assert 'form action="/api/"' in content
|
||||||
self.assertIn('input name="nested.one"', content)
|
assert 'input name="nested.one"' in content
|
||||||
self.assertIn('input name="nested.two"', content)
|
assert 'input name="nested.two"' in content
|
||||||
|
|
|
@ -50,5 +50,5 @@ class TestManyPostView(TestCase):
|
||||||
request = factory.post('/', data, format='json')
|
request = factory.post('/', data, format='json')
|
||||||
with self.assertNumQueries(1):
|
with self.assertNumQueries(1):
|
||||||
response = self.view(request).render()
|
response = self.view(request).render()
|
||||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
assert response.status_code == status.HTTP_200_OK
|
||||||
self.assertEqual(len(response.data), 3)
|
assert len(response.data) == 3
|
||||||
|
|
|
@ -67,8 +67,8 @@ class DBTransactionTests(TestCase):
|
||||||
|
|
||||||
with self.assertNumQueries(1):
|
with self.assertNumQueries(1):
|
||||||
response = self.view(request)
|
response = self.view(request)
|
||||||
self.assertFalse(transaction.get_rollback())
|
assert not transaction.get_rollback()
|
||||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
assert response.status_code == status.HTTP_200_OK
|
||||||
assert BasicModel.objects.count() == 1
|
assert BasicModel.objects.count() == 1
|
||||||
|
|
||||||
|
|
||||||
|
@ -98,7 +98,7 @@ class DBTransactionErrorTests(TestCase):
|
||||||
# 3 - release savepoint
|
# 3 - release savepoint
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
self.assertRaises(Exception, self.view, request)
|
self.assertRaises(Exception, self.view, request)
|
||||||
self.assertFalse(transaction.get_rollback())
|
assert not transaction.get_rollback()
|
||||||
assert BasicModel.objects.count() == 1
|
assert BasicModel.objects.count() == 1
|
||||||
|
|
||||||
|
|
||||||
|
@ -128,9 +128,8 @@ class DBTransactionAPIExceptionTests(TestCase):
|
||||||
# 4 - release savepoint (django>=1.8 only)
|
# 4 - release savepoint (django>=1.8 only)
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
response = self.view(request)
|
response = self.view(request)
|
||||||
self.assertTrue(transaction.get_rollback())
|
assert transaction.get_rollback()
|
||||||
self.assertEqual(response.status_code,
|
assert response.status_code == status.HTTP_500_INTERNAL_SERVER_ERROR
|
||||||
status.HTTP_500_INTERNAL_SERVER_ERROR)
|
|
||||||
assert BasicModel.objects.count() == 0
|
assert BasicModel.objects.count() == 0
|
||||||
|
|
||||||
|
|
||||||
|
@ -151,5 +150,4 @@ class NonAtomicDBTransactionAPIExceptionTests(TransactionTestCase):
|
||||||
|
|
||||||
# without checking connection.in_atomic_block view raises 500
|
# without checking connection.in_atomic_block view raises 500
|
||||||
# due attempt to rollback without transaction
|
# due attempt to rollback without transaction
|
||||||
self.assertEqual(response.status_code,
|
assert response.status_code == status.HTTP_404_NOT_FOUND
|
||||||
status.HTTP_404_NOT_FOUND)
|
|
||||||
|
|
|
@ -106,7 +106,7 @@ class BasicAuthTests(TestCase):
|
||||||
{'example': 'example'},
|
{'example': 'example'},
|
||||||
HTTP_AUTHORIZATION=auth
|
HTTP_AUTHORIZATION=auth
|
||||||
)
|
)
|
||||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
assert response.status_code == status.HTTP_200_OK
|
||||||
|
|
||||||
def test_post_json_passing_basic_auth(self):
|
def test_post_json_passing_basic_auth(self):
|
||||||
"""Ensure POSTing form over basic auth with correct credentials passes and does not require CSRF"""
|
"""Ensure POSTing form over basic auth with correct credentials passes and does not require CSRF"""
|
||||||
|
@ -121,7 +121,7 @@ class BasicAuthTests(TestCase):
|
||||||
format='json',
|
format='json',
|
||||||
HTTP_AUTHORIZATION=auth
|
HTTP_AUTHORIZATION=auth
|
||||||
)
|
)
|
||||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
assert response.status_code == status.HTTP_200_OK
|
||||||
|
|
||||||
def test_regression_handle_bad_base64_basic_auth_header(self):
|
def test_regression_handle_bad_base64_basic_auth_header(self):
|
||||||
"""Ensure POSTing JSON over basic auth with incorrectly padded Base64 string is handled correctly"""
|
"""Ensure POSTing JSON over basic auth with incorrectly padded Base64 string is handled correctly"""
|
||||||
|
@ -134,12 +134,12 @@ class BasicAuthTests(TestCase):
|
||||||
format='json',
|
format='json',
|
||||||
HTTP_AUTHORIZATION=auth
|
HTTP_AUTHORIZATION=auth
|
||||||
)
|
)
|
||||||
self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
|
assert response.status_code == status.HTTP_401_UNAUTHORIZED
|
||||||
|
|
||||||
def test_post_form_failing_basic_auth(self):
|
def test_post_form_failing_basic_auth(self):
|
||||||
"""Ensure POSTing form over basic auth without correct credentials fails"""
|
"""Ensure POSTing form over basic auth without correct credentials fails"""
|
||||||
response = self.csrf_client.post('/basic/', {'example': 'example'})
|
response = self.csrf_client.post('/basic/', {'example': 'example'})
|
||||||
self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
|
assert response.status_code == status.HTTP_401_UNAUTHORIZED
|
||||||
|
|
||||||
def test_post_json_failing_basic_auth(self):
|
def test_post_json_failing_basic_auth(self):
|
||||||
"""Ensure POSTing json over basic auth without correct credentials fails"""
|
"""Ensure POSTing json over basic auth without correct credentials fails"""
|
||||||
|
@ -148,8 +148,8 @@ class BasicAuthTests(TestCase):
|
||||||
{'example': 'example'},
|
{'example': 'example'},
|
||||||
format='json'
|
format='json'
|
||||||
)
|
)
|
||||||
self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
|
assert response.status_code == status.HTTP_401_UNAUTHORIZED
|
||||||
self.assertEqual(response['WWW-Authenticate'], 'Basic realm="api"')
|
assert response['WWW-Authenticate'] == 'Basic realm="api"'
|
||||||
|
|
||||||
|
|
||||||
@override_settings(ROOT_URLCONF='tests.test_authentication')
|
@override_settings(ROOT_URLCONF='tests.test_authentication')
|
||||||
|
@ -175,9 +175,8 @@ class SessionAuthTests(TestCase):
|
||||||
cf. [#1810](https://github.com/tomchristie/django-rest-framework/pull/1810)
|
cf. [#1810](https://github.com/tomchristie/django-rest-framework/pull/1810)
|
||||||
"""
|
"""
|
||||||
response = self.csrf_client.get('/auth/login/')
|
response = self.csrf_client.get('/auth/login/')
|
||||||
self.assertContains(
|
content = response.content.decode('utf8')
|
||||||
response, '<label for="id_username">Username:</label>'
|
assert '<label for="id_username">Username:</label>' in content
|
||||||
)
|
|
||||||
|
|
||||||
def test_post_form_session_auth_failing_csrf(self):
|
def test_post_form_session_auth_failing_csrf(self):
|
||||||
"""
|
"""
|
||||||
|
@ -185,7 +184,7 @@ class SessionAuthTests(TestCase):
|
||||||
"""
|
"""
|
||||||
self.csrf_client.login(username=self.username, password=self.password)
|
self.csrf_client.login(username=self.username, password=self.password)
|
||||||
response = self.csrf_client.post('/session/', {'example': 'example'})
|
response = self.csrf_client.post('/session/', {'example': 'example'})
|
||||||
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
|
assert response.status_code == status.HTTP_403_FORBIDDEN
|
||||||
|
|
||||||
def test_post_form_session_auth_passing(self):
|
def test_post_form_session_auth_passing(self):
|
||||||
"""
|
"""
|
||||||
|
@ -198,7 +197,7 @@ class SessionAuthTests(TestCase):
|
||||||
response = self.non_csrf_client.post(
|
response = self.non_csrf_client.post(
|
||||||
'/session/', {'example': 'example'}
|
'/session/', {'example': 'example'}
|
||||||
)
|
)
|
||||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
assert response.status_code == status.HTTP_200_OK
|
||||||
|
|
||||||
def test_put_form_session_auth_passing(self):
|
def test_put_form_session_auth_passing(self):
|
||||||
"""
|
"""
|
||||||
|
@ -211,14 +210,14 @@ class SessionAuthTests(TestCase):
|
||||||
response = self.non_csrf_client.put(
|
response = self.non_csrf_client.put(
|
||||||
'/session/', {'example': 'example'}
|
'/session/', {'example': 'example'}
|
||||||
)
|
)
|
||||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
assert response.status_code == status.HTTP_200_OK
|
||||||
|
|
||||||
def test_post_form_session_auth_failing(self):
|
def test_post_form_session_auth_failing(self):
|
||||||
"""
|
"""
|
||||||
Ensure POSTing form over session authentication without logged in user fails.
|
Ensure POSTing form over session authentication without logged in user fails.
|
||||||
"""
|
"""
|
||||||
response = self.csrf_client.post('/session/', {'example': 'example'})
|
response = self.csrf_client.post('/session/', {'example': 'example'})
|
||||||
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
|
assert response.status_code == status.HTTP_403_FORBIDDEN
|
||||||
|
|
||||||
|
|
||||||
class BaseTokenAuthTests(object):
|
class BaseTokenAuthTests(object):
|
||||||
|
@ -248,7 +247,7 @@ class BaseTokenAuthTests(object):
|
||||||
response = self.csrf_client.post(
|
response = self.csrf_client.post(
|
||||||
self.path, {'example': 'example'}, HTTP_AUTHORIZATION=auth
|
self.path, {'example': 'example'}, HTTP_AUTHORIZATION=auth
|
||||||
)
|
)
|
||||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
assert response.status_code == status.HTTP_200_OK
|
||||||
|
|
||||||
def test_fail_post_form_passing_nonexistent_token_auth(self):
|
def test_fail_post_form_passing_nonexistent_token_auth(self):
|
||||||
# use a nonexistent token key
|
# use a nonexistent token key
|
||||||
|
@ -256,7 +255,7 @@ class BaseTokenAuthTests(object):
|
||||||
response = self.csrf_client.post(
|
response = self.csrf_client.post(
|
||||||
self.path, {'example': 'example'}, HTTP_AUTHORIZATION=auth
|
self.path, {'example': 'example'}, HTTP_AUTHORIZATION=auth
|
||||||
)
|
)
|
||||||
self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
|
assert response.status_code == status.HTTP_401_UNAUTHORIZED
|
||||||
|
|
||||||
def test_fail_post_form_passing_invalid_token_auth(self):
|
def test_fail_post_form_passing_invalid_token_auth(self):
|
||||||
# add an 'invalid' unicode character
|
# add an 'invalid' unicode character
|
||||||
|
@ -264,7 +263,7 @@ class BaseTokenAuthTests(object):
|
||||||
response = self.csrf_client.post(
|
response = self.csrf_client.post(
|
||||||
self.path, {'example': 'example'}, HTTP_AUTHORIZATION=auth
|
self.path, {'example': 'example'}, HTTP_AUTHORIZATION=auth
|
||||||
)
|
)
|
||||||
self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
|
assert response.status_code == status.HTTP_401_UNAUTHORIZED
|
||||||
|
|
||||||
def test_post_json_passing_token_auth(self):
|
def test_post_json_passing_token_auth(self):
|
||||||
"""
|
"""
|
||||||
|
@ -276,7 +275,7 @@ class BaseTokenAuthTests(object):
|
||||||
self.path, {'example': 'example'},
|
self.path, {'example': 'example'},
|
||||||
format='json', HTTP_AUTHORIZATION=auth
|
format='json', HTTP_AUTHORIZATION=auth
|
||||||
)
|
)
|
||||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
assert response.status_code == status.HTTP_200_OK
|
||||||
|
|
||||||
def test_post_json_makes_one_db_query(self):
|
def test_post_json_makes_one_db_query(self):
|
||||||
"""
|
"""
|
||||||
|
@ -298,7 +297,7 @@ class BaseTokenAuthTests(object):
|
||||||
Ensure POSTing form over token auth without correct credentials fails
|
Ensure POSTing form over token auth without correct credentials fails
|
||||||
"""
|
"""
|
||||||
response = self.csrf_client.post(self.path, {'example': 'example'})
|
response = self.csrf_client.post(self.path, {'example': 'example'})
|
||||||
self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
|
assert response.status_code == status.HTTP_401_UNAUTHORIZED
|
||||||
|
|
||||||
def test_post_json_failing_token_auth(self):
|
def test_post_json_failing_token_auth(self):
|
||||||
"""
|
"""
|
||||||
|
@ -307,7 +306,7 @@ class BaseTokenAuthTests(object):
|
||||||
response = self.csrf_client.post(
|
response = self.csrf_client.post(
|
||||||
self.path, {'example': 'example'}, format='json'
|
self.path, {'example': 'example'}, format='json'
|
||||||
)
|
)
|
||||||
self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
|
assert response.status_code == status.HTTP_401_UNAUTHORIZED
|
||||||
|
|
||||||
|
|
||||||
@override_settings(ROOT_URLCONF='tests.test_authentication')
|
@override_settings(ROOT_URLCONF='tests.test_authentication')
|
||||||
|
@ -319,13 +318,13 @@ class TokenAuthTests(BaseTokenAuthTests, TestCase):
|
||||||
"""Ensure creating a token with no key will auto-assign a key"""
|
"""Ensure creating a token with no key will auto-assign a key"""
|
||||||
self.token.delete()
|
self.token.delete()
|
||||||
token = self.model.objects.create(user=self.user)
|
token = self.model.objects.create(user=self.user)
|
||||||
self.assertTrue(bool(token.key))
|
assert bool(token.key)
|
||||||
|
|
||||||
def test_generate_key_returns_string(self):
|
def test_generate_key_returns_string(self):
|
||||||
"""Ensure generate_key returns a string"""
|
"""Ensure generate_key returns a string"""
|
||||||
token = self.model()
|
token = self.model()
|
||||||
key = token.generate_key()
|
key = token.generate_key()
|
||||||
self.assertTrue(isinstance(key, six.string_types))
|
assert isinstance(key, six.string_types)
|
||||||
|
|
||||||
def test_token_login_json(self):
|
def test_token_login_json(self):
|
||||||
"""Ensure token login view using JSON POST works."""
|
"""Ensure token login view using JSON POST works."""
|
||||||
|
@ -335,8 +334,8 @@ class TokenAuthTests(BaseTokenAuthTests, TestCase):
|
||||||
{'username': self.username, 'password': self.password},
|
{'username': self.username, 'password': self.password},
|
||||||
format='json'
|
format='json'
|
||||||
)
|
)
|
||||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
assert response.status_code == status.HTTP_200_OK
|
||||||
self.assertEqual(response.data['token'], self.key)
|
assert response.data['token'] == self.key
|
||||||
|
|
||||||
def test_token_login_json_bad_creds(self):
|
def test_token_login_json_bad_creds(self):
|
||||||
"""
|
"""
|
||||||
|
@ -349,22 +348,24 @@ class TokenAuthTests(BaseTokenAuthTests, TestCase):
|
||||||
{'username': self.username, 'password': "badpass"},
|
{'username': self.username, 'password': "badpass"},
|
||||||
format='json'
|
format='json'
|
||||||
)
|
)
|
||||||
self.assertEqual(response.status_code, 400)
|
assert response.status_code == 400
|
||||||
|
|
||||||
def test_token_login_json_missing_fields(self):
|
def test_token_login_json_missing_fields(self):
|
||||||
"""Ensure token login view using JSON POST fails if missing fields."""
|
"""Ensure token login view using JSON POST fails if missing fields."""
|
||||||
client = APIClient(enforce_csrf_checks=True)
|
client = APIClient(enforce_csrf_checks=True)
|
||||||
response = client.post('/auth-token/',
|
response = client.post('/auth-token/',
|
||||||
{'username': self.username}, format='json')
|
{'username': self.username}, format='json')
|
||||||
self.assertEqual(response.status_code, 400)
|
assert response.status_code == 400
|
||||||
|
|
||||||
def test_token_login_form(self):
|
def test_token_login_form(self):
|
||||||
"""Ensure token login view using form POST works."""
|
"""Ensure token login view using form POST works."""
|
||||||
client = APIClient(enforce_csrf_checks=True)
|
client = APIClient(enforce_csrf_checks=True)
|
||||||
response = client.post('/auth-token/',
|
response = client.post(
|
||||||
{'username': self.username, 'password': self.password})
|
'/auth-token/',
|
||||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
{'username': self.username, 'password': self.password}
|
||||||
self.assertEqual(response.data['token'], self.key)
|
)
|
||||||
|
assert response.status_code == status.HTTP_200_OK
|
||||||
|
assert response.data['token'] == self.key
|
||||||
|
|
||||||
|
|
||||||
@override_settings(ROOT_URLCONF='tests.test_authentication')
|
@override_settings(ROOT_URLCONF='tests.test_authentication')
|
||||||
|
@ -397,8 +398,8 @@ class IncorrectCredentialsTests(TestCase):
|
||||||
permission_classes=()
|
permission_classes=()
|
||||||
)
|
)
|
||||||
response = view(request)
|
response = view(request)
|
||||||
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
|
assert response.status_code == status.HTTP_403_FORBIDDEN
|
||||||
self.assertEqual(response.data, {'detail': 'Bad credentials'})
|
assert response.data == {'detail': 'Bad credentials'}
|
||||||
|
|
||||||
|
|
||||||
class FailingAuthAccessedInRenderer(TestCase):
|
class FailingAuthAccessedInRenderer(TestCase):
|
||||||
|
@ -435,7 +436,7 @@ class FailingAuthAccessedInRenderer(TestCase):
|
||||||
request = factory.get('/')
|
request = factory.get('/')
|
||||||
response = self.view(request)
|
response = self.view(request)
|
||||||
content = response.render().content
|
content = response.render().content
|
||||||
self.assertEqual(content, b'not authenticated')
|
assert content == b'not authenticated'
|
||||||
|
|
||||||
|
|
||||||
class NoAuthenticationClassesTests(TestCase):
|
class NoAuthenticationClassesTests(TestCase):
|
||||||
|
@ -458,6 +459,5 @@ class NoAuthenticationClassesTests(TestCase):
|
||||||
permission_classes=(DummyPermission,),
|
permission_classes=(DummyPermission,),
|
||||||
)
|
)
|
||||||
response = view(request)
|
response = view(request)
|
||||||
self.assertEqual(response.status_code,
|
assert response.status_code == status.HTTP_403_FORBIDDEN
|
||||||
status.HTTP_403_FORBIDDEN)
|
assert response.data == {'detail': 'Dummy permission message'}
|
||||||
self.assertEqual(response.data, {'detail': 'Dummy permission message'})
|
|
||||||
|
|
|
@ -56,11 +56,11 @@ class DecoratorTestCase(TestCase):
|
||||||
|
|
||||||
request = self.factory.get('/')
|
request = self.factory.get('/')
|
||||||
response = view(request)
|
response = view(request)
|
||||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
assert response.status_code == status.HTTP_200_OK
|
||||||
|
|
||||||
request = self.factory.post('/')
|
request = self.factory.post('/')
|
||||||
response = view(request)
|
response = view(request)
|
||||||
self.assertEqual(response.status_code, status.HTTP_405_METHOD_NOT_ALLOWED)
|
assert response.status_code == status.HTTP_405_METHOD_NOT_ALLOWED
|
||||||
|
|
||||||
def test_calling_put_method(self):
|
def test_calling_put_method(self):
|
||||||
|
|
||||||
|
@ -70,11 +70,11 @@ class DecoratorTestCase(TestCase):
|
||||||
|
|
||||||
request = self.factory.put('/')
|
request = self.factory.put('/')
|
||||||
response = view(request)
|
response = view(request)
|
||||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
assert response.status_code == status.HTTP_200_OK
|
||||||
|
|
||||||
request = self.factory.post('/')
|
request = self.factory.post('/')
|
||||||
response = view(request)
|
response = view(request)
|
||||||
self.assertEqual(response.status_code, status.HTTP_405_METHOD_NOT_ALLOWED)
|
assert response.status_code == status.HTTP_405_METHOD_NOT_ALLOWED
|
||||||
|
|
||||||
def test_calling_patch_method(self):
|
def test_calling_patch_method(self):
|
||||||
|
|
||||||
|
@ -84,11 +84,11 @@ class DecoratorTestCase(TestCase):
|
||||||
|
|
||||||
request = self.factory.patch('/')
|
request = self.factory.patch('/')
|
||||||
response = view(request)
|
response = view(request)
|
||||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
assert response.status_code == status.HTTP_200_OK
|
||||||
|
|
||||||
request = self.factory.post('/')
|
request = self.factory.post('/')
|
||||||
response = view(request)
|
response = view(request)
|
||||||
self.assertEqual(response.status_code, status.HTTP_405_METHOD_NOT_ALLOWED)
|
assert response.status_code == status.HTTP_405_METHOD_NOT_ALLOWED
|
||||||
|
|
||||||
def test_renderer_classes(self):
|
def test_renderer_classes(self):
|
||||||
|
|
||||||
|
@ -99,16 +99,15 @@ class DecoratorTestCase(TestCase):
|
||||||
|
|
||||||
request = self.factory.get('/')
|
request = self.factory.get('/')
|
||||||
response = view(request)
|
response = view(request)
|
||||||
self.assertTrue(isinstance(response.accepted_renderer, JSONRenderer))
|
assert isinstance(response.accepted_renderer, JSONRenderer)
|
||||||
|
|
||||||
def test_parser_classes(self):
|
def test_parser_classes(self):
|
||||||
|
|
||||||
@api_view(['GET'])
|
@api_view(['GET'])
|
||||||
@parser_classes([JSONParser])
|
@parser_classes([JSONParser])
|
||||||
def view(request):
|
def view(request):
|
||||||
self.assertEqual(len(request.parsers), 1)
|
assert len(request.parsers) == 1
|
||||||
self.assertTrue(isinstance(request.parsers[0],
|
assert isinstance(request.parsers[0], JSONParser)
|
||||||
JSONParser))
|
|
||||||
return Response({})
|
return Response({})
|
||||||
|
|
||||||
request = self.factory.get('/')
|
request = self.factory.get('/')
|
||||||
|
@ -119,9 +118,8 @@ class DecoratorTestCase(TestCase):
|
||||||
@api_view(['GET'])
|
@api_view(['GET'])
|
||||||
@authentication_classes([BasicAuthentication])
|
@authentication_classes([BasicAuthentication])
|
||||||
def view(request):
|
def view(request):
|
||||||
self.assertEqual(len(request.authenticators), 1)
|
assert len(request.authenticators) == 1
|
||||||
self.assertTrue(isinstance(request.authenticators[0],
|
assert isinstance(request.authenticators[0], BasicAuthentication)
|
||||||
BasicAuthentication))
|
|
||||||
return Response({})
|
return Response({})
|
||||||
|
|
||||||
request = self.factory.get('/')
|
request = self.factory.get('/')
|
||||||
|
@ -136,7 +134,7 @@ class DecoratorTestCase(TestCase):
|
||||||
|
|
||||||
request = self.factory.get('/')
|
request = self.factory.get('/')
|
||||||
response = view(request)
|
response = view(request)
|
||||||
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
|
assert response.status_code == status.HTTP_403_FORBIDDEN
|
||||||
|
|
||||||
def test_throttle_classes(self):
|
def test_throttle_classes(self):
|
||||||
class OncePerDayUserThrottle(UserRateThrottle):
|
class OncePerDayUserThrottle(UserRateThrottle):
|
||||||
|
@ -149,7 +147,7 @@ class DecoratorTestCase(TestCase):
|
||||||
|
|
||||||
request = self.factory.get('/')
|
request = self.factory.get('/')
|
||||||
response = view(request)
|
response = view(request)
|
||||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
assert response.status_code == status.HTTP_200_OK
|
||||||
|
|
||||||
response = view(request)
|
response = view(request)
|
||||||
self.assertEqual(response.status_code, status.HTTP_429_TOO_MANY_REQUESTS)
|
assert response.status_code == status.HTTP_429_TOO_MANY_REQUESTS
|
||||||
|
|
|
@ -60,7 +60,7 @@ class TestViewNamesAndDescriptions(TestCase):
|
||||||
"""
|
"""
|
||||||
class MockView(APIView):
|
class MockView(APIView):
|
||||||
pass
|
pass
|
||||||
self.assertEqual(MockView().get_view_name(), 'Mock')
|
assert MockView().get_view_name() == 'Mock'
|
||||||
|
|
||||||
def test_view_description_uses_docstring(self):
|
def test_view_description_uses_docstring(self):
|
||||||
"""Ensure view descriptions are based on the docstring."""
|
"""Ensure view descriptions are based on the docstring."""
|
||||||
|
@ -80,7 +80,7 @@ class TestViewNamesAndDescriptions(TestCase):
|
||||||
|
|
||||||
# hash style header #"""
|
# hash style header #"""
|
||||||
|
|
||||||
self.assertEqual(MockView().get_view_description(), DESCRIPTION)
|
assert MockView().get_view_description() == DESCRIPTION
|
||||||
|
|
||||||
def test_view_description_can_be_empty(self):
|
def test_view_description_can_be_empty(self):
|
||||||
"""
|
"""
|
||||||
|
@ -89,7 +89,7 @@ class TestViewNamesAndDescriptions(TestCase):
|
||||||
"""
|
"""
|
||||||
class MockView(APIView):
|
class MockView(APIView):
|
||||||
pass
|
pass
|
||||||
self.assertEqual(MockView().get_view_description(), '')
|
assert MockView().get_view_description() == ''
|
||||||
|
|
||||||
def test_view_description_can_be_promise(self):
|
def test_view_description_can_be_promise(self):
|
||||||
"""
|
"""
|
||||||
|
@ -111,7 +111,7 @@ class TestViewNamesAndDescriptions(TestCase):
|
||||||
class MockView(APIView):
|
class MockView(APIView):
|
||||||
__doc__ = MockLazyStr("a gettext string")
|
__doc__ = MockLazyStr("a gettext string")
|
||||||
|
|
||||||
self.assertEqual(MockView().get_view_description(), 'a gettext string')
|
assert MockView().get_view_description() == 'a gettext string'
|
||||||
|
|
||||||
def test_markdown(self):
|
def test_markdown(self):
|
||||||
"""
|
"""
|
||||||
|
@ -120,7 +120,7 @@ class TestViewNamesAndDescriptions(TestCase):
|
||||||
if apply_markdown:
|
if apply_markdown:
|
||||||
gte_21_match = apply_markdown(DESCRIPTION) == MARKED_DOWN_gte_21
|
gte_21_match = apply_markdown(DESCRIPTION) == MARKED_DOWN_gte_21
|
||||||
lt_21_match = apply_markdown(DESCRIPTION) == MARKED_DOWN_lt_21
|
lt_21_match = apply_markdown(DESCRIPTION) == MARKED_DOWN_lt_21
|
||||||
self.assertTrue(gte_21_match or lt_21_match)
|
assert gte_21_match or lt_21_match
|
||||||
|
|
||||||
|
|
||||||
def test_dedent_tabs():
|
def test_dedent_tabs():
|
||||||
|
|
|
@ -20,21 +20,21 @@ class JSONEncoderTests(TestCase):
|
||||||
Tests encoding a decimal
|
Tests encoding a decimal
|
||||||
"""
|
"""
|
||||||
d = Decimal(3.14)
|
d = Decimal(3.14)
|
||||||
self.assertEqual(d, float(d))
|
assert d == float(d)
|
||||||
|
|
||||||
def test_encode_datetime(self):
|
def test_encode_datetime(self):
|
||||||
"""
|
"""
|
||||||
Tests encoding a datetime object
|
Tests encoding a datetime object
|
||||||
"""
|
"""
|
||||||
current_time = datetime.now()
|
current_time = datetime.now()
|
||||||
self.assertEqual(self.encoder.default(current_time), current_time.isoformat())
|
assert self.encoder.default(current_time) == current_time.isoformat()
|
||||||
|
|
||||||
def test_encode_time(self):
|
def test_encode_time(self):
|
||||||
"""
|
"""
|
||||||
Tests encoding a timezone
|
Tests encoding a timezone
|
||||||
"""
|
"""
|
||||||
current_time = datetime.now().time()
|
current_time = datetime.now().time()
|
||||||
self.assertEqual(self.encoder.default(current_time), current_time.isoformat()[:12])
|
assert self.encoder.default(current_time) == current_time.isoformat()[:12]
|
||||||
|
|
||||||
def test_encode_time_tz(self):
|
def test_encode_time_tz(self):
|
||||||
"""
|
"""
|
||||||
|
@ -64,18 +64,18 @@ class JSONEncoderTests(TestCase):
|
||||||
Tests encoding a date object
|
Tests encoding a date object
|
||||||
"""
|
"""
|
||||||
current_date = date.today()
|
current_date = date.today()
|
||||||
self.assertEqual(self.encoder.default(current_date), current_date.isoformat())
|
assert self.encoder.default(current_date) == current_date.isoformat()
|
||||||
|
|
||||||
def test_encode_timedelta(self):
|
def test_encode_timedelta(self):
|
||||||
"""
|
"""
|
||||||
Tests encoding a timedelta object
|
Tests encoding a timedelta object
|
||||||
"""
|
"""
|
||||||
delta = timedelta(hours=1)
|
delta = timedelta(hours=1)
|
||||||
self.assertEqual(self.encoder.default(delta), str(delta.total_seconds()))
|
assert self.encoder.default(delta) == str(delta.total_seconds())
|
||||||
|
|
||||||
def test_encode_uuid(self):
|
def test_encode_uuid(self):
|
||||||
"""
|
"""
|
||||||
Tests encoding a UUID object
|
Tests encoding a UUID object
|
||||||
"""
|
"""
|
||||||
unique_id = uuid4()
|
unique_id = uuid4()
|
||||||
self.assertEqual(self.encoder.default(unique_id), str(unique_id))
|
assert self.encoder.default(unique_id) == str(unique_id)
|
||||||
|
|
|
@ -16,28 +16,22 @@ class ExceptionTestCase(TestCase):
|
||||||
example = "string"
|
example = "string"
|
||||||
lazy_example = _(example)
|
lazy_example = _(example)
|
||||||
|
|
||||||
self.assertEqual(
|
assert _get_error_details(lazy_example) == example
|
||||||
_get_error_details(lazy_example),
|
|
||||||
example
|
|
||||||
)
|
|
||||||
assert isinstance(
|
assert isinstance(
|
||||||
_get_error_details(lazy_example),
|
_get_error_details(lazy_example),
|
||||||
ErrorDetail
|
ErrorDetail
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertEqual(
|
assert _get_error_details({'nested': lazy_example})['nested'] == example
|
||||||
_get_error_details({'nested': lazy_example})['nested'],
|
|
||||||
example
|
|
||||||
)
|
|
||||||
assert isinstance(
|
assert isinstance(
|
||||||
_get_error_details({'nested': lazy_example})['nested'],
|
_get_error_details({'nested': lazy_example})['nested'],
|
||||||
ErrorDetail
|
ErrorDetail
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertEqual(
|
assert _get_error_details([[lazy_example]])[0][0] == example
|
||||||
_get_error_details([[lazy_example]])[0][0],
|
|
||||||
example
|
|
||||||
)
|
|
||||||
assert isinstance(
|
assert isinstance(
|
||||||
_get_error_details([[lazy_example]])[0][0],
|
_get_error_details([[lazy_example]])[0][0],
|
||||||
ErrorDetail
|
ErrorDetail
|
||||||
|
|
|
@ -1014,16 +1014,16 @@ class TestLocalizedDecimalField(TestCase):
|
||||||
@override_settings(USE_L10N=True, LANGUAGE_CODE='pl')
|
@override_settings(USE_L10N=True, LANGUAGE_CODE='pl')
|
||||||
def test_to_internal_value(self):
|
def test_to_internal_value(self):
|
||||||
field = serializers.DecimalField(max_digits=2, decimal_places=1, localize=True)
|
field = serializers.DecimalField(max_digits=2, decimal_places=1, localize=True)
|
||||||
self.assertEqual(field.to_internal_value('1,1'), Decimal('1.1'))
|
assert field.to_internal_value('1,1') == Decimal('1.1')
|
||||||
|
|
||||||
@override_settings(USE_L10N=True, LANGUAGE_CODE='pl')
|
@override_settings(USE_L10N=True, LANGUAGE_CODE='pl')
|
||||||
def test_to_representation(self):
|
def test_to_representation(self):
|
||||||
field = serializers.DecimalField(max_digits=2, decimal_places=1, localize=True)
|
field = serializers.DecimalField(max_digits=2, decimal_places=1, localize=True)
|
||||||
self.assertEqual(field.to_representation(Decimal('1.1')), '1,1')
|
assert field.to_representation(Decimal('1.1')) == '1,1'
|
||||||
|
|
||||||
def test_localize_forces_coerce_to_string(self):
|
def test_localize_forces_coerce_to_string(self):
|
||||||
field = serializers.DecimalField(max_digits=2, decimal_places=1, coerce_to_string=False, localize=True)
|
field = serializers.DecimalField(max_digits=2, decimal_places=1, coerce_to_string=False, localize=True)
|
||||||
self.assertTrue(isinstance(field.to_representation(Decimal('1.1')), six.string_types))
|
assert isinstance(field.to_representation(Decimal('1.1')), six.string_types)
|
||||||
|
|
||||||
|
|
||||||
class TestQuantizedValueForDecimal(TestCase):
|
class TestQuantizedValueForDecimal(TestCase):
|
||||||
|
@ -1031,19 +1031,19 @@ class TestQuantizedValueForDecimal(TestCase):
|
||||||
field = serializers.DecimalField(max_digits=4, decimal_places=2)
|
field = serializers.DecimalField(max_digits=4, decimal_places=2)
|
||||||
value = field.to_internal_value(12).as_tuple()
|
value = field.to_internal_value(12).as_tuple()
|
||||||
expected_digit_tuple = (0, (1, 2, 0, 0), -2)
|
expected_digit_tuple = (0, (1, 2, 0, 0), -2)
|
||||||
self.assertEqual(value, expected_digit_tuple)
|
assert value == expected_digit_tuple
|
||||||
|
|
||||||
def test_string_quantized_value_for_decimal(self):
|
def test_string_quantized_value_for_decimal(self):
|
||||||
field = serializers.DecimalField(max_digits=4, decimal_places=2)
|
field = serializers.DecimalField(max_digits=4, decimal_places=2)
|
||||||
value = field.to_internal_value('12').as_tuple()
|
value = field.to_internal_value('12').as_tuple()
|
||||||
expected_digit_tuple = (0, (1, 2, 0, 0), -2)
|
expected_digit_tuple = (0, (1, 2, 0, 0), -2)
|
||||||
self.assertEqual(value, expected_digit_tuple)
|
assert value == expected_digit_tuple
|
||||||
|
|
||||||
def test_part_precision_string_quantized_value_for_decimal(self):
|
def test_part_precision_string_quantized_value_for_decimal(self):
|
||||||
field = serializers.DecimalField(max_digits=4, decimal_places=2)
|
field = serializers.DecimalField(max_digits=4, decimal_places=2)
|
||||||
value = field.to_internal_value('12.0').as_tuple()
|
value = field.to_internal_value('12.0').as_tuple()
|
||||||
expected_digit_tuple = (0, (1, 2, 0, 0), -2)
|
expected_digit_tuple = (0, (1, 2, 0, 0), -2)
|
||||||
self.assertEqual(value, expected_digit_tuple)
|
assert value == expected_digit_tuple
|
||||||
|
|
||||||
|
|
||||||
class TestNoDecimalPlaces(FieldValues):
|
class TestNoDecimalPlaces(FieldValues):
|
||||||
|
|
|
@ -155,8 +155,8 @@ class IntegrationTestFiltering(CommonFilteringTestCase):
|
||||||
request = factory.get('/')
|
request = factory.get('/')
|
||||||
response = view(request).render()
|
response = view(request).render()
|
||||||
|
|
||||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
assert response.status_code == status.HTTP_200_OK
|
||||||
self.assertEqual(response.data, self.data)
|
assert response.data == self.data
|
||||||
|
|
||||||
self.assertTrue(issubclass(w[-1].category, PendingDeprecationWarning))
|
self.assertTrue(issubclass(w[-1].category, PendingDeprecationWarning))
|
||||||
self.assertIn("'rest_framework.filters.DjangoFilterBackend' is pending deprecation.", str(w[-1].message))
|
self.assertIn("'rest_framework.filters.DjangoFilterBackend' is pending deprecation.", str(w[-1].message))
|
||||||
|
@ -175,9 +175,9 @@ class IntegrationTestFiltering(CommonFilteringTestCase):
|
||||||
request = factory.get('/')
|
request = factory.get('/')
|
||||||
response = view(request).render()
|
response = view(request).render()
|
||||||
|
|
||||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
assert response.status_code == status.HTTP_200_OK
|
||||||
self.assertEqual(response.data, self.data)
|
assert response.data == self.data
|
||||||
self.assertEqual(len(w), 0)
|
assert len(w) == 0
|
||||||
|
|
||||||
@unittest.skipUnless(django_filters, 'django-filter not installed')
|
@unittest.skipUnless(django_filters, 'django-filter not installed')
|
||||||
def test_get_filtered_fields_root_view(self):
|
def test_get_filtered_fields_root_view(self):
|
||||||
|
@ -189,24 +189,24 @@ class IntegrationTestFiltering(CommonFilteringTestCase):
|
||||||
# Basic test with no filter.
|
# Basic test with no filter.
|
||||||
request = factory.get('/')
|
request = factory.get('/')
|
||||||
response = view(request).render()
|
response = view(request).render()
|
||||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
assert response.status_code == status.HTTP_200_OK
|
||||||
self.assertEqual(response.data, self.data)
|
assert response.data == self.data
|
||||||
|
|
||||||
# Tests that the decimal filter works.
|
# Tests that the decimal filter works.
|
||||||
search_decimal = Decimal('2.25')
|
search_decimal = Decimal('2.25')
|
||||||
request = factory.get('/', {'decimal': '%s' % search_decimal})
|
request = factory.get('/', {'decimal': '%s' % search_decimal})
|
||||||
response = view(request).render()
|
response = view(request).render()
|
||||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
assert response.status_code == status.HTTP_200_OK
|
||||||
expected_data = [f for f in self.data if Decimal(f['decimal']) == search_decimal]
|
expected_data = [f for f in self.data if Decimal(f['decimal']) == search_decimal]
|
||||||
self.assertEqual(response.data, expected_data)
|
assert response.data == expected_data
|
||||||
|
|
||||||
# Tests that the date filter works.
|
# Tests that the date filter works.
|
||||||
search_date = datetime.date(2012, 9, 22)
|
search_date = datetime.date(2012, 9, 22)
|
||||||
request = factory.get('/', {'date': '%s' % search_date}) # search_date str: '2012-09-22'
|
request = factory.get('/', {'date': '%s' % search_date}) # search_date str: '2012-09-22'
|
||||||
response = view(request).render()
|
response = view(request).render()
|
||||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
assert response.status_code == status.HTTP_200_OK
|
||||||
expected_data = [f for f in self.data if parse_date(f['date']) == search_date]
|
expected_data = [f for f in self.data if parse_date(f['date']) == search_date]
|
||||||
self.assertEqual(response.data, expected_data)
|
assert response.data == expected_data
|
||||||
|
|
||||||
@unittest.skipUnless(django_filters, 'django-filter not installed')
|
@unittest.skipUnless(django_filters, 'django-filter not installed')
|
||||||
def test_filter_with_queryset(self):
|
def test_filter_with_queryset(self):
|
||||||
|
@ -219,9 +219,9 @@ class IntegrationTestFiltering(CommonFilteringTestCase):
|
||||||
search_decimal = Decimal('2.25')
|
search_decimal = Decimal('2.25')
|
||||||
request = factory.get('/', {'decimal': '%s' % search_decimal})
|
request = factory.get('/', {'decimal': '%s' % search_decimal})
|
||||||
response = view(request).render()
|
response = view(request).render()
|
||||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
assert response.status_code == status.HTTP_200_OK
|
||||||
expected_data = [f for f in self.data if Decimal(f['decimal']) == search_decimal]
|
expected_data = [f for f in self.data if Decimal(f['decimal']) == search_decimal]
|
||||||
self.assertEqual(response.data, expected_data)
|
assert response.data == expected_data
|
||||||
|
|
||||||
@unittest.skipUnless(django_filters, 'django-filter not installed')
|
@unittest.skipUnless(django_filters, 'django-filter not installed')
|
||||||
def test_filter_with_get_queryset_only(self):
|
def test_filter_with_get_queryset_only(self):
|
||||||
|
@ -245,32 +245,32 @@ class IntegrationTestFiltering(CommonFilteringTestCase):
|
||||||
# Basic test with no filter.
|
# Basic test with no filter.
|
||||||
request = factory.get('/')
|
request = factory.get('/')
|
||||||
response = view(request).render()
|
response = view(request).render()
|
||||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
assert response.status_code == status.HTTP_200_OK
|
||||||
self.assertEqual(response.data, self.data)
|
assert response.data == self.data
|
||||||
|
|
||||||
# Tests that the decimal filter set with 'lt' in the filter class works.
|
# Tests that the decimal filter set with 'lt' in the filter class works.
|
||||||
search_decimal = Decimal('4.25')
|
search_decimal = Decimal('4.25')
|
||||||
request = factory.get('/', {'decimal': '%s' % search_decimal})
|
request = factory.get('/', {'decimal': '%s' % search_decimal})
|
||||||
response = view(request).render()
|
response = view(request).render()
|
||||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
assert response.status_code == status.HTTP_200_OK
|
||||||
expected_data = [f for f in self.data if Decimal(f['decimal']) < search_decimal]
|
expected_data = [f for f in self.data if Decimal(f['decimal']) < search_decimal]
|
||||||
self.assertEqual(response.data, expected_data)
|
assert response.data == expected_data
|
||||||
|
|
||||||
# Tests that the date filter set with 'gt' in the filter class works.
|
# Tests that the date filter set with 'gt' in the filter class works.
|
||||||
search_date = datetime.date(2012, 10, 2)
|
search_date = datetime.date(2012, 10, 2)
|
||||||
request = factory.get('/', {'date': '%s' % search_date}) # search_date str: '2012-10-02'
|
request = factory.get('/', {'date': '%s' % search_date}) # search_date str: '2012-10-02'
|
||||||
response = view(request).render()
|
response = view(request).render()
|
||||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
assert response.status_code == status.HTTP_200_OK
|
||||||
expected_data = [f for f in self.data if parse_date(f['date']) > search_date]
|
expected_data = [f for f in self.data if parse_date(f['date']) > search_date]
|
||||||
self.assertEqual(response.data, expected_data)
|
assert response.data == expected_data
|
||||||
|
|
||||||
# Tests that the text filter set with 'icontains' in the filter class works.
|
# Tests that the text filter set with 'icontains' in the filter class works.
|
||||||
search_text = 'ff'
|
search_text = 'ff'
|
||||||
request = factory.get('/', {'text': '%s' % search_text})
|
request = factory.get('/', {'text': '%s' % search_text})
|
||||||
response = view(request).render()
|
response = view(request).render()
|
||||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
assert response.status_code == status.HTTP_200_OK
|
||||||
expected_data = [f for f in self.data if search_text in f['text'].lower()]
|
expected_data = [f for f in self.data if search_text in f['text'].lower()]
|
||||||
self.assertEqual(response.data, expected_data)
|
assert response.data == expected_data
|
||||||
|
|
||||||
# Tests that multiple filters works.
|
# Tests that multiple filters works.
|
||||||
search_decimal = Decimal('5.25')
|
search_decimal = Decimal('5.25')
|
||||||
|
@ -280,10 +280,10 @@ class IntegrationTestFiltering(CommonFilteringTestCase):
|
||||||
'date': '%s' % (search_date,)
|
'date': '%s' % (search_date,)
|
||||||
})
|
})
|
||||||
response = view(request).render()
|
response = view(request).render()
|
||||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
assert response.status_code == status.HTTP_200_OK
|
||||||
expected_data = [f for f in self.data if parse_date(f['date']) > search_date and
|
expected_data = [f for f in self.data if parse_date(f['date']) > search_date and
|
||||||
Decimal(f['decimal']) < search_decimal]
|
Decimal(f['decimal']) < search_decimal]
|
||||||
self.assertEqual(response.data, expected_data)
|
assert response.data == expected_data
|
||||||
|
|
||||||
@unittest.skipUnless(django_filters, 'django-filter not installed')
|
@unittest.skipUnless(django_filters, 'django-filter not installed')
|
||||||
def test_incorrectly_configured_filter(self):
|
def test_incorrectly_configured_filter(self):
|
||||||
|
@ -304,8 +304,8 @@ class IntegrationTestFiltering(CommonFilteringTestCase):
|
||||||
|
|
||||||
request = factory.get('/?text=aaa')
|
request = factory.get('/?text=aaa')
|
||||||
response = view(request).render()
|
response = view(request).render()
|
||||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
assert response.status_code == status.HTTP_200_OK
|
||||||
self.assertEqual(len(response.data), 1)
|
assert len(response.data) == 1
|
||||||
|
|
||||||
@unittest.skipUnless(django_filters, 'django-filter not installed')
|
@unittest.skipUnless(django_filters, 'django-filter not installed')
|
||||||
def test_base_model_filter_with_proxy(self):
|
def test_base_model_filter_with_proxy(self):
|
||||||
|
@ -316,8 +316,8 @@ class IntegrationTestFiltering(CommonFilteringTestCase):
|
||||||
|
|
||||||
request = factory.get('/?text=aaa')
|
request = factory.get('/?text=aaa')
|
||||||
response = view(request).render()
|
response = view(request).render()
|
||||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
assert response.status_code == status.HTTP_200_OK
|
||||||
self.assertEqual(len(response.data), 1)
|
assert len(response.data) == 1
|
||||||
|
|
||||||
@unittest.skipUnless(django_filters, 'django-filter not installed')
|
@unittest.skipUnless(django_filters, 'django-filter not installed')
|
||||||
def test_unknown_filter(self):
|
def test_unknown_filter(self):
|
||||||
|
@ -329,7 +329,7 @@ class IntegrationTestFiltering(CommonFilteringTestCase):
|
||||||
search_integer = 10
|
search_integer = 10
|
||||||
request = factory.get('/', {'integer': '%s' % search_integer})
|
request = factory.get('/', {'integer': '%s' % search_integer})
|
||||||
response = view(request).render()
|
response = view(request).render()
|
||||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
assert response.status_code == status.HTTP_200_OK
|
||||||
|
|
||||||
|
|
||||||
@override_settings(ROOT_URLCONF='tests.test_filters')
|
@override_settings(ROOT_URLCONF='tests.test_filters')
|
||||||
|
@ -351,8 +351,8 @@ class IntegrationTestDetailFiltering(CommonFilteringTestCase):
|
||||||
|
|
||||||
# Basic test with no filter.
|
# Basic test with no filter.
|
||||||
response = self.client.get(self._get_url(item))
|
response = self.client.get(self._get_url(item))
|
||||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
assert response.status_code == status.HTTP_200_OK
|
||||||
self.assertEqual(response.data, data)
|
assert response.data == data
|
||||||
|
|
||||||
# Tests that the decimal filter set that should fail.
|
# Tests that the decimal filter set that should fail.
|
||||||
search_decimal = Decimal('4.25')
|
search_decimal = Decimal('4.25')
|
||||||
|
@ -360,7 +360,7 @@ class IntegrationTestDetailFiltering(CommonFilteringTestCase):
|
||||||
response = self.client.get(
|
response = self.client.get(
|
||||||
'{url}'.format(url=self._get_url(high_item)),
|
'{url}'.format(url=self._get_url(high_item)),
|
||||||
{'decimal': '{param}'.format(param=search_decimal)})
|
{'decimal': '{param}'.format(param=search_decimal)})
|
||||||
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
|
assert response.status_code == status.HTTP_404_NOT_FOUND
|
||||||
|
|
||||||
# Tests that the decimal filter set that should succeed.
|
# Tests that the decimal filter set that should succeed.
|
||||||
search_decimal = Decimal('4.25')
|
search_decimal = Decimal('4.25')
|
||||||
|
@ -369,8 +369,8 @@ class IntegrationTestDetailFiltering(CommonFilteringTestCase):
|
||||||
response = self.client.get(
|
response = self.client.get(
|
||||||
'{url}'.format(url=self._get_url(low_item)),
|
'{url}'.format(url=self._get_url(low_item)),
|
||||||
{'decimal': '{param}'.format(param=search_decimal)})
|
{'decimal': '{param}'.format(param=search_decimal)})
|
||||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
assert response.status_code == status.HTTP_200_OK
|
||||||
self.assertEqual(response.data, low_item_data)
|
assert response.data == low_item_data
|
||||||
|
|
||||||
# Tests that multiple filters works.
|
# Tests that multiple filters works.
|
||||||
search_decimal = Decimal('5.25')
|
search_decimal = Decimal('5.25')
|
||||||
|
@ -382,8 +382,8 @@ class IntegrationTestDetailFiltering(CommonFilteringTestCase):
|
||||||
'decimal': '{decimal}'.format(decimal=search_decimal),
|
'decimal': '{decimal}'.format(decimal=search_decimal),
|
||||||
'date': '{date}'.format(date=search_date)
|
'date': '{date}'.format(date=search_date)
|
||||||
})
|
})
|
||||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
assert response.status_code == status.HTTP_200_OK
|
||||||
self.assertEqual(response.data, valid_item_data)
|
assert response.data == valid_item_data
|
||||||
|
|
||||||
|
|
||||||
class SearchFilterModel(models.Model):
|
class SearchFilterModel(models.Model):
|
||||||
|
@ -424,13 +424,10 @@ class SearchFilterTests(TestCase):
|
||||||
view = SearchListView.as_view()
|
view = SearchListView.as_view()
|
||||||
request = factory.get('/', {'search': 'b'})
|
request = factory.get('/', {'search': 'b'})
|
||||||
response = view(request)
|
response = view(request)
|
||||||
self.assertEqual(
|
assert response.data == [
|
||||||
response.data,
|
{'id': 1, 'title': 'z', 'text': 'abc'},
|
||||||
[
|
{'id': 2, 'title': 'zz', 'text': 'bcd'}
|
||||||
{'id': 1, 'title': 'z', 'text': 'abc'},
|
]
|
||||||
{'id': 2, 'title': 'zz', 'text': 'bcd'}
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_exact_search(self):
|
def test_exact_search(self):
|
||||||
class SearchListView(generics.ListAPIView):
|
class SearchListView(generics.ListAPIView):
|
||||||
|
@ -442,12 +439,9 @@ class SearchFilterTests(TestCase):
|
||||||
view = SearchListView.as_view()
|
view = SearchListView.as_view()
|
||||||
request = factory.get('/', {'search': 'zzz'})
|
request = factory.get('/', {'search': 'zzz'})
|
||||||
response = view(request)
|
response = view(request)
|
||||||
self.assertEqual(
|
assert response.data == [
|
||||||
response.data,
|
{'id': 3, 'title': 'zzz', 'text': 'cde'}
|
||||||
[
|
]
|
||||||
{'id': 3, 'title': 'zzz', 'text': 'cde'}
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_startswith_search(self):
|
def test_startswith_search(self):
|
||||||
class SearchListView(generics.ListAPIView):
|
class SearchListView(generics.ListAPIView):
|
||||||
|
@ -459,12 +453,9 @@ class SearchFilterTests(TestCase):
|
||||||
view = SearchListView.as_view()
|
view = SearchListView.as_view()
|
||||||
request = factory.get('/', {'search': 'b'})
|
request = factory.get('/', {'search': 'b'})
|
||||||
response = view(request)
|
response = view(request)
|
||||||
self.assertEqual(
|
assert response.data == [
|
||||||
response.data,
|
{'id': 2, 'title': 'zz', 'text': 'bcd'}
|
||||||
[
|
]
|
||||||
{'id': 2, 'title': 'zz', 'text': 'bcd'}
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_regexp_search(self):
|
def test_regexp_search(self):
|
||||||
class SearchListView(generics.ListAPIView):
|
class SearchListView(generics.ListAPIView):
|
||||||
|
@ -476,12 +467,9 @@ class SearchFilterTests(TestCase):
|
||||||
view = SearchListView.as_view()
|
view = SearchListView.as_view()
|
||||||
request = factory.get('/', {'search': 'z{2} ^b'})
|
request = factory.get('/', {'search': 'z{2} ^b'})
|
||||||
response = view(request)
|
response = view(request)
|
||||||
self.assertEqual(
|
assert response.data == [
|
||||||
response.data,
|
{'id': 2, 'title': 'zz', 'text': 'bcd'}
|
||||||
[
|
]
|
||||||
{'id': 2, 'title': 'zz', 'text': 'bcd'}
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_search_with_nonstandard_search_param(self):
|
def test_search_with_nonstandard_search_param(self):
|
||||||
with override_settings(REST_FRAMEWORK={'SEARCH_PARAM': 'query'}):
|
with override_settings(REST_FRAMEWORK={'SEARCH_PARAM': 'query'}):
|
||||||
|
@ -496,13 +484,10 @@ class SearchFilterTests(TestCase):
|
||||||
view = SearchListView.as_view()
|
view = SearchListView.as_view()
|
||||||
request = factory.get('/', {'query': 'b'})
|
request = factory.get('/', {'query': 'b'})
|
||||||
response = view(request)
|
response = view(request)
|
||||||
self.assertEqual(
|
assert response.data == [
|
||||||
response.data,
|
{'id': 1, 'title': 'z', 'text': 'abc'},
|
||||||
[
|
{'id': 2, 'title': 'zz', 'text': 'bcd'}
|
||||||
{'id': 1, 'title': 'z', 'text': 'abc'},
|
]
|
||||||
{'id': 2, 'title': 'zz', 'text': 'bcd'}
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
reload_module(filters)
|
reload_module(filters)
|
||||||
|
|
||||||
|
@ -528,15 +513,13 @@ class SearchFilterFkTests(TestCase):
|
||||||
filter_ = filters.SearchFilter()
|
filter_ = filters.SearchFilter()
|
||||||
prefixes = [''] + list(filter_.lookup_prefixes)
|
prefixes = [''] + list(filter_.lookup_prefixes)
|
||||||
for prefix in prefixes:
|
for prefix in prefixes:
|
||||||
self.assertFalse(
|
assert not filter_.must_call_distinct(
|
||||||
filter_.must_call_distinct(
|
SearchFilterModelFk._meta,
|
||||||
SearchFilterModelFk._meta, ["%stitle" % prefix]
|
["%stitle" % prefix]
|
||||||
)
|
|
||||||
)
|
)
|
||||||
self.assertFalse(
|
assert not filter_.must_call_distinct(
|
||||||
filter_.must_call_distinct(
|
SearchFilterModelFk._meta,
|
||||||
SearchFilterModelFk._meta, ["%stitle" % prefix, "%sattribute__label" % prefix]
|
["%stitle" % prefix, "%sattribute__label" % prefix]
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_must_call_distinct_restores_meta_for_each_field(self):
|
def test_must_call_distinct_restores_meta_for_each_field(self):
|
||||||
|
@ -545,10 +528,9 @@ class SearchFilterFkTests(TestCase):
|
||||||
filter_ = filters.SearchFilter()
|
filter_ = filters.SearchFilter()
|
||||||
prefixes = [''] + list(filter_.lookup_prefixes)
|
prefixes = [''] + list(filter_.lookup_prefixes)
|
||||||
for prefix in prefixes:
|
for prefix in prefixes:
|
||||||
self.assertFalse(
|
assert not filter_.must_call_distinct(
|
||||||
filter_.must_call_distinct(
|
SearchFilterModelFk._meta,
|
||||||
SearchFilterModelFk._meta, ["%sattribute__label" % prefix, "%stitle" % prefix]
|
["%sattribute__label" % prefix, "%stitle" % prefix]
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -596,21 +578,20 @@ class SearchFilterM2MTests(TestCase):
|
||||||
view = SearchListView.as_view()
|
view = SearchListView.as_view()
|
||||||
request = factory.get('/', {'search': 'zz'})
|
request = factory.get('/', {'search': 'zz'})
|
||||||
response = view(request)
|
response = view(request)
|
||||||
self.assertEqual(len(response.data), 1)
|
assert len(response.data) == 1
|
||||||
|
|
||||||
def test_must_call_distinct(self):
|
def test_must_call_distinct(self):
|
||||||
filter_ = filters.SearchFilter()
|
filter_ = filters.SearchFilter()
|
||||||
prefixes = [''] + list(filter_.lookup_prefixes)
|
prefixes = [''] + list(filter_.lookup_prefixes)
|
||||||
for prefix in prefixes:
|
for prefix in prefixes:
|
||||||
self.assertFalse(
|
assert not filter_.must_call_distinct(
|
||||||
filter_.must_call_distinct(
|
SearchFilterModelM2M._meta,
|
||||||
SearchFilterModelM2M._meta, ["%stitle" % prefix]
|
["%stitle" % prefix]
|
||||||
)
|
|
||||||
)
|
)
|
||||||
self.assertTrue(
|
|
||||||
filter_.must_call_distinct(
|
assert filter_.must_call_distinct(
|
||||||
SearchFilterModelM2M._meta, ["%stitle" % prefix, "%sattributes__label" % prefix]
|
SearchFilterModelM2M._meta,
|
||||||
)
|
["%stitle" % prefix, "%sattributes__label" % prefix]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -672,14 +653,11 @@ class DjangoFilterOrderingTests(TestCase):
|
||||||
request = factory.get('/')
|
request = factory.get('/')
|
||||||
response = view(request)
|
response = view(request)
|
||||||
|
|
||||||
self.assertEqual(
|
assert response.data == [
|
||||||
response.data,
|
{'id': 3, 'date': '2014-10-08', 'text': 'cde'},
|
||||||
[
|
{'id': 2, 'date': '2013-10-08', 'text': 'bcd'},
|
||||||
{'id': 3, 'date': '2014-10-08', 'text': 'cde'},
|
{'id': 1, 'date': '2012-10-08', 'text': 'abc'}
|
||||||
{'id': 2, 'date': '2013-10-08', 'text': 'bcd'},
|
]
|
||||||
{'id': 1, 'date': '2012-10-08', 'text': 'abc'}
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class OrderingFilterTests(TestCase):
|
class OrderingFilterTests(TestCase):
|
||||||
|
@ -713,14 +691,11 @@ class OrderingFilterTests(TestCase):
|
||||||
view = OrderingListView.as_view()
|
view = OrderingListView.as_view()
|
||||||
request = factory.get('/', {'ordering': 'text'})
|
request = factory.get('/', {'ordering': 'text'})
|
||||||
response = view(request)
|
response = view(request)
|
||||||
self.assertEqual(
|
assert response.data == [
|
||||||
response.data,
|
{'id': 1, 'title': 'zyx', 'text': 'abc'},
|
||||||
[
|
{'id': 2, 'title': 'yxw', 'text': 'bcd'},
|
||||||
{'id': 1, 'title': 'zyx', 'text': 'abc'},
|
{'id': 3, 'title': 'xwv', 'text': 'cde'},
|
||||||
{'id': 2, 'title': 'yxw', 'text': 'bcd'},
|
]
|
||||||
{'id': 3, 'title': 'xwv', 'text': 'cde'},
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_reverse_ordering(self):
|
def test_reverse_ordering(self):
|
||||||
class OrderingListView(generics.ListAPIView):
|
class OrderingListView(generics.ListAPIView):
|
||||||
|
@ -733,14 +708,11 @@ class OrderingFilterTests(TestCase):
|
||||||
view = OrderingListView.as_view()
|
view = OrderingListView.as_view()
|
||||||
request = factory.get('/', {'ordering': '-text'})
|
request = factory.get('/', {'ordering': '-text'})
|
||||||
response = view(request)
|
response = view(request)
|
||||||
self.assertEqual(
|
assert response.data == [
|
||||||
response.data,
|
{'id': 3, 'title': 'xwv', 'text': 'cde'},
|
||||||
[
|
{'id': 2, 'title': 'yxw', 'text': 'bcd'},
|
||||||
{'id': 3, 'title': 'xwv', 'text': 'cde'},
|
{'id': 1, 'title': 'zyx', 'text': 'abc'},
|
||||||
{'id': 2, 'title': 'yxw', 'text': 'bcd'},
|
]
|
||||||
{'id': 1, 'title': 'zyx', 'text': 'abc'},
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_incorrectfield_ordering(self):
|
def test_incorrectfield_ordering(self):
|
||||||
class OrderingListView(generics.ListAPIView):
|
class OrderingListView(generics.ListAPIView):
|
||||||
|
@ -753,14 +725,11 @@ class OrderingFilterTests(TestCase):
|
||||||
view = OrderingListView.as_view()
|
view = OrderingListView.as_view()
|
||||||
request = factory.get('/', {'ordering': 'foobar'})
|
request = factory.get('/', {'ordering': 'foobar'})
|
||||||
response = view(request)
|
response = view(request)
|
||||||
self.assertEqual(
|
assert response.data == [
|
||||||
response.data,
|
{'id': 3, 'title': 'xwv', 'text': 'cde'},
|
||||||
[
|
{'id': 2, 'title': 'yxw', 'text': 'bcd'},
|
||||||
{'id': 3, 'title': 'xwv', 'text': 'cde'},
|
{'id': 1, 'title': 'zyx', 'text': 'abc'},
|
||||||
{'id': 2, 'title': 'yxw', 'text': 'bcd'},
|
]
|
||||||
{'id': 1, 'title': 'zyx', 'text': 'abc'},
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_default_ordering(self):
|
def test_default_ordering(self):
|
||||||
class OrderingListView(generics.ListAPIView):
|
class OrderingListView(generics.ListAPIView):
|
||||||
|
@ -773,14 +742,11 @@ class OrderingFilterTests(TestCase):
|
||||||
view = OrderingListView.as_view()
|
view = OrderingListView.as_view()
|
||||||
request = factory.get('')
|
request = factory.get('')
|
||||||
response = view(request)
|
response = view(request)
|
||||||
self.assertEqual(
|
assert response.data == [
|
||||||
response.data,
|
{'id': 3, 'title': 'xwv', 'text': 'cde'},
|
||||||
[
|
{'id': 2, 'title': 'yxw', 'text': 'bcd'},
|
||||||
{'id': 3, 'title': 'xwv', 'text': 'cde'},
|
{'id': 1, 'title': 'zyx', 'text': 'abc'},
|
||||||
{'id': 2, 'title': 'yxw', 'text': 'bcd'},
|
]
|
||||||
{'id': 1, 'title': 'zyx', 'text': 'abc'},
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_default_ordering_using_string(self):
|
def test_default_ordering_using_string(self):
|
||||||
class OrderingListView(generics.ListAPIView):
|
class OrderingListView(generics.ListAPIView):
|
||||||
|
@ -793,14 +759,11 @@ class OrderingFilterTests(TestCase):
|
||||||
view = OrderingListView.as_view()
|
view = OrderingListView.as_view()
|
||||||
request = factory.get('')
|
request = factory.get('')
|
||||||
response = view(request)
|
response = view(request)
|
||||||
self.assertEqual(
|
assert response.data == [
|
||||||
response.data,
|
{'id': 3, 'title': 'xwv', 'text': 'cde'},
|
||||||
[
|
{'id': 2, 'title': 'yxw', 'text': 'bcd'},
|
||||||
{'id': 3, 'title': 'xwv', 'text': 'cde'},
|
{'id': 1, 'title': 'zyx', 'text': 'abc'},
|
||||||
{'id': 2, 'title': 'yxw', 'text': 'bcd'},
|
]
|
||||||
{'id': 1, 'title': 'zyx', 'text': 'abc'},
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_ordering_by_aggregate_field(self):
|
def test_ordering_by_aggregate_field(self):
|
||||||
# create some related models to aggregate order by
|
# create some related models to aggregate order by
|
||||||
|
@ -824,14 +787,11 @@ class OrderingFilterTests(TestCase):
|
||||||
view = OrderingListView.as_view()
|
view = OrderingListView.as_view()
|
||||||
request = factory.get('/', {'ordering': 'relateds__count'})
|
request = factory.get('/', {'ordering': 'relateds__count'})
|
||||||
response = view(request)
|
response = view(request)
|
||||||
self.assertEqual(
|
assert response.data == [
|
||||||
response.data,
|
{'id': 1, 'title': 'zyx', 'text': 'abc'},
|
||||||
[
|
{'id': 3, 'title': 'xwv', 'text': 'cde'},
|
||||||
{'id': 1, 'title': 'zyx', 'text': 'abc'},
|
{'id': 2, 'title': 'yxw', 'text': 'bcd'},
|
||||||
{'id': 3, 'title': 'xwv', 'text': 'cde'},
|
]
|
||||||
{'id': 2, 'title': 'yxw', 'text': 'bcd'},
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_ordering_with_nonstandard_ordering_param(self):
|
def test_ordering_with_nonstandard_ordering_param(self):
|
||||||
with override_settings(REST_FRAMEWORK={'ORDERING_PARAM': 'order'}):
|
with override_settings(REST_FRAMEWORK={'ORDERING_PARAM': 'order'}):
|
||||||
|
@ -847,14 +807,11 @@ class OrderingFilterTests(TestCase):
|
||||||
view = OrderingListView.as_view()
|
view = OrderingListView.as_view()
|
||||||
request = factory.get('/', {'order': 'text'})
|
request = factory.get('/', {'order': 'text'})
|
||||||
response = view(request)
|
response = view(request)
|
||||||
self.assertEqual(
|
assert response.data == [
|
||||||
response.data,
|
{'id': 1, 'title': 'zyx', 'text': 'abc'},
|
||||||
[
|
{'id': 2, 'title': 'yxw', 'text': 'bcd'},
|
||||||
{'id': 1, 'title': 'zyx', 'text': 'abc'},
|
{'id': 3, 'title': 'xwv', 'text': 'cde'},
|
||||||
{'id': 2, 'title': 'yxw', 'text': 'bcd'},
|
]
|
||||||
{'id': 3, 'title': 'xwv', 'text': 'cde'},
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
reload_module(filters)
|
reload_module(filters)
|
||||||
|
|
||||||
|
@ -884,14 +841,11 @@ class OrderingFilterTests(TestCase):
|
||||||
view = OrderingListView.as_view()
|
view = OrderingListView.as_view()
|
||||||
request = factory.get('/', {'ordering': 'text'})
|
request = factory.get('/', {'ordering': 'text'})
|
||||||
response = view(request)
|
response = view(request)
|
||||||
self.assertEqual(
|
assert response.data == [
|
||||||
response.data,
|
{'id': 1, 'title': 'zyx', 'text': 'abc'},
|
||||||
[
|
{'id': 2, 'title': 'yxw', 'text': 'bcd'},
|
||||||
{'id': 1, 'title': 'zyx', 'text': 'abc'},
|
{'id': 3, 'title': 'xwv', 'text': 'cde'},
|
||||||
{'id': 2, 'title': 'yxw', 'text': 'bcd'},
|
]
|
||||||
{'id': 3, 'title': 'xwv', 'text': 'cde'},
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_ordering_with_improper_configuration(self):
|
def test_ordering_with_improper_configuration(self):
|
||||||
class OrderingListView(generics.ListAPIView):
|
class OrderingListView(generics.ListAPIView):
|
||||||
|
@ -967,14 +921,11 @@ class SensitiveOrderingFilterTests(TestCase):
|
||||||
username_field = 'username'
|
username_field = 'username'
|
||||||
|
|
||||||
# Note: Inverse username ordering correctly applied.
|
# Note: Inverse username ordering correctly applied.
|
||||||
self.assertEqual(
|
assert response.data == [
|
||||||
response.data,
|
{'id': 3, username_field: 'userC'},
|
||||||
[
|
{'id': 2, username_field: 'userB'},
|
||||||
{'id': 3, username_field: 'userC'},
|
{'id': 1, username_field: 'userA'},
|
||||||
{'id': 2, username_field: 'userB'},
|
]
|
||||||
{'id': 1, username_field: 'userA'},
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_cannot_order_by_non_serializer_fields(self):
|
def test_cannot_order_by_non_serializer_fields(self):
|
||||||
for serializer_cls in [
|
for serializer_cls in [
|
||||||
|
@ -997,11 +948,8 @@ class SensitiveOrderingFilterTests(TestCase):
|
||||||
username_field = 'username'
|
username_field = 'username'
|
||||||
|
|
||||||
# Note: The passwords are not in order. Default ordering is used.
|
# Note: The passwords are not in order. Default ordering is used.
|
||||||
self.assertEqual(
|
assert response.data == [
|
||||||
response.data,
|
{'id': 1, username_field: 'userA'}, # PassB
|
||||||
[
|
{'id': 2, username_field: 'userB'}, # PassC
|
||||||
{'id': 1, username_field: 'userA'}, # PassB
|
{'id': 3, username_field: 'userC'}, # PassA
|
||||||
{'id': 2, username_field: 'userB'}, # PassC
|
]
|
||||||
{'id': 3, username_field: 'userC'}, # PassA
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
|
@ -98,8 +98,8 @@ class TestRootView(TestCase):
|
||||||
request = factory.get('/')
|
request = factory.get('/')
|
||||||
with self.assertNumQueries(1):
|
with self.assertNumQueries(1):
|
||||||
response = self.view(request).render()
|
response = self.view(request).render()
|
||||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
assert response.status_code == status.HTTP_200_OK
|
||||||
self.assertEqual(response.data, self.data)
|
assert response.data == self.data
|
||||||
|
|
||||||
def test_post_root_view(self):
|
def test_post_root_view(self):
|
||||||
"""
|
"""
|
||||||
|
@ -109,10 +109,10 @@ class TestRootView(TestCase):
|
||||||
request = factory.post('/', data, format='json')
|
request = factory.post('/', data, format='json')
|
||||||
with self.assertNumQueries(1):
|
with self.assertNumQueries(1):
|
||||||
response = self.view(request).render()
|
response = self.view(request).render()
|
||||||
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
|
assert response.status_code == status.HTTP_201_CREATED
|
||||||
self.assertEqual(response.data, {'id': 4, 'text': 'foobar'})
|
assert response.data == {'id': 4, 'text': 'foobar'}
|
||||||
created = self.objects.get(id=4)
|
created = self.objects.get(id=4)
|
||||||
self.assertEqual(created.text, 'foobar')
|
assert created.text == 'foobar'
|
||||||
|
|
||||||
def test_put_root_view(self):
|
def test_put_root_view(self):
|
||||||
"""
|
"""
|
||||||
|
@ -122,8 +122,8 @@ class TestRootView(TestCase):
|
||||||
request = factory.put('/', data, format='json')
|
request = factory.put('/', data, format='json')
|
||||||
with self.assertNumQueries(0):
|
with self.assertNumQueries(0):
|
||||||
response = self.view(request).render()
|
response = self.view(request).render()
|
||||||
self.assertEqual(response.status_code, status.HTTP_405_METHOD_NOT_ALLOWED)
|
assert response.status_code == status.HTTP_405_METHOD_NOT_ALLOWED
|
||||||
self.assertEqual(response.data, {"detail": 'Method "PUT" not allowed.'})
|
assert response.data == {"detail": 'Method "PUT" not allowed.'}
|
||||||
|
|
||||||
def test_delete_root_view(self):
|
def test_delete_root_view(self):
|
||||||
"""
|
"""
|
||||||
|
@ -132,8 +132,8 @@ class TestRootView(TestCase):
|
||||||
request = factory.delete('/')
|
request = factory.delete('/')
|
||||||
with self.assertNumQueries(0):
|
with self.assertNumQueries(0):
|
||||||
response = self.view(request).render()
|
response = self.view(request).render()
|
||||||
self.assertEqual(response.status_code, status.HTTP_405_METHOD_NOT_ALLOWED)
|
assert response.status_code == status.HTTP_405_METHOD_NOT_ALLOWED
|
||||||
self.assertEqual(response.data, {"detail": 'Method "DELETE" not allowed.'})
|
assert response.data == {"detail": 'Method "DELETE" not allowed.'}
|
||||||
|
|
||||||
def test_post_cannot_set_id(self):
|
def test_post_cannot_set_id(self):
|
||||||
"""
|
"""
|
||||||
|
@ -143,10 +143,10 @@ class TestRootView(TestCase):
|
||||||
request = factory.post('/', data, format='json')
|
request = factory.post('/', data, format='json')
|
||||||
with self.assertNumQueries(1):
|
with self.assertNumQueries(1):
|
||||||
response = self.view(request).render()
|
response = self.view(request).render()
|
||||||
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
|
assert response.status_code == status.HTTP_201_CREATED
|
||||||
self.assertEqual(response.data, {'id': 4, 'text': 'foobar'})
|
assert response.data == {'id': 4, 'text': 'foobar'}
|
||||||
created = self.objects.get(id=4)
|
created = self.objects.get(id=4)
|
||||||
self.assertEqual(created.text, 'foobar')
|
assert created.text == 'foobar'
|
||||||
|
|
||||||
def test_post_error_root_view(self):
|
def test_post_error_root_view(self):
|
||||||
"""
|
"""
|
||||||
|
@ -156,7 +156,7 @@ class TestRootView(TestCase):
|
||||||
request = factory.post('/', data, HTTP_ACCEPT='text/html')
|
request = factory.post('/', data, HTTP_ACCEPT='text/html')
|
||||||
response = self.view(request).render()
|
response = self.view(request).render()
|
||||||
expected_error = '<span class="help-block">Ensure this field has no more than 100 characters.</span>'
|
expected_error = '<span class="help-block">Ensure this field has no more than 100 characters.</span>'
|
||||||
self.assertIn(expected_error, response.rendered_content.decode('utf-8'))
|
assert expected_error in response.rendered_content.decode('utf-8')
|
||||||
|
|
||||||
|
|
||||||
EXPECTED_QUERIES_FOR_PUT = 2
|
EXPECTED_QUERIES_FOR_PUT = 2
|
||||||
|
@ -185,8 +185,8 @@ class TestInstanceView(TestCase):
|
||||||
request = factory.get('/1')
|
request = factory.get('/1')
|
||||||
with self.assertNumQueries(1):
|
with self.assertNumQueries(1):
|
||||||
response = self.view(request, pk=1).render()
|
response = self.view(request, pk=1).render()
|
||||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
assert response.status_code == status.HTTP_200_OK
|
||||||
self.assertEqual(response.data, self.data[0])
|
assert response.data == self.data[0]
|
||||||
|
|
||||||
def test_post_instance_view(self):
|
def test_post_instance_view(self):
|
||||||
"""
|
"""
|
||||||
|
@ -196,8 +196,8 @@ class TestInstanceView(TestCase):
|
||||||
request = factory.post('/', data, format='json')
|
request = factory.post('/', data, format='json')
|
||||||
with self.assertNumQueries(0):
|
with self.assertNumQueries(0):
|
||||||
response = self.view(request).render()
|
response = self.view(request).render()
|
||||||
self.assertEqual(response.status_code, status.HTTP_405_METHOD_NOT_ALLOWED)
|
assert response.status_code == status.HTTP_405_METHOD_NOT_ALLOWED
|
||||||
self.assertEqual(response.data, {"detail": 'Method "POST" not allowed.'})
|
assert response.data == {"detail": 'Method "POST" not allowed.'}
|
||||||
|
|
||||||
def test_put_instance_view(self):
|
def test_put_instance_view(self):
|
||||||
"""
|
"""
|
||||||
|
@ -207,10 +207,10 @@ class TestInstanceView(TestCase):
|
||||||
request = factory.put('/1', data, format='json')
|
request = factory.put('/1', data, format='json')
|
||||||
with self.assertNumQueries(EXPECTED_QUERIES_FOR_PUT):
|
with self.assertNumQueries(EXPECTED_QUERIES_FOR_PUT):
|
||||||
response = self.view(request, pk='1').render()
|
response = self.view(request, pk='1').render()
|
||||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
assert response.status_code == status.HTTP_200_OK
|
||||||
self.assertEqual(dict(response.data), {'id': 1, 'text': 'foobar'})
|
assert dict(response.data) == {'id': 1, 'text': 'foobar'}
|
||||||
updated = self.objects.get(id=1)
|
updated = self.objects.get(id=1)
|
||||||
self.assertEqual(updated.text, 'foobar')
|
assert updated.text == 'foobar'
|
||||||
|
|
||||||
def test_patch_instance_view(self):
|
def test_patch_instance_view(self):
|
||||||
"""
|
"""
|
||||||
|
@ -221,10 +221,10 @@ class TestInstanceView(TestCase):
|
||||||
|
|
||||||
with self.assertNumQueries(EXPECTED_QUERIES_FOR_PUT):
|
with self.assertNumQueries(EXPECTED_QUERIES_FOR_PUT):
|
||||||
response = self.view(request, pk=1).render()
|
response = self.view(request, pk=1).render()
|
||||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
assert response.status_code == status.HTTP_200_OK
|
||||||
self.assertEqual(response.data, {'id': 1, 'text': 'foobar'})
|
assert response.data == {'id': 1, 'text': 'foobar'}
|
||||||
updated = self.objects.get(id=1)
|
updated = self.objects.get(id=1)
|
||||||
self.assertEqual(updated.text, 'foobar')
|
assert updated.text == 'foobar'
|
||||||
|
|
||||||
def test_delete_instance_view(self):
|
def test_delete_instance_view(self):
|
||||||
"""
|
"""
|
||||||
|
@ -233,10 +233,10 @@ class TestInstanceView(TestCase):
|
||||||
request = factory.delete('/1')
|
request = factory.delete('/1')
|
||||||
with self.assertNumQueries(2):
|
with self.assertNumQueries(2):
|
||||||
response = self.view(request, pk=1).render()
|
response = self.view(request, pk=1).render()
|
||||||
self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
|
assert response.status_code == status.HTTP_204_NO_CONTENT
|
||||||
self.assertEqual(response.content, six.b(''))
|
assert response.content == six.b('')
|
||||||
ids = [obj.id for obj in self.objects.all()]
|
ids = [obj.id for obj in self.objects.all()]
|
||||||
self.assertEqual(ids, [2, 3])
|
assert ids == [2, 3]
|
||||||
|
|
||||||
def test_get_instance_view_incorrect_arg(self):
|
def test_get_instance_view_incorrect_arg(self):
|
||||||
"""
|
"""
|
||||||
|
@ -246,7 +246,7 @@ class TestInstanceView(TestCase):
|
||||||
request = factory.get('/a')
|
request = factory.get('/a')
|
||||||
with self.assertNumQueries(0):
|
with self.assertNumQueries(0):
|
||||||
response = self.view(request, pk='a').render()
|
response = self.view(request, pk='a').render()
|
||||||
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
|
assert response.status_code == status.HTTP_404_NOT_FOUND
|
||||||
|
|
||||||
def test_put_cannot_set_id(self):
|
def test_put_cannot_set_id(self):
|
||||||
"""
|
"""
|
||||||
|
@ -256,10 +256,10 @@ class TestInstanceView(TestCase):
|
||||||
request = factory.put('/1', data, format='json')
|
request = factory.put('/1', data, format='json')
|
||||||
with self.assertNumQueries(EXPECTED_QUERIES_FOR_PUT):
|
with self.assertNumQueries(EXPECTED_QUERIES_FOR_PUT):
|
||||||
response = self.view(request, pk=1).render()
|
response = self.view(request, pk=1).render()
|
||||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
assert response.status_code == status.HTTP_200_OK
|
||||||
self.assertEqual(response.data, {'id': 1, 'text': 'foobar'})
|
assert response.data == {'id': 1, 'text': 'foobar'}
|
||||||
updated = self.objects.get(id=1)
|
updated = self.objects.get(id=1)
|
||||||
self.assertEqual(updated.text, 'foobar')
|
assert updated.text == 'foobar'
|
||||||
|
|
||||||
def test_put_to_deleted_instance(self):
|
def test_put_to_deleted_instance(self):
|
||||||
"""
|
"""
|
||||||
|
@ -271,7 +271,7 @@ class TestInstanceView(TestCase):
|
||||||
request = factory.put('/1', data, format='json')
|
request = factory.put('/1', data, format='json')
|
||||||
with self.assertNumQueries(1):
|
with self.assertNumQueries(1):
|
||||||
response = self.view(request, pk=1).render()
|
response = self.view(request, pk=1).render()
|
||||||
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
|
assert response.status_code == status.HTTP_404_NOT_FOUND
|
||||||
|
|
||||||
def test_put_to_filtered_out_instance(self):
|
def test_put_to_filtered_out_instance(self):
|
||||||
"""
|
"""
|
||||||
|
@ -282,7 +282,7 @@ class TestInstanceView(TestCase):
|
||||||
filtered_out_pk = BasicModel.objects.filter(text='filtered out')[0].pk
|
filtered_out_pk = BasicModel.objects.filter(text='filtered out')[0].pk
|
||||||
request = factory.put('/{0}'.format(filtered_out_pk), data, format='json')
|
request = factory.put('/{0}'.format(filtered_out_pk), data, format='json')
|
||||||
response = self.view(request, pk=filtered_out_pk).render()
|
response = self.view(request, pk=filtered_out_pk).render()
|
||||||
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
|
assert response.status_code == status.HTTP_404_NOT_FOUND
|
||||||
|
|
||||||
def test_patch_cannot_create_an_object(self):
|
def test_patch_cannot_create_an_object(self):
|
||||||
"""
|
"""
|
||||||
|
@ -292,8 +292,8 @@ class TestInstanceView(TestCase):
|
||||||
request = factory.patch('/999', data, format='json')
|
request = factory.patch('/999', data, format='json')
|
||||||
with self.assertNumQueries(1):
|
with self.assertNumQueries(1):
|
||||||
response = self.view(request, pk=999).render()
|
response = self.view(request, pk=999).render()
|
||||||
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
|
assert response.status_code == status.HTTP_404_NOT_FOUND
|
||||||
self.assertFalse(self.objects.filter(id=999).exists())
|
assert not self.objects.filter(id=999).exists()
|
||||||
|
|
||||||
def test_put_error_instance_view(self):
|
def test_put_error_instance_view(self):
|
||||||
"""
|
"""
|
||||||
|
@ -303,7 +303,7 @@ class TestInstanceView(TestCase):
|
||||||
request = factory.put('/', data, HTTP_ACCEPT='text/html')
|
request = factory.put('/', data, HTTP_ACCEPT='text/html')
|
||||||
response = self.view(request, pk=1).render()
|
response = self.view(request, pk=1).render()
|
||||||
expected_error = '<span class="help-block">Ensure this field has no more than 100 characters.</span>'
|
expected_error = '<span class="help-block">Ensure this field has no more than 100 characters.</span>'
|
||||||
self.assertIn(expected_error, response.rendered_content.decode('utf-8'))
|
assert expected_error in response.rendered_content.decode('utf-8')
|
||||||
|
|
||||||
|
|
||||||
class TestFKInstanceView(TestCase):
|
class TestFKInstanceView(TestCase):
|
||||||
|
@ -363,8 +363,8 @@ class TestOverriddenGetObject(TestCase):
|
||||||
request = factory.get('/1')
|
request = factory.get('/1')
|
||||||
with self.assertNumQueries(1):
|
with self.assertNumQueries(1):
|
||||||
response = self.view(request, pk=1).render()
|
response = self.view(request, pk=1).render()
|
||||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
assert response.status_code == status.HTTP_200_OK
|
||||||
self.assertEqual(response.data, self.data[0])
|
assert response.data == self.data[0]
|
||||||
|
|
||||||
|
|
||||||
# Regression test for #285
|
# Regression test for #285
|
||||||
|
@ -394,9 +394,9 @@ class TestCreateModelWithAutoNowAddField(TestCase):
|
||||||
data = {'email': 'foobar@example.com', 'content': 'foobar'}
|
data = {'email': 'foobar@example.com', 'content': 'foobar'}
|
||||||
request = factory.post('/', data, format='json')
|
request = factory.post('/', data, format='json')
|
||||||
response = self.view(request).render()
|
response = self.view(request).render()
|
||||||
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
|
assert response.status_code == status.HTTP_201_CREATED
|
||||||
created = self.objects.get(id=1)
|
created = self.objects.get(id=1)
|
||||||
self.assertEqual(created.content, 'foobar')
|
assert created.content == 'foobar'
|
||||||
|
|
||||||
|
|
||||||
# Test for particularly ugly regression with m2m in browsable API
|
# Test for particularly ugly regression with m2m in browsable API
|
||||||
|
@ -432,7 +432,7 @@ class TestM2MBrowsableAPI(TestCase):
|
||||||
request = factory.get('/', HTTP_ACCEPT='text/html')
|
request = factory.get('/', HTTP_ACCEPT='text/html')
|
||||||
view = ExampleView().as_view()
|
view = ExampleView().as_view()
|
||||||
response = view(request).render()
|
response = view(request).render()
|
||||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
assert response.status_code == status.HTTP_200_OK
|
||||||
|
|
||||||
|
|
||||||
class InclusiveFilterBackend(object):
|
class InclusiveFilterBackend(object):
|
||||||
|
@ -489,9 +489,9 @@ class TestFilterBackendAppliedToViews(TestCase):
|
||||||
root_view = RootView.as_view(filter_backends=(InclusiveFilterBackend,))
|
root_view = RootView.as_view(filter_backends=(InclusiveFilterBackend,))
|
||||||
request = factory.get('/')
|
request = factory.get('/')
|
||||||
response = root_view(request).render()
|
response = root_view(request).render()
|
||||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
assert response.status_code == status.HTTP_200_OK
|
||||||
self.assertEqual(len(response.data), 1)
|
assert len(response.data) == 1
|
||||||
self.assertEqual(response.data, [{'id': 1, 'text': 'foo'}])
|
assert response.data == [{'id': 1, 'text': 'foo'}]
|
||||||
|
|
||||||
def test_get_root_view_filters_out_all_models_with_exclusive_filter_backend(self):
|
def test_get_root_view_filters_out_all_models_with_exclusive_filter_backend(self):
|
||||||
"""
|
"""
|
||||||
|
@ -500,8 +500,8 @@ class TestFilterBackendAppliedToViews(TestCase):
|
||||||
root_view = RootView.as_view(filter_backends=(ExclusiveFilterBackend,))
|
root_view = RootView.as_view(filter_backends=(ExclusiveFilterBackend,))
|
||||||
request = factory.get('/')
|
request = factory.get('/')
|
||||||
response = root_view(request).render()
|
response = root_view(request).render()
|
||||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
assert response.status_code == status.HTTP_200_OK
|
||||||
self.assertEqual(response.data, [])
|
assert response.data == []
|
||||||
|
|
||||||
def test_get_instance_view_filters_out_name_with_filter_backend(self):
|
def test_get_instance_view_filters_out_name_with_filter_backend(self):
|
||||||
"""
|
"""
|
||||||
|
@ -510,8 +510,8 @@ class TestFilterBackendAppliedToViews(TestCase):
|
||||||
instance_view = InstanceView.as_view(filter_backends=(ExclusiveFilterBackend,))
|
instance_view = InstanceView.as_view(filter_backends=(ExclusiveFilterBackend,))
|
||||||
request = factory.get('/1')
|
request = factory.get('/1')
|
||||||
response = instance_view(request, pk=1).render()
|
response = instance_view(request, pk=1).render()
|
||||||
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
|
assert response.status_code == status.HTTP_404_NOT_FOUND
|
||||||
self.assertEqual(response.data, {'detail': 'Not found.'})
|
assert response.data == {'detail': 'Not found.'}
|
||||||
|
|
||||||
def test_get_instance_view_will_return_single_object_when_filter_does_not_exclude_it(self):
|
def test_get_instance_view_will_return_single_object_when_filter_does_not_exclude_it(self):
|
||||||
"""
|
"""
|
||||||
|
@ -520,8 +520,8 @@ class TestFilterBackendAppliedToViews(TestCase):
|
||||||
instance_view = InstanceView.as_view(filter_backends=(InclusiveFilterBackend,))
|
instance_view = InstanceView.as_view(filter_backends=(InclusiveFilterBackend,))
|
||||||
request = factory.get('/1')
|
request = factory.get('/1')
|
||||||
response = instance_view(request, pk=1).render()
|
response = instance_view(request, pk=1).render()
|
||||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
assert response.status_code == status.HTTP_200_OK
|
||||||
self.assertEqual(response.data, {'id': 1, 'text': 'foo'})
|
assert response.data == {'id': 1, 'text': 'foo'}
|
||||||
|
|
||||||
def test_dynamic_serializer_form_in_browsable_api(self):
|
def test_dynamic_serializer_form_in_browsable_api(self):
|
||||||
"""
|
"""
|
||||||
|
@ -530,8 +530,9 @@ class TestFilterBackendAppliedToViews(TestCase):
|
||||||
view = DynamicSerializerView.as_view()
|
view = DynamicSerializerView.as_view()
|
||||||
request = factory.get('/')
|
request = factory.get('/')
|
||||||
response = view(request).render()
|
response = view(request).render()
|
||||||
self.assertContains(response, 'field_b')
|
content = response.content.decode('utf8')
|
||||||
self.assertNotContains(response, 'field_a')
|
assert 'field_b' in content
|
||||||
|
assert 'field_a' not in content
|
||||||
|
|
||||||
|
|
||||||
class TestGuardedQueryset(TestCase):
|
class TestGuardedQueryset(TestCase):
|
||||||
|
|
|
@ -94,7 +94,7 @@ class Issue3674ParentModel(models.Model):
|
||||||
|
|
||||||
|
|
||||||
class Issue3674ChildModel(models.Model):
|
class Issue3674ChildModel(models.Model):
|
||||||
parent = models.ForeignKey(Issue3674ParentModel, related_name='children')
|
parent = models.ForeignKey(Issue3674ParentModel, related_name='children', on_delete=models.CASCADE)
|
||||||
value = models.CharField(primary_key=True, max_length=64)
|
value = models.CharField(primary_key=True, max_length=64)
|
||||||
|
|
||||||
|
|
||||||
|
@ -1013,7 +1013,7 @@ class Issue3674Test(TestCase):
|
||||||
title = models.CharField(max_length=64)
|
title = models.CharField(max_length=64)
|
||||||
|
|
||||||
class TestChildModel(models.Model):
|
class TestChildModel(models.Model):
|
||||||
parent = models.ForeignKey(TestParentModel, related_name='children')
|
parent = models.ForeignKey(TestParentModel, related_name='children', on_delete=models.CASCADE)
|
||||||
value = models.CharField(primary_key=True, max_length=64)
|
value = models.CharField(primary_key=True, max_length=64)
|
||||||
|
|
||||||
class TestChildModelSerializer(serializers.ModelSerializer):
|
class TestChildModelSerializer(serializers.ModelSerializer):
|
||||||
|
|
|
@ -2,6 +2,7 @@ from django.contrib.auth.models import Group, User
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
|
|
||||||
from rest_framework import generics, serializers
|
from rest_framework import generics, serializers
|
||||||
|
from rest_framework.compat import set_many
|
||||||
from rest_framework.test import APIRequestFactory
|
from rest_framework.test import APIRequestFactory
|
||||||
|
|
||||||
factory = APIRequestFactory()
|
factory = APIRequestFactory()
|
||||||
|
@ -22,7 +23,7 @@ class TestPrefetchRelatedUpdates(TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.user = User.objects.create(username='tom', email='tom@example.com')
|
self.user = User.objects.create(username='tom', email='tom@example.com')
|
||||||
self.groups = [Group.objects.create(name='a'), Group.objects.create(name='b')]
|
self.groups = [Group.objects.create(name='a'), Group.objects.create(name='b')]
|
||||||
self.user.groups = self.groups
|
set_many(self.user, 'groups', self.groups)
|
||||||
self.user.save()
|
self.user.save()
|
||||||
|
|
||||||
def test_prefetch_related_updates(self):
|
def test_prefetch_related_updates(self):
|
||||||
|
|
|
@ -75,7 +75,7 @@ class TestGenericRelations(TestCase):
|
||||||
'tags': ['django', 'python'],
|
'tags': ['django', 'python'],
|
||||||
'url': 'https://www.djangoproject.com/'
|
'url': 'https://www.djangoproject.com/'
|
||||||
}
|
}
|
||||||
self.assertEqual(serializer.data, expected)
|
assert serializer.data == expected
|
||||||
|
|
||||||
def test_generic_fk(self):
|
def test_generic_fk(self):
|
||||||
"""
|
"""
|
||||||
|
@ -105,4 +105,4 @@ class TestGenericRelations(TestCase):
|
||||||
'tagged_item': 'Note: Remember the milk'
|
'tagged_item': 'Note: Remember the milk'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
self.assertEqual(serializer.data, expected)
|
assert serializer.data == expected
|
||||||
|
|
|
@ -84,7 +84,7 @@ class PKManyToManyTests(TestCase):
|
||||||
{'id': 3, 'name': 'source-3', 'targets': [1, 2, 3]}
|
{'id': 3, 'name': 'source-3', 'targets': [1, 2, 3]}
|
||||||
]
|
]
|
||||||
with self.assertNumQueries(4):
|
with self.assertNumQueries(4):
|
||||||
self.assertEqual(serializer.data, expected)
|
assert serializer.data == expected
|
||||||
|
|
||||||
def test_many_to_many_retrieve_prefetch_related(self):
|
def test_many_to_many_retrieve_prefetch_related(self):
|
||||||
queryset = ManyToManySource.objects.all().prefetch_related('targets')
|
queryset = ManyToManySource.objects.all().prefetch_related('targets')
|
||||||
|
@ -101,15 +101,15 @@ class PKManyToManyTests(TestCase):
|
||||||
{'id': 3, 'name': 'target-3', 'sources': [3]}
|
{'id': 3, 'name': 'target-3', 'sources': [3]}
|
||||||
]
|
]
|
||||||
with self.assertNumQueries(4):
|
with self.assertNumQueries(4):
|
||||||
self.assertEqual(serializer.data, expected)
|
assert serializer.data == expected
|
||||||
|
|
||||||
def test_many_to_many_update(self):
|
def test_many_to_many_update(self):
|
||||||
data = {'id': 1, 'name': 'source-1', 'targets': [1, 2, 3]}
|
data = {'id': 1, 'name': 'source-1', 'targets': [1, 2, 3]}
|
||||||
instance = ManyToManySource.objects.get(pk=1)
|
instance = ManyToManySource.objects.get(pk=1)
|
||||||
serializer = ManyToManySourceSerializer(instance, data=data)
|
serializer = ManyToManySourceSerializer(instance, data=data)
|
||||||
self.assertTrue(serializer.is_valid())
|
assert serializer.is_valid()
|
||||||
serializer.save()
|
serializer.save()
|
||||||
self.assertEqual(serializer.data, data)
|
assert serializer.data == data
|
||||||
|
|
||||||
# Ensure source 1 is updated, and everything else is as expected
|
# Ensure source 1 is updated, and everything else is as expected
|
||||||
queryset = ManyToManySource.objects.all()
|
queryset = ManyToManySource.objects.all()
|
||||||
|
@ -119,15 +119,15 @@ class PKManyToManyTests(TestCase):
|
||||||
{'id': 2, 'name': 'source-2', 'targets': [1, 2]},
|
{'id': 2, 'name': 'source-2', 'targets': [1, 2]},
|
||||||
{'id': 3, 'name': 'source-3', 'targets': [1, 2, 3]}
|
{'id': 3, 'name': 'source-3', 'targets': [1, 2, 3]}
|
||||||
]
|
]
|
||||||
self.assertEqual(serializer.data, expected)
|
assert serializer.data == expected
|
||||||
|
|
||||||
def test_reverse_many_to_many_update(self):
|
def test_reverse_many_to_many_update(self):
|
||||||
data = {'id': 1, 'name': 'target-1', 'sources': [1]}
|
data = {'id': 1, 'name': 'target-1', 'sources': [1]}
|
||||||
instance = ManyToManyTarget.objects.get(pk=1)
|
instance = ManyToManyTarget.objects.get(pk=1)
|
||||||
serializer = ManyToManyTargetSerializer(instance, data=data)
|
serializer = ManyToManyTargetSerializer(instance, data=data)
|
||||||
self.assertTrue(serializer.is_valid())
|
assert serializer.is_valid()
|
||||||
serializer.save()
|
serializer.save()
|
||||||
self.assertEqual(serializer.data, data)
|
assert serializer.data == data
|
||||||
|
|
||||||
# Ensure target 1 is updated, and everything else is as expected
|
# Ensure target 1 is updated, and everything else is as expected
|
||||||
queryset = ManyToManyTarget.objects.all()
|
queryset = ManyToManyTarget.objects.all()
|
||||||
|
@ -137,15 +137,15 @@ class PKManyToManyTests(TestCase):
|
||||||
{'id': 2, 'name': 'target-2', 'sources': [2, 3]},
|
{'id': 2, 'name': 'target-2', 'sources': [2, 3]},
|
||||||
{'id': 3, 'name': 'target-3', 'sources': [3]}
|
{'id': 3, 'name': 'target-3', 'sources': [3]}
|
||||||
]
|
]
|
||||||
self.assertEqual(serializer.data, expected)
|
assert serializer.data == expected
|
||||||
|
|
||||||
def test_many_to_many_create(self):
|
def test_many_to_many_create(self):
|
||||||
data = {'id': 4, 'name': 'source-4', 'targets': [1, 3]}
|
data = {'id': 4, 'name': 'source-4', 'targets': [1, 3]}
|
||||||
serializer = ManyToManySourceSerializer(data=data)
|
serializer = ManyToManySourceSerializer(data=data)
|
||||||
self.assertTrue(serializer.is_valid())
|
assert serializer.is_valid()
|
||||||
obj = serializer.save()
|
obj = serializer.save()
|
||||||
self.assertEqual(serializer.data, data)
|
assert serializer.data == data
|
||||||
self.assertEqual(obj.name, 'source-4')
|
assert obj.name == 'source-4'
|
||||||
|
|
||||||
# Ensure source 4 is added, and everything else is as expected
|
# Ensure source 4 is added, and everything else is as expected
|
||||||
queryset = ManyToManySource.objects.all()
|
queryset = ManyToManySource.objects.all()
|
||||||
|
@ -156,7 +156,7 @@ class PKManyToManyTests(TestCase):
|
||||||
{'id': 3, 'name': 'source-3', 'targets': [1, 2, 3]},
|
{'id': 3, 'name': 'source-3', 'targets': [1, 2, 3]},
|
||||||
{'id': 4, 'name': 'source-4', 'targets': [1, 3]},
|
{'id': 4, 'name': 'source-4', 'targets': [1, 3]},
|
||||||
]
|
]
|
||||||
self.assertEqual(serializer.data, expected)
|
assert serializer.data == expected
|
||||||
|
|
||||||
def test_many_to_many_unsaved(self):
|
def test_many_to_many_unsaved(self):
|
||||||
source = ManyToManySource(name='source-unsaved')
|
source = ManyToManySource(name='source-unsaved')
|
||||||
|
@ -166,15 +166,15 @@ class PKManyToManyTests(TestCase):
|
||||||
expected = {'id': None, 'name': 'source-unsaved', 'targets': []}
|
expected = {'id': None, 'name': 'source-unsaved', 'targets': []}
|
||||||
# no query if source hasn't been created yet
|
# no query if source hasn't been created yet
|
||||||
with self.assertNumQueries(0):
|
with self.assertNumQueries(0):
|
||||||
self.assertEqual(serializer.data, expected)
|
assert serializer.data == expected
|
||||||
|
|
||||||
def test_reverse_many_to_many_create(self):
|
def test_reverse_many_to_many_create(self):
|
||||||
data = {'id': 4, 'name': 'target-4', 'sources': [1, 3]}
|
data = {'id': 4, 'name': 'target-4', 'sources': [1, 3]}
|
||||||
serializer = ManyToManyTargetSerializer(data=data)
|
serializer = ManyToManyTargetSerializer(data=data)
|
||||||
self.assertTrue(serializer.is_valid())
|
assert serializer.is_valid()
|
||||||
obj = serializer.save()
|
obj = serializer.save()
|
||||||
self.assertEqual(serializer.data, data)
|
assert serializer.data == data
|
||||||
self.assertEqual(obj.name, 'target-4')
|
assert obj.name == 'target-4'
|
||||||
|
|
||||||
# Ensure target 4 is added, and everything else is as expected
|
# Ensure target 4 is added, and everything else is as expected
|
||||||
queryset = ManyToManyTarget.objects.all()
|
queryset = ManyToManyTarget.objects.all()
|
||||||
|
@ -185,7 +185,7 @@ class PKManyToManyTests(TestCase):
|
||||||
{'id': 3, 'name': 'target-3', 'sources': [3]},
|
{'id': 3, 'name': 'target-3', 'sources': [3]},
|
||||||
{'id': 4, 'name': 'target-4', 'sources': [1, 3]}
|
{'id': 4, 'name': 'target-4', 'sources': [1, 3]}
|
||||||
]
|
]
|
||||||
self.assertEqual(serializer.data, expected)
|
assert serializer.data == expected
|
||||||
|
|
||||||
|
|
||||||
class PKForeignKeyTests(TestCase):
|
class PKForeignKeyTests(TestCase):
|
||||||
|
@ -207,7 +207,7 @@ class PKForeignKeyTests(TestCase):
|
||||||
{'id': 3, 'name': 'source-3', 'target': 1}
|
{'id': 3, 'name': 'source-3', 'target': 1}
|
||||||
]
|
]
|
||||||
with self.assertNumQueries(1):
|
with self.assertNumQueries(1):
|
||||||
self.assertEqual(serializer.data, expected)
|
assert serializer.data == expected
|
||||||
|
|
||||||
def test_reverse_foreign_key_retrieve(self):
|
def test_reverse_foreign_key_retrieve(self):
|
||||||
queryset = ForeignKeyTarget.objects.all()
|
queryset = ForeignKeyTarget.objects.all()
|
||||||
|
@ -217,7 +217,7 @@ class PKForeignKeyTests(TestCase):
|
||||||
{'id': 2, 'name': 'target-2', 'sources': []},
|
{'id': 2, 'name': 'target-2', 'sources': []},
|
||||||
]
|
]
|
||||||
with self.assertNumQueries(3):
|
with self.assertNumQueries(3):
|
||||||
self.assertEqual(serializer.data, expected)
|
assert serializer.data == expected
|
||||||
|
|
||||||
def test_reverse_foreign_key_retrieve_prefetch_related(self):
|
def test_reverse_foreign_key_retrieve_prefetch_related(self):
|
||||||
queryset = ForeignKeyTarget.objects.all().prefetch_related('sources')
|
queryset = ForeignKeyTarget.objects.all().prefetch_related('sources')
|
||||||
|
@ -229,9 +229,9 @@ class PKForeignKeyTests(TestCase):
|
||||||
data = {'id': 1, 'name': 'source-1', 'target': 2}
|
data = {'id': 1, 'name': 'source-1', 'target': 2}
|
||||||
instance = ForeignKeySource.objects.get(pk=1)
|
instance = ForeignKeySource.objects.get(pk=1)
|
||||||
serializer = ForeignKeySourceSerializer(instance, data=data)
|
serializer = ForeignKeySourceSerializer(instance, data=data)
|
||||||
self.assertTrue(serializer.is_valid())
|
assert serializer.is_valid()
|
||||||
serializer.save()
|
serializer.save()
|
||||||
self.assertEqual(serializer.data, data)
|
assert serializer.data == data
|
||||||
|
|
||||||
# Ensure source 1 is updated, and everything else is as expected
|
# Ensure source 1 is updated, and everything else is as expected
|
||||||
queryset = ForeignKeySource.objects.all()
|
queryset = ForeignKeySource.objects.all()
|
||||||
|
@ -241,20 +241,20 @@ class PKForeignKeyTests(TestCase):
|
||||||
{'id': 2, 'name': 'source-2', 'target': 1},
|
{'id': 2, 'name': 'source-2', 'target': 1},
|
||||||
{'id': 3, 'name': 'source-3', 'target': 1}
|
{'id': 3, 'name': 'source-3', 'target': 1}
|
||||||
]
|
]
|
||||||
self.assertEqual(serializer.data, expected)
|
assert serializer.data == expected
|
||||||
|
|
||||||
def test_foreign_key_update_incorrect_type(self):
|
def test_foreign_key_update_incorrect_type(self):
|
||||||
data = {'id': 1, 'name': 'source-1', 'target': 'foo'}
|
data = {'id': 1, 'name': 'source-1', 'target': 'foo'}
|
||||||
instance = ForeignKeySource.objects.get(pk=1)
|
instance = ForeignKeySource.objects.get(pk=1)
|
||||||
serializer = ForeignKeySourceSerializer(instance, data=data)
|
serializer = ForeignKeySourceSerializer(instance, data=data)
|
||||||
self.assertFalse(serializer.is_valid())
|
assert not serializer.is_valid()
|
||||||
self.assertEqual(serializer.errors, {'target': ['Incorrect type. Expected pk value, received %s.' % six.text_type.__name__]})
|
assert serializer.errors == {'target': ['Incorrect type. Expected pk value, received %s.' % six.text_type.__name__]}
|
||||||
|
|
||||||
def test_reverse_foreign_key_update(self):
|
def test_reverse_foreign_key_update(self):
|
||||||
data = {'id': 2, 'name': 'target-2', 'sources': [1, 3]}
|
data = {'id': 2, 'name': 'target-2', 'sources': [1, 3]}
|
||||||
instance = ForeignKeyTarget.objects.get(pk=2)
|
instance = ForeignKeyTarget.objects.get(pk=2)
|
||||||
serializer = ForeignKeyTargetSerializer(instance, data=data)
|
serializer = ForeignKeyTargetSerializer(instance, data=data)
|
||||||
self.assertTrue(serializer.is_valid())
|
assert serializer.is_valid()
|
||||||
# We shouldn't have saved anything to the db yet since save
|
# We shouldn't have saved anything to the db yet since save
|
||||||
# hasn't been called.
|
# hasn't been called.
|
||||||
queryset = ForeignKeyTarget.objects.all()
|
queryset = ForeignKeyTarget.objects.all()
|
||||||
|
@ -263,10 +263,10 @@ class PKForeignKeyTests(TestCase):
|
||||||
{'id': 1, 'name': 'target-1', 'sources': [1, 2, 3]},
|
{'id': 1, 'name': 'target-1', 'sources': [1, 2, 3]},
|
||||||
{'id': 2, 'name': 'target-2', 'sources': []},
|
{'id': 2, 'name': 'target-2', 'sources': []},
|
||||||
]
|
]
|
||||||
self.assertEqual(new_serializer.data, expected)
|
assert new_serializer.data == expected
|
||||||
|
|
||||||
serializer.save()
|
serializer.save()
|
||||||
self.assertEqual(serializer.data, data)
|
assert serializer.data == data
|
||||||
|
|
||||||
# Ensure target 2 is update, and everything else is as expected
|
# Ensure target 2 is update, and everything else is as expected
|
||||||
queryset = ForeignKeyTarget.objects.all()
|
queryset = ForeignKeyTarget.objects.all()
|
||||||
|
@ -275,15 +275,15 @@ class PKForeignKeyTests(TestCase):
|
||||||
{'id': 1, 'name': 'target-1', 'sources': [2]},
|
{'id': 1, 'name': 'target-1', 'sources': [2]},
|
||||||
{'id': 2, 'name': 'target-2', 'sources': [1, 3]},
|
{'id': 2, 'name': 'target-2', 'sources': [1, 3]},
|
||||||
]
|
]
|
||||||
self.assertEqual(serializer.data, expected)
|
assert serializer.data == expected
|
||||||
|
|
||||||
def test_foreign_key_create(self):
|
def test_foreign_key_create(self):
|
||||||
data = {'id': 4, 'name': 'source-4', 'target': 2}
|
data = {'id': 4, 'name': 'source-4', 'target': 2}
|
||||||
serializer = ForeignKeySourceSerializer(data=data)
|
serializer = ForeignKeySourceSerializer(data=data)
|
||||||
self.assertTrue(serializer.is_valid())
|
assert serializer.is_valid()
|
||||||
obj = serializer.save()
|
obj = serializer.save()
|
||||||
self.assertEqual(serializer.data, data)
|
assert serializer.data == data
|
||||||
self.assertEqual(obj.name, 'source-4')
|
assert obj.name == 'source-4'
|
||||||
|
|
||||||
# Ensure source 4 is added, and everything else is as expected
|
# Ensure source 4 is added, and everything else is as expected
|
||||||
queryset = ForeignKeySource.objects.all()
|
queryset = ForeignKeySource.objects.all()
|
||||||
|
@ -294,15 +294,15 @@ class PKForeignKeyTests(TestCase):
|
||||||
{'id': 3, 'name': 'source-3', 'target': 1},
|
{'id': 3, 'name': 'source-3', 'target': 1},
|
||||||
{'id': 4, 'name': 'source-4', 'target': 2},
|
{'id': 4, 'name': 'source-4', 'target': 2},
|
||||||
]
|
]
|
||||||
self.assertEqual(serializer.data, expected)
|
assert serializer.data == expected
|
||||||
|
|
||||||
def test_reverse_foreign_key_create(self):
|
def test_reverse_foreign_key_create(self):
|
||||||
data = {'id': 3, 'name': 'target-3', 'sources': [1, 3]}
|
data = {'id': 3, 'name': 'target-3', 'sources': [1, 3]}
|
||||||
serializer = ForeignKeyTargetSerializer(data=data)
|
serializer = ForeignKeyTargetSerializer(data=data)
|
||||||
self.assertTrue(serializer.is_valid())
|
assert serializer.is_valid()
|
||||||
obj = serializer.save()
|
obj = serializer.save()
|
||||||
self.assertEqual(serializer.data, data)
|
assert serializer.data == data
|
||||||
self.assertEqual(obj.name, 'target-3')
|
assert obj.name == 'target-3'
|
||||||
|
|
||||||
# Ensure target 3 is added, and everything else is as expected
|
# Ensure target 3 is added, and everything else is as expected
|
||||||
queryset = ForeignKeyTarget.objects.all()
|
queryset = ForeignKeyTarget.objects.all()
|
||||||
|
@ -312,14 +312,14 @@ class PKForeignKeyTests(TestCase):
|
||||||
{'id': 2, 'name': 'target-2', 'sources': []},
|
{'id': 2, 'name': 'target-2', 'sources': []},
|
||||||
{'id': 3, 'name': 'target-3', 'sources': [1, 3]},
|
{'id': 3, 'name': 'target-3', 'sources': [1, 3]},
|
||||||
]
|
]
|
||||||
self.assertEqual(serializer.data, expected)
|
assert serializer.data == expected
|
||||||
|
|
||||||
def test_foreign_key_update_with_invalid_null(self):
|
def test_foreign_key_update_with_invalid_null(self):
|
||||||
data = {'id': 1, 'name': 'source-1', 'target': None}
|
data = {'id': 1, 'name': 'source-1', 'target': None}
|
||||||
instance = ForeignKeySource.objects.get(pk=1)
|
instance = ForeignKeySource.objects.get(pk=1)
|
||||||
serializer = ForeignKeySourceSerializer(instance, data=data)
|
serializer = ForeignKeySourceSerializer(instance, data=data)
|
||||||
self.assertFalse(serializer.is_valid())
|
assert not serializer.is_valid()
|
||||||
self.assertEqual(serializer.errors, {'target': ['This field may not be null.']})
|
assert serializer.errors == {'target': ['This field may not be null.']}
|
||||||
|
|
||||||
def test_foreign_key_with_unsaved(self):
|
def test_foreign_key_with_unsaved(self):
|
||||||
source = ForeignKeySource(name='source-unsaved')
|
source = ForeignKeySource(name='source-unsaved')
|
||||||
|
@ -329,7 +329,7 @@ class PKForeignKeyTests(TestCase):
|
||||||
|
|
||||||
# no query if source hasn't been created yet
|
# no query if source hasn't been created yet
|
||||||
with self.assertNumQueries(0):
|
with self.assertNumQueries(0):
|
||||||
self.assertEqual(serializer.data, expected)
|
assert serializer.data == expected
|
||||||
|
|
||||||
def test_foreign_key_with_empty(self):
|
def test_foreign_key_with_empty(self):
|
||||||
"""
|
"""
|
||||||
|
@ -338,7 +338,7 @@ class PKForeignKeyTests(TestCase):
|
||||||
https://github.com/tomchristie/django-rest-framework/issues/1072
|
https://github.com/tomchristie/django-rest-framework/issues/1072
|
||||||
"""
|
"""
|
||||||
serializer = NullableForeignKeySourceSerializer()
|
serializer = NullableForeignKeySourceSerializer()
|
||||||
self.assertEqual(serializer.data['target'], None)
|
assert serializer.data['target'] is None
|
||||||
|
|
||||||
def test_foreign_key_not_required(self):
|
def test_foreign_key_not_required(self):
|
||||||
"""
|
"""
|
||||||
|
@ -350,7 +350,7 @@ class PKForeignKeyTests(TestCase):
|
||||||
extra_kwargs = {'target': {'required': False}}
|
extra_kwargs = {'target': {'required': False}}
|
||||||
serializer = ModelSerializer(data={'name': 'test'})
|
serializer = ModelSerializer(data={'name': 'test'})
|
||||||
serializer.is_valid(raise_exception=True)
|
serializer.is_valid(raise_exception=True)
|
||||||
self.assertNotIn('target', serializer.validated_data)
|
assert 'target' not in serializer.validated_data
|
||||||
|
|
||||||
|
|
||||||
class PKNullableForeignKeyTests(TestCase):
|
class PKNullableForeignKeyTests(TestCase):
|
||||||
|
@ -371,15 +371,15 @@ class PKNullableForeignKeyTests(TestCase):
|
||||||
{'id': 2, 'name': 'source-2', 'target': 1},
|
{'id': 2, 'name': 'source-2', 'target': 1},
|
||||||
{'id': 3, 'name': 'source-3', 'target': None},
|
{'id': 3, 'name': 'source-3', 'target': None},
|
||||||
]
|
]
|
||||||
self.assertEqual(serializer.data, expected)
|
assert serializer.data == expected
|
||||||
|
|
||||||
def test_foreign_key_create_with_valid_null(self):
|
def test_foreign_key_create_with_valid_null(self):
|
||||||
data = {'id': 4, 'name': 'source-4', 'target': None}
|
data = {'id': 4, 'name': 'source-4', 'target': None}
|
||||||
serializer = NullableForeignKeySourceSerializer(data=data)
|
serializer = NullableForeignKeySourceSerializer(data=data)
|
||||||
self.assertTrue(serializer.is_valid())
|
assert serializer.is_valid()
|
||||||
obj = serializer.save()
|
obj = serializer.save()
|
||||||
self.assertEqual(serializer.data, data)
|
assert serializer.data == data
|
||||||
self.assertEqual(obj.name, 'source-4')
|
assert obj.name == 'source-4'
|
||||||
|
|
||||||
# Ensure source 4 is created, and everything else is as expected
|
# Ensure source 4 is created, and everything else is as expected
|
||||||
queryset = NullableForeignKeySource.objects.all()
|
queryset = NullableForeignKeySource.objects.all()
|
||||||
|
@ -390,7 +390,7 @@ class PKNullableForeignKeyTests(TestCase):
|
||||||
{'id': 3, 'name': 'source-3', 'target': None},
|
{'id': 3, 'name': 'source-3', 'target': None},
|
||||||
{'id': 4, 'name': 'source-4', 'target': None}
|
{'id': 4, 'name': 'source-4', 'target': None}
|
||||||
]
|
]
|
||||||
self.assertEqual(serializer.data, expected)
|
assert serializer.data == expected
|
||||||
|
|
||||||
def test_foreign_key_create_with_valid_emptystring(self):
|
def test_foreign_key_create_with_valid_emptystring(self):
|
||||||
"""
|
"""
|
||||||
|
@ -400,10 +400,10 @@ class PKNullableForeignKeyTests(TestCase):
|
||||||
data = {'id': 4, 'name': 'source-4', 'target': ''}
|
data = {'id': 4, 'name': 'source-4', 'target': ''}
|
||||||
expected_data = {'id': 4, 'name': 'source-4', 'target': None}
|
expected_data = {'id': 4, 'name': 'source-4', 'target': None}
|
||||||
serializer = NullableForeignKeySourceSerializer(data=data)
|
serializer = NullableForeignKeySourceSerializer(data=data)
|
||||||
self.assertTrue(serializer.is_valid())
|
assert serializer.is_valid()
|
||||||
obj = serializer.save()
|
obj = serializer.save()
|
||||||
self.assertEqual(serializer.data, expected_data)
|
assert serializer.data == expected_data
|
||||||
self.assertEqual(obj.name, 'source-4')
|
assert obj.name == 'source-4'
|
||||||
|
|
||||||
# Ensure source 4 is created, and everything else is as expected
|
# Ensure source 4 is created, and everything else is as expected
|
||||||
queryset = NullableForeignKeySource.objects.all()
|
queryset = NullableForeignKeySource.objects.all()
|
||||||
|
@ -414,15 +414,15 @@ class PKNullableForeignKeyTests(TestCase):
|
||||||
{'id': 3, 'name': 'source-3', 'target': None},
|
{'id': 3, 'name': 'source-3', 'target': None},
|
||||||
{'id': 4, 'name': 'source-4', 'target': None}
|
{'id': 4, 'name': 'source-4', 'target': None}
|
||||||
]
|
]
|
||||||
self.assertEqual(serializer.data, expected)
|
assert serializer.data == expected
|
||||||
|
|
||||||
def test_foreign_key_update_with_valid_null(self):
|
def test_foreign_key_update_with_valid_null(self):
|
||||||
data = {'id': 1, 'name': 'source-1', 'target': None}
|
data = {'id': 1, 'name': 'source-1', 'target': None}
|
||||||
instance = NullableForeignKeySource.objects.get(pk=1)
|
instance = NullableForeignKeySource.objects.get(pk=1)
|
||||||
serializer = NullableForeignKeySourceSerializer(instance, data=data)
|
serializer = NullableForeignKeySourceSerializer(instance, data=data)
|
||||||
self.assertTrue(serializer.is_valid())
|
assert serializer.is_valid()
|
||||||
serializer.save()
|
serializer.save()
|
||||||
self.assertEqual(serializer.data, data)
|
assert serializer.data == data
|
||||||
|
|
||||||
# Ensure source 1 is updated, and everything else is as expected
|
# Ensure source 1 is updated, and everything else is as expected
|
||||||
queryset = NullableForeignKeySource.objects.all()
|
queryset = NullableForeignKeySource.objects.all()
|
||||||
|
@ -432,7 +432,7 @@ class PKNullableForeignKeyTests(TestCase):
|
||||||
{'id': 2, 'name': 'source-2', 'target': 1},
|
{'id': 2, 'name': 'source-2', 'target': 1},
|
||||||
{'id': 3, 'name': 'source-3', 'target': None}
|
{'id': 3, 'name': 'source-3', 'target': None}
|
||||||
]
|
]
|
||||||
self.assertEqual(serializer.data, expected)
|
assert serializer.data == expected
|
||||||
|
|
||||||
def test_foreign_key_update_with_valid_emptystring(self):
|
def test_foreign_key_update_with_valid_emptystring(self):
|
||||||
"""
|
"""
|
||||||
|
@ -443,9 +443,9 @@ class PKNullableForeignKeyTests(TestCase):
|
||||||
expected_data = {'id': 1, 'name': 'source-1', 'target': None}
|
expected_data = {'id': 1, 'name': 'source-1', 'target': None}
|
||||||
instance = NullableForeignKeySource.objects.get(pk=1)
|
instance = NullableForeignKeySource.objects.get(pk=1)
|
||||||
serializer = NullableForeignKeySourceSerializer(instance, data=data)
|
serializer = NullableForeignKeySourceSerializer(instance, data=data)
|
||||||
self.assertTrue(serializer.is_valid())
|
assert serializer.is_valid()
|
||||||
serializer.save()
|
serializer.save()
|
||||||
self.assertEqual(serializer.data, expected_data)
|
assert serializer.data == expected_data
|
||||||
|
|
||||||
# Ensure source 1 is updated, and everything else is as expected
|
# Ensure source 1 is updated, and everything else is as expected
|
||||||
queryset = NullableForeignKeySource.objects.all()
|
queryset = NullableForeignKeySource.objects.all()
|
||||||
|
@ -455,18 +455,18 @@ class PKNullableForeignKeyTests(TestCase):
|
||||||
{'id': 2, 'name': 'source-2', 'target': 1},
|
{'id': 2, 'name': 'source-2', 'target': 1},
|
||||||
{'id': 3, 'name': 'source-3', 'target': None}
|
{'id': 3, 'name': 'source-3', 'target': None}
|
||||||
]
|
]
|
||||||
self.assertEqual(serializer.data, expected)
|
assert serializer.data == expected
|
||||||
|
|
||||||
def test_null_uuid_foreign_key_serializes_as_none(self):
|
def test_null_uuid_foreign_key_serializes_as_none(self):
|
||||||
source = NullableUUIDForeignKeySource(name='Source')
|
source = NullableUUIDForeignKeySource(name='Source')
|
||||||
serializer = NullableUUIDForeignKeySourceSerializer(source)
|
serializer = NullableUUIDForeignKeySourceSerializer(source)
|
||||||
data = serializer.data
|
data = serializer.data
|
||||||
self.assertEqual(data["target"], None)
|
assert data["target"] is None
|
||||||
|
|
||||||
def test_nullable_uuid_foreign_key_is_valid_when_none(self):
|
def test_nullable_uuid_foreign_key_is_valid_when_none(self):
|
||||||
data = {"name": "Source", "target": None}
|
data = {"name": "Source", "target": None}
|
||||||
serializer = NullableUUIDForeignKeySourceSerializer(data=data)
|
serializer = NullableUUIDForeignKeySourceSerializer(data=data)
|
||||||
self.assertTrue(serializer.is_valid(), serializer.errors)
|
assert serializer.is_valid(), serializer.errors
|
||||||
|
|
||||||
|
|
||||||
class PKNullableOneToOneTests(TestCase):
|
class PKNullableOneToOneTests(TestCase):
|
||||||
|
@ -485,4 +485,4 @@ class PKNullableOneToOneTests(TestCase):
|
||||||
{'id': 1, 'name': 'target-1', 'nullable_source': None},
|
{'id': 1, 'name': 'target-1', 'nullable_source': None},
|
||||||
{'id': 2, 'name': 'target-2', 'nullable_source': 1},
|
{'id': 2, 'name': 'target-2', 'nullable_source': 1},
|
||||||
]
|
]
|
||||||
self.assertEqual(serializer.data, expected)
|
assert serializer.data == expected
|
||||||
|
|
|
@ -60,11 +60,11 @@ class TestNestedValidationError(TestCase):
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
self.assertEqual(serializers.as_serializer_error(e), {
|
assert serializers.as_serializer_error(e) == {
|
||||||
'nested': {
|
'nested': {
|
||||||
'field': ['error'],
|
'field': ['error'],
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
|
||||||
|
|
||||||
class TestPreSaveValidationExclusionsSerializer(TestCase):
|
class TestPreSaveValidationExclusionsSerializer(TestCase):
|
||||||
|
@ -75,20 +75,20 @@ class TestPreSaveValidationExclusionsSerializer(TestCase):
|
||||||
# We've set `required=False` on the serializer, but the model
|
# We've set `required=False` on the serializer, but the model
|
||||||
# does not have `blank=True`, so this serializer should not validate.
|
# does not have `blank=True`, so this serializer should not validate.
|
||||||
serializer = ShouldValidateModelSerializer(data={'renamed': ''})
|
serializer = ShouldValidateModelSerializer(data={'renamed': ''})
|
||||||
self.assertEqual(serializer.is_valid(), False)
|
assert serializer.is_valid() is False
|
||||||
self.assertIn('renamed', serializer.errors)
|
assert 'renamed' in serializer.errors
|
||||||
self.assertNotIn('should_validate_field', serializer.errors)
|
assert 'should_validate_field' not in serializer.errors
|
||||||
|
|
||||||
|
|
||||||
class TestCustomValidationMethods(TestCase):
|
class TestCustomValidationMethods(TestCase):
|
||||||
def test_custom_validation_method_is_executed(self):
|
def test_custom_validation_method_is_executed(self):
|
||||||
serializer = ShouldValidateModelSerializer(data={'renamed': 'fo'})
|
serializer = ShouldValidateModelSerializer(data={'renamed': 'fo'})
|
||||||
self.assertFalse(serializer.is_valid())
|
assert not serializer.is_valid()
|
||||||
self.assertIn('renamed', serializer.errors)
|
assert 'renamed' in serializer.errors
|
||||||
|
|
||||||
def test_custom_validation_method_passing(self):
|
def test_custom_validation_method_passing(self):
|
||||||
serializer = ShouldValidateModelSerializer(data={'renamed': 'foo'})
|
serializer = ShouldValidateModelSerializer(data={'renamed': 'foo'})
|
||||||
self.assertTrue(serializer.is_valid())
|
assert serializer.is_valid()
|
||||||
|
|
||||||
|
|
||||||
class ValidationSerializer(serializers.Serializer):
|
class ValidationSerializer(serializers.Serializer):
|
||||||
|
@ -108,12 +108,12 @@ class TestAvoidValidation(TestCase):
|
||||||
"""
|
"""
|
||||||
def test_serializer_errors_has_only_invalid_data_error(self):
|
def test_serializer_errors_has_only_invalid_data_error(self):
|
||||||
serializer = ValidationSerializer(data='invalid data')
|
serializer = ValidationSerializer(data='invalid data')
|
||||||
self.assertFalse(serializer.is_valid())
|
assert not serializer.is_valid()
|
||||||
self.assertDictEqual(serializer.errors, {
|
assert serializer.errors == {
|
||||||
'non_field_errors': [
|
'non_field_errors': [
|
||||||
'Invalid data. Expected a dictionary, but got %s.' % type('').__name__
|
'Invalid data. Expected a dictionary, but got %s.' % type('').__name__
|
||||||
]
|
]
|
||||||
})
|
}
|
||||||
|
|
||||||
|
|
||||||
# regression tests for issue: 1493
|
# regression tests for issue: 1493
|
||||||
|
@ -137,27 +137,31 @@ class TestMaxValueValidatorValidation(TestCase):
|
||||||
|
|
||||||
def test_max_value_validation_serializer_success(self):
|
def test_max_value_validation_serializer_success(self):
|
||||||
serializer = ValidationMaxValueValidatorModelSerializer(data={'number_value': 99})
|
serializer = ValidationMaxValueValidatorModelSerializer(data={'number_value': 99})
|
||||||
self.assertTrue(serializer.is_valid())
|
assert serializer.is_valid()
|
||||||
|
|
||||||
def test_max_value_validation_serializer_fails(self):
|
def test_max_value_validation_serializer_fails(self):
|
||||||
serializer = ValidationMaxValueValidatorModelSerializer(data={'number_value': 101})
|
serializer = ValidationMaxValueValidatorModelSerializer(data={'number_value': 101})
|
||||||
self.assertFalse(serializer.is_valid())
|
assert not serializer.is_valid()
|
||||||
self.assertDictEqual({'number_value': ['Ensure this value is less than or equal to 100.']}, serializer.errors)
|
assert serializer.errors == {
|
||||||
|
'number_value': [
|
||||||
|
'Ensure this value is less than or equal to 100.'
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
def test_max_value_validation_success(self):
|
def test_max_value_validation_success(self):
|
||||||
obj = ValidationMaxValueValidatorModel.objects.create(number_value=100)
|
obj = ValidationMaxValueValidatorModel.objects.create(number_value=100)
|
||||||
request = factory.patch('/{0}'.format(obj.pk), {'number_value': 98}, format='json')
|
request = factory.patch('/{0}'.format(obj.pk), {'number_value': 98}, format='json')
|
||||||
view = UpdateMaxValueValidationModel().as_view()
|
view = UpdateMaxValueValidationModel().as_view()
|
||||||
response = view(request, pk=obj.pk).render()
|
response = view(request, pk=obj.pk).render()
|
||||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
assert response.status_code == status.HTTP_200_OK
|
||||||
|
|
||||||
def test_max_value_validation_fail(self):
|
def test_max_value_validation_fail(self):
|
||||||
obj = ValidationMaxValueValidatorModel.objects.create(number_value=100)
|
obj = ValidationMaxValueValidatorModel.objects.create(number_value=100)
|
||||||
request = factory.patch('/{0}'.format(obj.pk), {'number_value': 101}, format='json')
|
request = factory.patch('/{0}'.format(obj.pk), {'number_value': 101}, format='json')
|
||||||
view = UpdateMaxValueValidationModel().as_view()
|
view = UpdateMaxValueValidationModel().as_view()
|
||||||
response = view(request, pk=obj.pk).render()
|
response = view(request, pk=obj.pk).render()
|
||||||
self.assertEqual(response.content, b'{"number_value":["Ensure this value is less than or equal to 100."]}')
|
assert response.content == b'{"number_value":["Ensure this value is less than or equal to 100."]}'
|
||||||
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
|
assert response.status_code == status.HTTP_400_BAD_REQUEST
|
||||||
|
|
||||||
|
|
||||||
# regression tests for issue: 1533
|
# regression tests for issue: 1533
|
||||||
|
|
|
@ -54,16 +54,16 @@ class TestValidationErrorWithFullDetails(TestCase):
|
||||||
|
|
||||||
request = factory.get('/', content_type='application/json')
|
request = factory.get('/', content_type='application/json')
|
||||||
response = view(request)
|
response = view(request)
|
||||||
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
|
assert response.status_code == status.HTTP_400_BAD_REQUEST
|
||||||
self.assertEqual(response.data, self.expected_response_data)
|
assert response.data == self.expected_response_data
|
||||||
|
|
||||||
def test_function_based_view_exception_handler(self):
|
def test_function_based_view_exception_handler(self):
|
||||||
view = error_view
|
view = error_view
|
||||||
|
|
||||||
request = factory.get('/', content_type='application/json')
|
request = factory.get('/', content_type='application/json')
|
||||||
response = view(request)
|
response = view(request)
|
||||||
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
|
assert response.status_code == status.HTTP_400_BAD_REQUEST
|
||||||
self.assertEqual(response.data, self.expected_response_data)
|
assert response.data == self.expected_response_data
|
||||||
|
|
||||||
|
|
||||||
class TestValidationErrorWithCodes(TestCase):
|
class TestValidationErrorWithCodes(TestCase):
|
||||||
|
@ -89,13 +89,13 @@ class TestValidationErrorWithCodes(TestCase):
|
||||||
|
|
||||||
request = factory.get('/', content_type='application/json')
|
request = factory.get('/', content_type='application/json')
|
||||||
response = view(request)
|
response = view(request)
|
||||||
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
|
assert response.status_code == status.HTTP_400_BAD_REQUEST
|
||||||
self.assertEqual(response.data, self.expected_response_data)
|
assert response.data == self.expected_response_data
|
||||||
|
|
||||||
def test_function_based_view_exception_handler(self):
|
def test_function_based_view_exception_handler(self):
|
||||||
view = error_view
|
view = error_view
|
||||||
|
|
||||||
request = factory.get('/', content_type='application/json')
|
request = factory.get('/', content_type='application/json')
|
||||||
response = view(request)
|
response = view(request)
|
||||||
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
|
assert response.status_code == status.HTTP_400_BAD_REQUEST
|
||||||
self.assertEqual(response.data, self.expected_response_data)
|
assert response.data == self.expected_response_data
|
||||||
|
|
Loading…
Reference in New Issue
Block a user