This commit is contained in:
Asif Saif Uddin (Auvi) 2020-05-12 10:04:01 +06:00
commit c32997735e
19 changed files with 42 additions and 29 deletions

View File

@ -1,6 +1,6 @@
language: python language: python
cache: pip cache: pip
dist: xenial dist: bionic
matrix: matrix:
fast_finish: true fast_finish: true
include: include:

View File

@ -89,7 +89,7 @@ Startup up a new project like so...
Now edit the `example/urls.py` module in your project: Now edit the `example/urls.py` module in your project:
```python ```python
from django.conf.urls import url, include from django.urls import path, include
from django.contrib.auth.models import User from django.contrib.auth.models import User
from rest_framework import serializers, viewsets, routers from rest_framework import serializers, viewsets, routers
@ -114,8 +114,8 @@ router.register(r'users', UserViewSet)
# Wire up our API using automatic URL routing. # Wire up our API using automatic URL routing.
# Additionally, we include login URLs for the browsable API. # Additionally, we include login URLs for the browsable API.
urlpatterns = [ urlpatterns = [
url(r'^', include(router.urls)), path('', include(router.urls)),
url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')) path('api-auth/', include('rest_framework.urls', namespace='rest_framework'))
] ]
``` ```

View File

@ -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.: 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) * [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 # Custom authentication

View File

@ -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. For example, the following additional route could be used on a viewset to provide a linkable schema endpoint.
@action(methods=['GET'], detail=False) @action(methods=['GET'], detail=False)
def schema(self, request): def api_schema(self, request):
meta = self.metadata_class() meta = self.metadata_class()
data = meta.determine_metadata(request, self) data = meta.determine_metadata(request, self)
return Response(data) return Response(data)

View File

@ -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. We're ready to create our API now.
Here's our project's root `urls.py` module: 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 django.contrib.auth.models import User
from rest_framework import routers, serializers, viewsets 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. # Wire up our API using automatic URL routing.
# Additionally, we include login URLs for the browsable API. # Additionally, we include login URLs for the browsable API.
urlpatterns = [ urlpatterns = [
url(r'^', include(router.urls)), path('', include(router.urls)),
url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')) 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. 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.

View File

@ -1,6 +1,6 @@
# PEP8 code linting, which we run on all commits. # PEP8 code linting, which we run on all commits.
flake8==3.7.8 flake8==3.7.9
flake8-tidy-imports==3.0.0 flake8-tidy-imports==4.1.0
pycodestyle==2.5.0 pycodestyle==2.5.0
# Sort and lint imports # Sort and lint imports

View File

@ -1,2 +1,2 @@
# MkDocs to build our documentation. # MkDocs to build our documentation.
mkdocs==1.0.4 mkdocs==1.1

View File

@ -1,8 +1,8 @@
# Optional packages which may be used with REST framework. # 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 markdown==3.1.1
pygments==2.4.2 pygments==2.4.2
django-guardian==2.1.0 django-guardian==2.2.0
django-filter>=2.2.0, <2.3 django-filter>=2.2.0, <2.3
coreapi==2.3.1 coreapi==2.3.1
coreschema==0.0.4 coreschema==0.0.4

View File

@ -1,8 +1,8 @@
# Wheel for PyPI installs. # Wheel for PyPI installs.
wheel==0.30.0 wheel==0.34.2
# Twine for secured PyPI uploads. # Twine for secured PyPI uploads.
twine==1.11.0 twine==3.1.1
# Transifex client for managing translation resources. # Transifex client for managing translation resources.
transifex-client==0.11 transifex-client==0.13.9

View File

@ -1,4 +1,4 @@
# Pytest for running the tests. # Pytest for running the tests.
pytest>=5.0,<5.1 pytest>=5.4.1,<5.5
pytest-django>=3.5.1,<3.6 pytest-django>=3.9.0,<3.10
pytest-cov>=2.7.1 pytest-cov>=2.7.1

View File

@ -3,10 +3,8 @@ from django.contrib import admin
from rest_framework.authtoken.models import Token from rest_framework.authtoken.models import Token
@admin.register(Token)
class TokenAdmin(admin.ModelAdmin): class TokenAdmin(admin.ModelAdmin):
list_display = ('key', 'user', 'created') list_display = ('key', 'user', 'created')
fields = ('user',) fields = ('user',)
ordering = ('-created',) ordering = ('-created',)
admin.site.register(Token, TokenAdmin)

View File

@ -85,7 +85,7 @@ class SearchFilter(BaseFilterBackend):
search_field = search_field[1:] search_field = search_field[1:]
# Annotated fields do not need to be distinct # Annotated fields do not need to be distinct
if isinstance(queryset, models.QuerySet) and search_field in queryset.query.annotations: if isinstance(queryset, models.QuerySet) and search_field in queryset.query.annotations:
return False continue
parts = search_field.split(LOOKUP_SEP) parts = search_field.split(LOOKUP_SEP)
for part in parts: for part in parts:
field = opts.get_field(part) field = opts.get_field(part)

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -250,7 +250,7 @@
csrfToken: "{{ csrf_token }}" csrfToken: "{{ csrf_token }}"
}; };
</script> </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/ajax-form.js" %}"></script>
<script src="{% static "rest_framework/js/csrf.js" %}"></script> <script src="{% static "rest_framework/js/csrf.js" %}"></script>
<script src="{% static "rest_framework/js/bootstrap.min.js" %}"></script> <script src="{% static "rest_framework/js/bootstrap.min.js" %}"></script>

View File

@ -293,7 +293,7 @@
csrfToken: "{% if request %}{{ csrf_token }}{% endif %}" csrfToken: "{% if request %}{{ csrf_token }}{% endif %}"
}; };
</script> </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/ajax-form.js" %}"></script>
<script src="{% static "rest_framework/js/csrf.js" %}"></script> <script src="{% static "rest_framework/js/csrf.js" %}"></script>
<script src="{% static "rest_framework/js/bootstrap.min.js" %}"></script> <script src="{% static "rest_framework/js/bootstrap.min.js" %}"></script>

View File

@ -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> </body>
</html> </html>

View File

@ -38,7 +38,7 @@
{% include "rest_framework/docs/auth/basic.html" %} {% include "rest_framework/docs/auth/basic.html" %}
{% include "rest_framework/docs/auth/session.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/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/jquery.json-view.min.js' %}"></script>
<script src="{% static 'rest_framework/docs/js/api.js' %}"></script> <script src="{% static 'rest_framework/docs/js/api.js' %}"></script>

View File

@ -406,6 +406,21 @@ class SearchFilterAnnotatedFieldTests(TestCase):
assert len(response.data) == 1 assert len(response.data) == 1
assert response.data[0]['title_text'] == 'ABCDEF' 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): class OrderingFilterModel(models.Model):
title = models.CharField(max_length=20, verbose_name='verbose title') title = models.CharField(max_length=20, verbose_name='verbose title')