mirror of
https://github.com/encode/django-rest-framework.git
synced 2025-07-27 16:40:03 +03:00
Merge branch 'master' of https://github.com/encode/django-rest-framework
This commit is contained in:
commit
c32997735e
|
@ -1,6 +1,6 @@
|
|||
language: python
|
||||
cache: pip
|
||||
dist: xenial
|
||||
dist: bionic
|
||||
matrix:
|
||||
fast_finish: true
|
||||
include:
|
||||
|
|
|
@ -89,7 +89,7 @@ Startup up a new project like so...
|
|||
Now edit the `example/urls.py` module in your project:
|
||||
|
||||
```python
|
||||
from django.conf.urls import url, include
|
||||
from django.urls import path, include
|
||||
from django.contrib.auth.models import User
|
||||
from rest_framework import serializers, viewsets, routers
|
||||
|
||||
|
@ -114,8 +114,8 @@ router.register(r'users', UserViewSet)
|
|||
# Wire up our API using automatic URL routing.
|
||||
# Additionally, we include login URLs for the browsable API.
|
||||
urlpatterns = [
|
||||
url(r'^', include(router.urls)),
|
||||
url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework'))
|
||||
path('', include(router.urls)),
|
||||
path('api-auth/', include('rest_framework.urls', namespace='rest_framework'))
|
||||
]
|
||||
```
|
||||
|
||||
|
|
|
@ -304,7 +304,7 @@ If successfully authenticated, `RemoteUserAuthentication` provides the following
|
|||
Consult your web server's documentation for information about configuring an authentication method, e.g.:
|
||||
|
||||
* [Apache Authentication How-To](https://httpd.apache.org/docs/2.4/howto/auth.html)
|
||||
* [NGINX (Restricting Access)](https://www.nginx.com/resources/admin-guide/#restricting_access)
|
||||
* [NGINX (Restricting Access)](https://docs.nginx.com/nginx/admin-guide/security-controls/configuring-http-basic-authentication/)
|
||||
|
||||
|
||||
# Custom authentication
|
||||
|
|
|
@ -71,7 +71,7 @@ If you have specific requirements for creating schema endpoints that are accesse
|
|||
For example, the following additional route could be used on a viewset to provide a linkable schema endpoint.
|
||||
|
||||
@action(methods=['GET'], detail=False)
|
||||
def schema(self, request):
|
||||
def api_schema(self, request):
|
||||
meta = self.metadata_class()
|
||||
data = meta.determine_metadata(request, self)
|
||||
return Response(data)
|
||||
|
|
|
@ -148,7 +148,7 @@ Don't forget to make sure you've also added `rest_framework` to your `INSTALLED_
|
|||
We're ready to create our API now.
|
||||
Here's our project's root `urls.py` module:
|
||||
|
||||
from django.conf.urls import url, include
|
||||
from django.urls import path, include
|
||||
from django.contrib.auth.models import User
|
||||
from rest_framework import routers, serializers, viewsets
|
||||
|
||||
|
@ -170,8 +170,8 @@ Here's our project's root `urls.py` module:
|
|||
# Wire up our API using automatic URL routing.
|
||||
# Additionally, we include login URLs for the browsable API.
|
||||
urlpatterns = [
|
||||
url(r'^', include(router.urls)),
|
||||
url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework'))
|
||||
path('', include(router.urls)),
|
||||
path('api-auth/', include('rest_framework.urls', namespace='rest_framework'))
|
||||
]
|
||||
|
||||
You can now open the API in your browser at [http://127.0.0.1:8000/](http://127.0.0.1:8000/), and view your new 'users' API. If you use the login control in the top right corner you'll also be able to add, create and delete users from the system.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# PEP8 code linting, which we run on all commits.
|
||||
flake8==3.7.8
|
||||
flake8-tidy-imports==3.0.0
|
||||
flake8==3.7.9
|
||||
flake8-tidy-imports==4.1.0
|
||||
pycodestyle==2.5.0
|
||||
|
||||
# Sort and lint imports
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
# MkDocs to build our documentation.
|
||||
mkdocs==1.0.4
|
||||
mkdocs==1.1
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
# Optional packages which may be used with REST framework.
|
||||
psycopg2-binary>=2.8.2, <2.9
|
||||
psycopg2-binary>=2.8.5, <2.9
|
||||
markdown==3.1.1
|
||||
pygments==2.4.2
|
||||
django-guardian==2.1.0
|
||||
django-guardian==2.2.0
|
||||
django-filter>=2.2.0, <2.3
|
||||
coreapi==2.3.1
|
||||
coreschema==0.0.4
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
# Wheel for PyPI installs.
|
||||
wheel==0.30.0
|
||||
wheel==0.34.2
|
||||
|
||||
# Twine for secured PyPI uploads.
|
||||
twine==1.11.0
|
||||
twine==3.1.1
|
||||
|
||||
# Transifex client for managing translation resources.
|
||||
transifex-client==0.11
|
||||
transifex-client==0.13.9
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# Pytest for running the tests.
|
||||
pytest>=5.0,<5.1
|
||||
pytest-django>=3.5.1,<3.6
|
||||
pytest>=5.4.1,<5.5
|
||||
pytest-django>=3.9.0,<3.10
|
||||
pytest-cov>=2.7.1
|
||||
|
|
|
@ -3,10 +3,8 @@ from django.contrib import admin
|
|||
from rest_framework.authtoken.models import Token
|
||||
|
||||
|
||||
@admin.register(Token)
|
||||
class TokenAdmin(admin.ModelAdmin):
|
||||
list_display = ('key', 'user', 'created')
|
||||
fields = ('user',)
|
||||
ordering = ('-created',)
|
||||
|
||||
|
||||
admin.site.register(Token, TokenAdmin)
|
||||
|
|
|
@ -85,7 +85,7 @@ class SearchFilter(BaseFilterBackend):
|
|||
search_field = search_field[1:]
|
||||
# Annotated fields do not need to be distinct
|
||||
if isinstance(queryset, models.QuerySet) and search_field in queryset.query.annotations:
|
||||
return False
|
||||
continue
|
||||
parts = search_field.split(LOOKUP_SEP)
|
||||
for part in parts:
|
||||
field = opts.get_field(part)
|
||||
|
|
File diff suppressed because one or more lines are too long
2
rest_framework/static/rest_framework/js/jquery-3.5.1.min.js
vendored
Normal file
2
rest_framework/static/rest_framework/js/jquery-3.5.1.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
|
@ -250,7 +250,7 @@
|
|||
csrfToken: "{{ csrf_token }}"
|
||||
};
|
||||
</script>
|
||||
<script src="{% static "rest_framework/js/jquery-3.4.1.min.js" %}"></script>
|
||||
<script src="{% static "rest_framework/js/jquery-3.5.1.min.js" %}"></script>
|
||||
<script src="{% static "rest_framework/js/ajax-form.js" %}"></script>
|
||||
<script src="{% static "rest_framework/js/csrf.js" %}"></script>
|
||||
<script src="{% static "rest_framework/js/bootstrap.min.js" %}"></script>
|
||||
|
|
|
@ -293,7 +293,7 @@
|
|||
csrfToken: "{% if request %}{{ csrf_token }}{% endif %}"
|
||||
};
|
||||
</script>
|
||||
<script src="{% static "rest_framework/js/jquery-3.4.1.min.js" %}"></script>
|
||||
<script src="{% static "rest_framework/js/jquery-3.5.1.min.js" %}"></script>
|
||||
<script src="{% static "rest_framework/js/ajax-form.js" %}"></script>
|
||||
<script src="{% static "rest_framework/js/csrf.js" %}"></script>
|
||||
<script src="{% static "rest_framework/js/bootstrap.min.js" %}"></script>
|
||||
|
|
|
@ -66,6 +66,6 @@ at <code>rest_framework/docs/error.html</code>.</p>
|
|||
|
||||
|
||||
|
||||
<script src="{% static 'rest_framework/js/jquery-3.4.1.min.js' %}"></script>
|
||||
<script src="{% static 'rest_framework/js/jquery-3.5.1.min.js' %}"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -38,7 +38,7 @@
|
|||
{% include "rest_framework/docs/auth/basic.html" %}
|
||||
{% include "rest_framework/docs/auth/session.html" %}
|
||||
|
||||
<script src="{% static 'rest_framework/js/jquery-3.4.1.min.js' %}"></script>
|
||||
<script src="{% static 'rest_framework/js/jquery-3.5.1.min.js' %}"></script>
|
||||
<script src="{% static 'rest_framework/js/bootstrap.min.js' %}"></script>
|
||||
<script src="{% static 'rest_framework/docs/js/jquery.json-view.min.js' %}"></script>
|
||||
<script src="{% static 'rest_framework/docs/js/api.js' %}"></script>
|
||||
|
|
|
@ -406,6 +406,21 @@ class SearchFilterAnnotatedFieldTests(TestCase):
|
|||
assert len(response.data) == 1
|
||||
assert response.data[0]['title_text'] == 'ABCDEF'
|
||||
|
||||
def test_must_call_distinct_subsequent_m2m_fields(self):
|
||||
f = filters.SearchFilter()
|
||||
|
||||
queryset = SearchFilterModelM2M.objects.annotate(
|
||||
title_text=Upper(
|
||||
Concat(models.F('title'), models.F('text'))
|
||||
)
|
||||
).all()
|
||||
|
||||
# Sanity check that m2m must call distinct
|
||||
assert f.must_call_distinct(queryset, ['attributes'])
|
||||
|
||||
# Annotated field should not prevent m2m must call distinct
|
||||
assert f.must_call_distinct(queryset, ['title_text', 'attributes'])
|
||||
|
||||
|
||||
class OrderingFilterModel(models.Model):
|
||||
title = models.CharField(max_length=20, verbose_name='verbose title')
|
||||
|
|
Loading…
Reference in New Issue
Block a user