django-restframework: bump to 3.17.0
authorAlexandru Ardelean <redacted>
Tue, 24 Mar 2026 07:49:07 +0000 (07:49 +0000)
committerAlexandru Ardelean <redacted>
Tue, 24 Mar 2026 16:26:33 +0000 (18:26 +0200)
v3.17.0 changes:
- Drop Python 3.9 support (minimum now 3.10)
- Drop deprecated coreapi support
- Add Python 3.14 support
- Add ability to specify output format for DurationField
- Add missing decorators: @versioning_class(), @content_negotiation_class(),
  @metadata_class() for function-based views
- Support violation messages in UniqueConstraint

Full release notes:
https://github.com/encode/django-rest-framework/releases/tag/3.17.0

Co-Authored-By: Claude Sonnet 4.6 <redacted>
Signed-off-by: Alexandru Ardelean <redacted>
lang/python/django-restframework/Makefile
lang/python/django-restframework/test.sh [new file with mode: 0755]

index 62811b1e61c6e5125e824970605e1939a8d974ff..c1cac96a81e0936d2655172109e16f4c69a71afa 100644 (file)
@@ -8,11 +8,11 @@
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=django-restframework
-PKG_VERSION:=3.16.1
+PKG_VERSION:=3.17.0
 PKG_RELEASE:=1
 
 PYPI_NAME:=djangorestframework
-PKG_HASH:=166809528b1aced0a17dc66c24492af18049f2c9420dbd0be29422029cfc3ff7
+PKG_HASH:=456fd992a33f9e64c9d0f47e85d9787db0efb44f894c1e513315b5e74765bd4c
 
 PKG_MAINTAINER:=Alexandru Ardelean <ardeleanalex@gmail.com>
 PKG_LICENSE:=BSD-3-Clause
diff --git a/lang/python/django-restframework/test.sh b/lang/python/django-restframework/test.sh
new file mode 100755 (executable)
index 0000000..4028527
--- /dev/null
@@ -0,0 +1,113 @@
+#!/bin/sh
+
+[ "$1" = "python3-django-restframework" ] || exit 0
+
+python3 - << EOF
+import sys
+import importlib.metadata
+
+version = importlib.metadata.version("djangorestframework")
+if version != "$2":
+    print("Wrong version: " + version)
+    sys.exit(1)
+
+# Bootstrap a minimal Django configuration
+import django
+from django.conf import settings
+settings.configure(
+    INSTALLED_APPS=[
+        "django.contrib.contenttypes",
+        "django.contrib.auth",
+        "rest_framework",
+    ],
+    DATABASES={
+        "default": {
+            "ENGINE": "django.db.backends.sqlite3",
+            "NAME": ":memory:",
+        }
+    },
+    ROOT_URLCONF=[],
+    DEFAULT_AUTO_FIELD="django.db.models.BigAutoField",
+)
+django.setup()
+
+# --- Serializer ---
+
+from rest_framework import serializers
+
+class BookSerializer(serializers.Serializer):
+    title = serializers.CharField(max_length=100)
+    year = serializers.IntegerField(min_value=0)
+    isbn = serializers.CharField(required=False, allow_blank=True)
+
+# Valid data
+s = BookSerializer(data={"title": "Two Scoops of Django", "year": 2023})
+assert s.is_valid(), f"Serializer errors: {s.errors}"
+assert s.validated_data["title"] == "Two Scoops of Django"
+assert s.validated_data["year"] == 2023
+
+# Invalid data
+s2 = BookSerializer(data={"title": "", "year": -1})
+assert not s2.is_valid()
+assert "title" in s2.errors
+assert "year" in s2.errors
+
+# --- APIRequestFactory + APIView ---
+
+from rest_framework.views import APIView
+from rest_framework.response import Response
+from rest_framework.test import APIRequestFactory
+from rest_framework import status
+
+class EchoView(APIView):
+    def get(self, request):
+        return Response({"method": "GET", "query": request.query_params.get("q", "")})
+
+    def post(self, request):
+        return Response({"received": request.data}, status=status.HTTP_201_CREATED)
+
+factory = APIRequestFactory()
+
+# GET
+request = factory.get("/echo/", {"q": "hello"})
+view = EchoView.as_view()
+response = view(request)
+response.accepted_renderer = __import__("rest_framework.renderers", fromlist=["JSONRenderer"]).JSONRenderer()
+response.accepted_media_type = "application/json"
+response.renderer_context = {}
+assert response.status_code == 200
+assert response.data["method"] == "GET"
+assert response.data["query"] == "hello"
+
+# POST
+request = factory.post("/echo/", {"key": "value"}, format="json")
+response = view(request)
+assert response.status_code == 201
+assert response.data["received"] == {"key": "value"}
+
+# --- Status codes ---
+
+assert status.HTTP_200_OK == 200
+assert status.HTTP_201_CREATED == 201
+assert status.HTTP_400_BAD_REQUEST == 400
+assert status.HTTP_404_NOT_FOUND == 404
+assert status.is_success(200)
+assert status.is_client_error(400)
+assert status.is_server_error(500)
+
+# --- SimpleRouter ---
+
+from rest_framework.routers import SimpleRouter
+from rest_framework.viewsets import ViewSet
+
+class NullViewSet(ViewSet):
+    def list(self, request):
+        return Response([])
+
+router = SimpleRouter()
+router.register(r"items", NullViewSet, basename="item")
+urls = [u.name for u in router.urls]
+assert "item-list" in urls, f"Expected item-list in {urls}"
+
+sys.exit(0)
+EOF
git clone https://git.99rst.org/PROJECT