Share
Embed
Transcript
48 slides
-
DRF Content negotiation / Parser Router Authentication / Permissions /
Throttling Deserialization Processing / Pagination / Filtering Serialization Renderer Middleware -
Parsers / Renderers b'{"demo": 1}’ <class bytes> b'"2015-06-03"' <class bytes>
{"demo": 1} <class dict> "2015-06-03" <class str> JSONParser Binary world Python land JSONRenderer -
Identification Permissions Throttling • Identification: Qui êtes-vous ? • Permissions:
Pouvez-vous le faire ? • Throttling: Abusez-vous des ressources ? -
(dé)sérialisation • Types de base Python <-> objets complexes •
Etape de représentation • "2015-06-03" <-> datetime.date(2015, 6, 3) • Validation des entrées: • Vérification de typage • Sécurisation (injections diverses) -
Serializers {"demo": 1} <class dict> "2015-06-03" <class str> <SomeObj> <class
SomeObj> 2015-06-03 <class date> Serializer Unsafe Safe -
settings.py INSTALLED_APPS = [ … 'rest_framework', 'teaching', 'corsheaders', ] …
MIDDLEWARE = [ … 'corsheaders.middleware.CorsMiddleware', ] … CORS_ORIGIN_ALLOW_ALL = True -
teaching/serializers.py from rest_framework import serializers from . import models class
CourseMaterialSerializer(serializers.ModelSerializer): class Meta: model = models.CourseMaterial fields = ['title', 'description', 'url', 'author'] -
teaching/api_views.py from rest_framework import viewsets from . import serializers, models
class CourseMaterialViewSet(viewsets.ModelViewSet): queryset = models.CourseMaterial.objects.all() serializer_class = serializers.CourseMaterialSerializer -
teaching/urls.py from rest_framework import routers from . import views, api_views
router = routers.DefaultRouter() router.register( r'course_material', api_views.CourseMaterialViewSet, ) urlpatterns = [ … ] + router.urls -
Navigation • Page de garde: ➡ http://localhost:8000/teaching/ • Liste /
creation: ➡ http://localhost:8000/teaching/course_material/ • Voir / mettre à jour / supprimer: ➡ http://localhost:8000/teaching/course_material/1/ • En JSon: ➡ …/teaching/course_material/?format=json ➡ …/teaching/course_material.json -
Création http --json POST http://127.0.0.1:8000/teaching/course_material/\ author=1 description="blabla" title="bla" HTTP/1.1 201
Created Allow: GET, POST, HEAD, OPTIONS Content-Length: 60 Content-Type: application/json Date: Fri, 05 Oct 2018 23:05:39 GMT Location: None Server: WSGIServer/0.2 CPython/3.6.6 Vary: Accept, Cookie X-Frame-Options: SAMEORIGIN { "author": 1, "description": "blabla", "title": "bla", "url": null } -
teaching/tests.py class TestTask(APITestCase): def test_task_creation(self): author = models.Author.objects.create( name="hodor", email="[email protected]",
) course_material = models.CourseMaterial.objects.create( title="Hodoooor", author=author, ) data = { 'title': "Hodoooor", 'description': None, 'author': 1, 'url': None, } url = reverse('teaching:coursematerial-list') response = self.client.post(url, data, format='json') self.assertEqual( response.status_code, status.HTTP_201_CREATED, response.content) self.assertEqual(response.data, data) -
teaching/tests.py class TestTask(APITestCase): def test_task_creation(self): author = models.Author.objects.create( name="hodor", email="[email protected]",
) course_material = models.CourseMaterial.objects.create( title="Hodoooor", author=author, ) data = { 'title': "Hodoooor", 'description': None, 'author': 1, 'url': None, } url = reverse('teaching:coursematerial-list') response = self.client.post(url, data, format='json') self.assertEqual( response.status_code, status.HTTP_201_CREATED, response.content) self.assertEqual(response.data, data) -
teaching/tests.py class TestTask(APITestCase): def test_task_creation(self): author = models.Author.objects.create( name="hodor", email="[email protected]",
) course_material = models.CourseMaterial.objects.create( title="Hodoooor", author=author, ) data = { 'title': "Hodoooor", 'description': None, 'author': 1, 'url': None, } url = reverse('teaching:coursematerial-list') response = self.client.post(url, data, format='json') self.assertEqual( response.status_code, status.HTTP_201_CREATED, response.content) self.assertEqual(response.data, data) -
teaching/tests.py class TestTask(APITestCase): def test_task_creation(self): author = models.Author.objects.create( name="hodor", email="[email protected]",
) course_material = models.CourseMaterial.objects.create( title="Hodoooor", author=author, ) data = { 'title': "Hodoooor", 'description': None, 'author': 1, 'url': None, } url = reverse('teaching:coursematerial-list') response = self.client.post(url, data, format='json') self.assertEqual( response.status_code, status.HTTP_201_CREATED, response.content) self.assertEqual(response.data, data) -
teaching/tests.py class TestTask(APITestCase): def test_task_creation(self): author = models.Author.objects.create( name="hodor", email="[email protected]",
) course_material = models.CourseMaterial.objects.create( title="Hodoooor", author=author, ) data = { 'title': "Hodoooor", 'description': None, 'author': 1, 'url': None, } url = reverse('teaching:coursematerial-list') response = self.client.post(url, data, format='json') self.assertEqual( response.status_code, status.HTTP_201_CREATED, response.content) self.assertEqual(response.data, data) -
teaching/tests.py class TestTask(APITestCase): def test_task_creation(self): author = models.Author.objects.create( name="hodor", email="[email protected]",
) course_material = models.CourseMaterial.objects.create( title="Hodoooor", author=author, ) data = { 'title': "Hodoooor", 'description': None, 'author': 1, 'url': None, } url = reverse('teaching:coursematerial-list') response = self.client.post(url, data, format='json') self.assertEqual( response.status_code, status.HTTP_201_CREATED, response.content) self.assertEqual(response.data, data) -
Lancer le test (tp-atelier-django)[monprojet]$ python manage.py test Creating test database
for alias 'default'... System check identified no issues (0 silenced). . ---------------------------------------------------------------- Ran 1 test in 0.015s OK Destroying test database for alias 'default'... (tp-atelier-django)[monprojet]$ -
teaching/tests.py from django.urls import reverse from rest_framework import status from
rest_framework.test import APITestCase from . import models -
teaching/tests.py class TestTask(APITestCase): def test_task_creation(self): data = { 'title': "Hodoooor",
'description': None, 'author': 1, 'url': None, } author = models.Author.objects.create( name="hodor", email="[email protected]", ) course_material = models.CourseMaterial.objects.create( title="Hodoooor", author=author, ) url = reverse('teaching:coursematerial-list') response = self.client.post(url, data, format='json') self.assertEqual( response.status_code, status.HTTP_201_CREATED, response.content) self.assertEqual(response.data, data) -
Lancer le test (tp-atelier-django)[monprojet]$ python manage.py test Creating test database
for alias 'default'... System check identified no issues (0 silenced). . ---------------------------------------------------------------- Ran 1 test in 0.015s OK Destroying test database for alias 'default'... (tp-atelier-django)[monprojet]$ -
Author illisible http --json POST http://127.0.0.1:8000/teaching/course_material/\ author=1 description="blabla" title="bla" HTTP/1.1
201 Created Allow: GET, POST, HEAD, OPTIONS Content-Length: 60 Content-Type: application/json Date: Fri, 05 Oct 2018 23:05:39 GMT Location: None Server: WSGIServer/0.2 CPython/3.6.6 Vary: Accept, Cookie X-Frame-Options: SAMEORIGIN { "author": 1, "description": "blabla", "title": "bla", "url": null } -
teaching/serializers.py class CourseMaterialSerializer(serializers.ModelSerializer): author = serializers.SlugRelatedField( slug_field='name', queryset=models.Author.objects.all(), ) class
Meta: model = models.CourseMaterial fields = ['title', 'description', 'url', 'author'] -
Author amélioré http --json POST http://127.0.0.1:8000/teaching/course_material/\ author=1 description="blabla" title="bla" HTTP/1.1
201 Created Allow: GET, POST, HEAD, OPTIONS Content-Length: 60 Content-Type: application/json Date: Fri, 05 Oct 2018 23:05:39 GMT Location: None Server: WSGIServer/0.2 CPython/3.6.6 Vary: Accept, Cookie X-Frame-Options: SAMEORIGIN { "author": "A. Christie", "description": "blabla", "title": "bla", "url": null } -
Tests (tp-atelier-django)[monprojet]$ python manage.py test Creating test database for alias
'default'... System check identified no issues (0 silenced). F ================================================================= FAIL: test_task_creation (teaching.tests.TestTask) ----------------------------------------------------------------- Traceback (most recent call last): File "/Users/xordoquy/Documents/Devs/tp-atelier-django/monprojet/ teaching/tests.py", line 26, in test_task_creation response.content) AssertionError: 400 != 201 : b'{"author":["L\'object avec name=1 n\'existe pas."]}' ----------------------------------------------------------------- Ran 1 test in 0.016s FAILED (failures=1) Destroying test database for alias 'default'... (tp-atelier-django)[monprojet]$ -
teaching/tests.py class TestTask(APITestCase): def test_task_creation(self): author = models.Author.objects.create( name="hodor", email="[email protected]",
) course_material = models.CourseMaterial.objects.create( title="Hodoooor", author=author, ) data = { 'title': course_material.title, 'description': None, 'author': author.name, 'url': None, } url = reverse('teaching:coursematerial-list') response = self.client.post(url, data, format='json') self.assertEqual( response.status_code, status.HTTP_201_CREATED, response.content) self.assertEqual(response.data, data) -
teaching/serializers.py from rest_framework import serializers from . import models class
CourseMaterialSerializer(serializers.ModelSerializer): self_url = serializers.HyperlinkedIdentityField( 'coursematerial-detail', source='id', read_only=True) class Meta: model = models.CourseMaterial fields = [ 'title', 'description', 'url', 'author', 'self_url', ] -
Exemple { "author": { "email": "[email protected]", "id": 3, "name": "aha"
}, "description": "Description", "title": "titre !", "url": null } -
serializers.py class AuthorSerializer(serializers.ModelSerializer): id = serializers.IntegerField(required=False) class Meta: model =
models.Author fields = ['id', 'name', 'email'] class CourseMaterialSerializer(serializers.ModelSerializer): author = AuthorSerializer(read_only=True) class Meta: model = models.CourseMaterial fields = ['title', 'description', 'url', 'author'] -
Résultat http --json http://127.0.0.1:8000/teaching/course_material/1/ -s colorful HTTP/1.1 200 OK …
{ "author": { "email": "[email protected]", "id": 1, "name": "A. Christie" }, "description": "Le crime de l'Orient-Express", "title": "Résoudre un mystère", "url": null } -
serializers.py class AuthorSerializer(serializers.ModelSerializer): id = serializers.IntegerField(required=False) class Meta: model =
models.Author fields = ['id', 'name', ‘email'] class CourseMaterialSerializer(serializers.ModelSerializer): author = AuthorSerializer(read_only=True) class Meta: model = models.CourseMaterial fields = ['title', 'description', 'url', 'author'] -
serializers.py class CourseMaterialSerializer(serializers.ModelSerializer): … def create(self, validated_data): author = self.create_or_update_author(
validated_data.pop('author') ) course_material = models.CourseMaterial.objects.create( author=author, **validated_data, ) return course_material -
serializers.py class CourseMaterialSerializer(serializers.ModelSerializer): … def update(self, instance, validated_data): author =
self.create_or_update_author( validated_data.pop('author') ) instance.title = validated_data['title'] instance.description = validated_data['description'] instance.email = validated_data['email'] instance.author = author instance.save() return instance -
serializers.py class CourseMaterialSerializer(serializers.ModelSerializer): … def create_or_update_author(self, author_data): try: author =
models.Author.objects.get( id=author_data.get('id'), ) author.name = author_data['name'] author.email = author_data['email'] except models.Author.DoesNotExist: author = models.Author(**author_data) author.save() return author -
Résultat: http --json POST http://127.0.0.1:8000/teaching/course_material/\ author:='{"email": "[email protected]", "name": "aha"}' \
description="blabla2" title="bla2" HTTP/1.1 201 Created … { "author": { "email": "[email protected]", "id": 3, "name": "aha" }, "description": "blabla2", "title": "bla2", "url": null } -
teaching/api_views.py from rest_framework import viewsets from rest_framework.decorators import action from
rest_framework.response import Response from . import serializers, models class CourseMaterialViewSet(viewsets.ModelViewSet): queryset = models.CourseMaterial.objects.all() serializer_class = serializers.CourseMaterialSerializer @action(methods=['get'], detail=False) def authors(self, request, *args, **kwargs): authors = models.Author.objects.all() serializer = serializers.AuthorSerializer( instance=authors, many=True, ) return Response(serializer.data) -
Résultat http --json http://127.0.0.1:8000/teaching/course_material/authors/ HTTP/1.1 200 OK Allow: GET, HEAD,
OPTIONS Content-Length: 139 Content-Type: application/json Date: Sat, 06 Oct 2018 00:47:21 GMT Server: WSGIServer/0.2 CPython/3.6.6 Vary: Accept, Cookie X-Frame-Options: SAMEORIGIN [ { "email": "[email protected]", "id": 1, "name": "A. Christie" } ]