Skip to content

Commit 2c49951

Browse files
authored
Merge branch 'master' into 20240426_requirements
2 parents 8030a12 + e596f43 commit 2c49951

File tree

6 files changed

+25
-160
lines changed

6 files changed

+25
-160
lines changed

README.md

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -172,8 +172,6 @@ Full documentation for the project is available at [https://www.django-rest-fram
172172

173173
For questions and support, use the [REST framework discussion group][group], or `#restframework` on libera.chat IRC.
174174

175-
You may also want to [follow the author on Twitter][twitter].
176-
177175
# Security
178176

179177
Please see the [security policy][security-policy].
@@ -184,7 +182,6 @@ Please see the [security policy][security-policy].
184182
[codecov]: https://codecov.io/github/encode/django-rest-framework?branch=master
185183
[pypi-version]: https://img.shields.io/pypi/v/djangorestframework.svg
186184
[pypi]: https://pypi.org/project/djangorestframework/
187-
[twitter]: https://twitter.com/starletdreaming
188185
[group]: https://groups.google.com/forum/?fromgroups#!forum/django-rest-framework
189186

190187
[funding]: https://fund.django-rest-framework.org/topics/funding/

docs/tutorial/quickstart.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ Create a new Django project named `tutorial`, then start a new app called `quick
1515
source env/bin/activate # On Windows use `env\Scripts\activate`
1616

1717
# Install Django and Django REST framework into the virtual environment
18-
pip install django
1918
pip install djangorestframework
2019

2120
# Set up a new project with a single application

rest_framework/fields.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44
import decimal
55
import functools
66
import inspect
7-
import logging
87
import re
98
import uuid
9+
import warnings
1010
from collections.abc import Mapping
1111
from enum import Enum
1212

@@ -44,8 +44,6 @@
4444
from rest_framework.utils.timezone import valid_datetime
4545
from rest_framework.validators import ProhibitSurrogateCharactersValidator
4646

47-
logger = logging.getLogger("rest_framework.fields")
48-
4947

5048
class empty:
5149
"""
@@ -989,9 +987,9 @@ def __init__(self, max_digits, decimal_places, coerce_to_string=None, max_value=
989987
self.min_value = min_value
990988

991989
if self.max_value is not None and not isinstance(self.max_value, decimal.Decimal):
992-
logger.warning("max_value in DecimalField should be Decimal type.")
990+
warnings.warn("max_value should be a Decimal instance.")
993991
if self.min_value is not None and not isinstance(self.min_value, decimal.Decimal):
994-
logger.warning("min_value in DecimalField should be Decimal type.")
992+
warnings.warn("min_value should be a Decimal instance.")
995993

996994
if self.max_digits is not None and self.decimal_places is not None:
997995
self.max_whole_digits = self.max_digits - self.decimal_places

rest_framework/pagination.py

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111

1212
from django.core.paginator import InvalidPage
1313
from django.core.paginator import Paginator as DjangoPaginator
14-
from django.db.models import Q
1514
from django.template import loader
1615
from django.utils.encoding import force_str
1716
from django.utils.translation import gettext_lazy as _
@@ -631,7 +630,7 @@ def paginate_queryset(self, queryset, request, view=None):
631630
queryset = queryset.order_by(*self.ordering)
632631

633632
# If we have a cursor with a fixed position then filter by that.
634-
if str(current_position) != 'None':
633+
if current_position is not None:
635634
order = self.ordering[0]
636635
is_reversed = order.startswith('-')
637636
order_attr = order.lstrip('-')
@@ -642,12 +641,7 @@ def paginate_queryset(self, queryset, request, view=None):
642641
else:
643642
kwargs = {order_attr + '__gt': current_position}
644643

645-
filter_query = Q(**kwargs)
646-
# If some records contain a null for the ordering field, don't lose them.
647-
# When reverse ordering, nulls will come last and need to be included.
648-
if (reverse and not is_reversed) or is_reversed:
649-
filter_query |= Q(**{order_attr + '__isnull': True})
650-
queryset = queryset.filter(filter_query)
644+
queryset = queryset.filter(**kwargs)
651645

652646
# If we have an offset cursor then offset the entire page by that amount.
653647
# We also always fetch an extra item in order to determine if there is a
@@ -720,7 +714,7 @@ def get_next_link(self):
720714
# The item in this position and the item following it
721715
# have different positions. We can use this position as
722716
# our marker.
723-
has_item_with_unique_position = position is not None
717+
has_item_with_unique_position = True
724718
break
725719

726720
# The item in this position has the same position as the item
@@ -773,7 +767,7 @@ def get_previous_link(self):
773767
# The item in this position and the item following it
774768
# have different positions. We can use this position as
775769
# our marker.
776-
has_item_with_unique_position = position is not None
770+
has_item_with_unique_position = True
777771
break
778772

779773
# The item in this position has the same position as the item
@@ -896,7 +890,7 @@ def _get_position_from_instance(self, instance, ordering):
896890
attr = instance[field_name]
897891
else:
898892
attr = getattr(instance, field_name)
899-
return None if attr is None else str(attr)
893+
return str(attr)
900894

901895
def get_paginated_response(self, data):
902896
return Response({

tests/test_fields.py

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import re
55
import sys
66
import uuid
7+
import warnings
78
from decimal import ROUND_DOWN, ROUND_UP, Decimal
89
from enum import auto
910
from unittest.mock import patch
@@ -1254,15 +1255,19 @@ class TestMinMaxDecimalField(FieldValues):
12541255
)
12551256

12561257
def test_warning_when_not_decimal_types(self, caplog):
1257-
import logging
1258-
serializers.DecimalField(
1259-
max_digits=3, decimal_places=1,
1260-
min_value=10, max_value=20
1261-
)
1262-
assert caplog.record_tuples == [
1263-
("rest_framework.fields", logging.WARNING, "max_value in DecimalField should be Decimal type."),
1264-
("rest_framework.fields", logging.WARNING, "min_value in DecimalField should be Decimal type.")
1265-
]
1258+
with warnings.catch_warnings(record=True) as w:
1259+
warnings.simplefilter('always')
1260+
1261+
serializers.DecimalField(
1262+
max_digits=3, decimal_places=1,
1263+
min_value=10, max_value=20
1264+
)
1265+
1266+
assert len(w) == 2
1267+
assert all(issubclass(i.category, UserWarning) for i in w)
1268+
1269+
assert 'max_value should be a Decimal instance' in str(w[0].message)
1270+
assert 'min_value should be a Decimal instance' in str(w[1].message)
12661271

12671272

12681273
class TestAllowEmptyStrDecimalFieldWithValidators(FieldValues):

tests/test_pagination.py

Lines changed: 3 additions & 131 deletions
Original file line numberDiff line numberDiff line change
@@ -972,24 +972,17 @@ class MockQuerySet:
972972
def __init__(self, items):
973973
self.items = items
974974

975-
def filter(self, q):
976-
q_args = dict(q.deconstruct()[1])
977-
if not q_args:
978-
# django 3.0.x artifact
979-
q_args = dict(q.deconstruct()[2])
980-
created__gt = q_args.get('created__gt')
981-
created__lt = q_args.get('created__lt')
982-
975+
def filter(self, created__gt=None, created__lt=None):
983976
if created__gt is not None:
984977
return MockQuerySet([
985978
item for item in self.items
986-
if item.created is None or item.created > int(created__gt)
979+
if item.created > int(created__gt)
987980
])
988981

989982
assert created__lt is not None
990983
return MockQuerySet([
991984
item for item in self.items
992-
if item.created is None or item.created < int(created__lt)
985+
if item.created < int(created__lt)
993986
])
994987

995988
def order_by(self, *ordering):
@@ -1108,127 +1101,6 @@ def get_pages(self, url):
11081101
return (previous, current, next, previous_url, next_url)
11091102

11101103

1111-
class NullableCursorPaginationModel(models.Model):
1112-
created = models.IntegerField(null=True)
1113-
1114-
1115-
class TestCursorPaginationWithNulls(TestCase):
1116-
"""
1117-
Unit tests for `pagination.CursorPagination` with ordering on a nullable field.
1118-
"""
1119-
1120-
def setUp(self):
1121-
class ExamplePagination(pagination.CursorPagination):
1122-
page_size = 1
1123-
ordering = 'created'
1124-
1125-
self.pagination = ExamplePagination()
1126-
data = [
1127-
None, None, 3, 4
1128-
]
1129-
for idx in data:
1130-
NullableCursorPaginationModel.objects.create(created=idx)
1131-
1132-
self.queryset = NullableCursorPaginationModel.objects.all()
1133-
1134-
get_pages = TestCursorPagination.get_pages
1135-
1136-
def test_ascending(self):
1137-
"""Test paginating one row at a time, current should go 1, 2, 3, 4, 3, 2, 1."""
1138-
(previous, current, next, previous_url, next_url) = self.get_pages('/')
1139-
1140-
assert previous is None
1141-
assert current == [None]
1142-
assert next == [None]
1143-
1144-
(previous, current, next, previous_url, next_url) = self.get_pages(next_url)
1145-
1146-
assert previous == [None]
1147-
assert current == [None]
1148-
assert next == [3]
1149-
1150-
(previous, current, next, previous_url, next_url) = self.get_pages(next_url)
1151-
1152-
assert previous == [3] # [None] paging artifact documented at https://github.com/ddelange/django-rest-framework/blob/3.14.0/rest_framework/pagination.py#L789
1153-
assert current == [3]
1154-
assert next == [4]
1155-
1156-
(previous, current, next, previous_url, next_url) = self.get_pages(next_url)
1157-
1158-
assert previous == [3]
1159-
assert current == [4]
1160-
assert next is None
1161-
assert next_url is None
1162-
1163-
(previous, current, next, previous_url, next_url) = self.get_pages(previous_url)
1164-
1165-
assert previous == [None]
1166-
assert current == [3]
1167-
assert next == [4]
1168-
1169-
(previous, current, next, previous_url, next_url) = self.get_pages(previous_url)
1170-
1171-
assert previous == [None]
1172-
assert current == [None]
1173-
assert next == [None] # [3] paging artifact documented at https://github.com/ddelange/django-rest-framework/blob/3.14.0/rest_framework/pagination.py#L731
1174-
1175-
(previous, current, next, previous_url, next_url) = self.get_pages(previous_url)
1176-
1177-
assert previous is None
1178-
assert current == [None]
1179-
assert next == [None]
1180-
1181-
def test_descending(self):
1182-
"""Test paginating one row at a time, current should go 4, 3, 2, 1, 2, 3, 4."""
1183-
self.pagination.ordering = ('-created',)
1184-
(previous, current, next, previous_url, next_url) = self.get_pages('/')
1185-
1186-
assert previous is None
1187-
assert current == [4]
1188-
assert next == [3]
1189-
1190-
(previous, current, next, previous_url, next_url) = self.get_pages(next_url)
1191-
1192-
assert previous == [None] # [4] paging artifact
1193-
assert current == [3]
1194-
assert next == [None]
1195-
1196-
(previous, current, next, previous_url, next_url) = self.get_pages(next_url)
1197-
1198-
assert previous == [None] # [3] paging artifact
1199-
assert current == [None]
1200-
assert next == [None]
1201-
1202-
(previous, current, next, previous_url, next_url) = self.get_pages(next_url)
1203-
1204-
assert previous == [None]
1205-
assert current == [None]
1206-
assert next is None
1207-
assert next_url is None
1208-
1209-
(previous, current, next, previous_url, next_url) = self.get_pages(previous_url)
1210-
1211-
assert previous == [3]
1212-
assert current == [None]
1213-
assert next == [None]
1214-
1215-
(previous, current, next, previous_url, next_url) = self.get_pages(previous_url)
1216-
1217-
assert previous == [None]
1218-
assert current == [3]
1219-
assert next == [3] # [4] paging artifact documented at https://github.com/ddelange/django-rest-framework/blob/3.14.0/rest_framework/pagination.py#L731
1220-
1221-
# skip back artifact
1222-
(previous, current, next, previous_url, next_url) = self.get_pages(previous_url)
1223-
(previous, current, next, previous_url, next_url) = self.get_pages(previous_url)
1224-
1225-
(previous, current, next, previous_url, next_url) = self.get_pages(previous_url)
1226-
1227-
assert previous is None
1228-
assert current == [4]
1229-
assert next == [3]
1230-
1231-
12321104
def test_get_displayed_page_numbers():
12331105
"""
12341106
Test our contextual page display function.

0 commit comments

Comments
 (0)