Skip to content

Commit e7384da

Browse files
authored
Merge pull request github#14341 from GeekMasher/py-django-restframework
Python - Add support for RestFramework ModelViewSet functions
2 parents 0dd3837 + 3162033 commit e7384da

File tree

8 files changed

+59
-22
lines changed

8 files changed

+59
-22
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: minorAnalysis
3+
---
4+
* Django Rest Framework better handles custom `ModelViewSet` classes functions

python/ql/lib/semmle/python/frameworks/RestFramework.qll

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,10 @@ private module RestFramework {
131131
"initial", "http_method_not_allowed", "permission_denied", "throttled",
132132
"get_authenticate_header", "perform_content_negotiation", "perform_authentication",
133133
"check_permissions", "check_object_permissions", "check_throttles", "determine_version",
134-
"initialize_request", "finalize_response", "dispatch", "options"
134+
"initialize_request", "finalize_response", "dispatch", "options",
135+
// ModelViewSet
136+
// https://github.com/encode/django-rest-framework/blob/master/rest_framework/viewsets.py
137+
"create", "retrieve", "update", "partial_update", "destroy", "list"
135138
]
136139
}
137140
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
failures
21
testFailures
2+
failures
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,8 @@
11
import python
22
import experimental.meta.ConceptsTest
3+
4+
class DedicatedTest extends DedicatedResponseTest {
5+
DedicatedTest() { this = "response_test.py" }
6+
7+
override predicate isDedicatedFile(File file) { file.getShortName() = this }
8+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
semmle-extractor-options: --max-import-depth=1 -r testapp

python/ql/test/library-tests/frameworks/rest_framework/taint_test.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ def test_taint(request: Request, routed_param): # $ requestHandler routedParamet
8181
)
8282
ensure_not_tainted(request.user.password)
8383

84-
return Response("ok") # $ HttpResponse responseBody="ok"
84+
return Response("ok") # $ HttpResponse
8585

8686

8787
# class based view
@@ -105,7 +105,7 @@ def get(self, request: Request, routed_param): # $ requestHandler routedParamete
105105
# same as for standard Django view
106106
ensure_tainted(self.args, self.kwargs) # $ tainted
107107

108-
return Response("ok") # $ HttpResponse responseBody="ok"
108+
return Response("ok") # $ HttpResponse
109109

110110

111111

python/ql/test/library-tests/frameworks/rest_framework/testapp/urls.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,11 @@
99
router.register(r"bars", views.BarViewSet)
1010

1111
urlpatterns = [
12-
path("", include(router.urls)),
13-
path("api-auth/", include("rest_framework.urls", namespace="rest_framework")),
14-
path("class-based-view/", views.MyClass.as_view()), # $routeSetup="lcass-based-view/"
15-
path("function-based-view/", views.function_based_view), # $routeSetup="function-based-view/"
16-
path("cookie-test/", views.cookie_test), # $routeSetup="function-based-view/"
17-
path("exception-test/", views.exception_test), # $routeSetup="exception-test/"
12+
path("", include(router.urls)), # $ routeSetup=""
13+
path("api-auth/", include("rest_framework.urls", namespace="rest_framework")), # $ routeSetup="api-auth/"
14+
path("class-based-view/", views.MyClass.as_view()), # $ routeSetup="class-based-view/"
15+
path("function-based-view/", views.function_based_view), # $ routeSetup="function-based-view/"
16+
path("cookie-test/", views.cookie_test), # $ routeSetup="cookie-test/"
17+
path("exception-test/", views.exception_test), # $ routeSetup="exception-test/"
18+
path("viewset-entrypoints-test/", views.EntrypointViewSet.as_view()) # $ routeSetup="viewset-entrypoints-test/"
1819
]

python/ql/test/library-tests/frameworks/rest_framework/testapp/views.py

Lines changed: 34 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,41 +19,63 @@ class BarViewSet(viewsets.ModelViewSet):
1919
queryset = Bar.objects.all()
2020
serializer_class = BarSerializer
2121

22+
class EntrypointViewSet(viewsets.ModelViewSet):
23+
queryset = Bar.objects.all()
24+
serializer_class = BarSerializer
25+
26+
def create(self, request, *args, **kwargs): # $ requestHandler
27+
return Response("create") # $ HttpResponse
28+
29+
def retrieve(self, request, *args, **kwargs): # $ requestHandler
30+
return Response("retrieve") # $ HttpResponse
31+
32+
def update(self, request, *args, **kwargs): # $ requestHandler
33+
return Response("update") # $ HttpResponse
34+
35+
def partial_update(self, request, *args, **kwargs): # $ requestHandler
36+
return Response("partial_update") # $ HttpResponse
37+
38+
def destroy(self, request, *args, **kwargs): # $ requestHandler
39+
return Response("destroy") # $ HttpResponse
40+
41+
def list(self, request, *args, **kwargs): # $ requestHandler
42+
return Response("list") # $ HttpResponse
43+
2244
# class based view
2345
# see https://www.django-rest-framework.org/api-guide/views/#class-based-views
2446

2547
class MyClass(APIView):
26-
def initial(self, request, *args, **kwargs):
48+
def initial(self, request, *args, **kwargs): # $ requestHandler
2749
# this method will be called before processing any request
2850
super().initial(request, *args, **kwargs)
2951

30-
def get(self, request):
31-
return Response("GET request")
52+
def get(self, request): # $ requestHandler
53+
return Response("GET request") # $ HttpResponse
3254

33-
def post(self, request):
34-
return Response("POST request")
55+
def post(self, request): # $ requestHandler
56+
return Response("POST request") # $ HttpResponse
3557

3658

3759
# function based view
3860
# see https://www.django-rest-framework.org/api-guide/views/#function-based-views
3961

4062

4163
@api_view(["GET", "POST"])
42-
def function_based_view(request: Request):
43-
return Response({"message": "Hello, world!"})
64+
def function_based_view(request: Request): # $ requestHandler
65+
return Response({"message": "Hello, world!"}) # $ HttpResponse
4466

4567

4668
@api_view(["GET", "POST"])
47-
def cookie_test(request: Request):
48-
resp = Response("wat")
69+
def cookie_test(request: Request): # $ requestHandler
70+
resp = Response("wat") # $ HttpResponse
4971
resp.set_cookie("key", "value") # $ CookieWrite CookieName="key" CookieValue="value"
50-
resp.set_cookie(key="key4", value="value") # $ CookieWrite CookieName="key" CookieValue="value"
72+
resp.set_cookie(key="key4", value="value") # $ CookieWrite CookieName="key4" CookieValue="value"
5173
resp.headers["Set-Cookie"] = "key2=value2" # $ MISSING: CookieWrite CookieRawHeader="key2=value2"
5274
resp.cookies["key3"] = "value3" # $ CookieWrite CookieName="key3" CookieValue="value3"
5375
return resp
5476

5577
@api_view(["GET", "POST"])
56-
def exception_test(request: Request):
78+
def exception_test(request: Request): # $ requestHandler
5779
# see https://www.django-rest-framework.org/api-guide/exceptions/
5880
# note: `code details` not exposed by default
59-
raise APIException("exception details", "code details")
81+
raise APIException("exception details", "code details") # $ HttpResponse

0 commit comments

Comments
 (0)