From 34a43b6d5087bc8f5fcde168dec0d68e29098edb Mon Sep 17 00:00:00 2001 From: Faris Chebib Date: Sat, 2 Sep 2017 19:52:36 -0600 Subject: [PATCH] Added nested writable relationship Custom serializer ref --- README.md | 13 +++++++++ apps/django_music/settings.py | 9 +++++-- apps/django_music/urls.py | 6 +++++ apps/web_endpoints/__init__.py | 0 apps/web_endpoints/admin.py | 3 +++ apps/web_endpoints/apps.py | 5 ++++ apps/web_endpoints/migrations/__init__.py | 0 apps/web_endpoints/models.py | 3 +++ apps/web_endpoints/serializers.py | 33 +++++++++++++++++++++++ apps/web_endpoints/tests.py | 3 +++ apps/web_endpoints/urls.py | 11 ++++++++ apps/web_endpoints/views.py | 15 +++++++++++ requirements.txt | 2 ++ 13 files changed, 101 insertions(+), 2 deletions(-) create mode 100644 apps/web_endpoints/__init__.py create mode 100644 apps/web_endpoints/admin.py create mode 100644 apps/web_endpoints/apps.py create mode 100644 apps/web_endpoints/migrations/__init__.py create mode 100644 apps/web_endpoints/models.py create mode 100644 apps/web_endpoints/serializers.py create mode 100644 apps/web_endpoints/tests.py create mode 100644 apps/web_endpoints/urls.py create mode 100644 apps/web_endpoints/views.py diff --git a/README.md b/README.md index 5114d51..2a16ebb 100644 --- a/README.md +++ b/README.md @@ -81,3 +81,16 @@ Now we're going to play with Django's ORM and admin: One of the main selling-poi 6. And we also add an `admin.py` file for easy management of the DB. 7. We can visit `localhost:8000/admin` and `localhost:8000/db/songs`; etc for more views. 8. Because our urls are named, we can use the `{% url %}` django template tag to directly link to a model's page (or the list page). + +## 4. `web_endpoint` + +Instead of creating new models, we'll use the old ones from `web_db` to create *Endpoints*. + +Endpoints are simply api endpoints which can be used by javascript or mobile to make changes to the DB. + +1. Spin up `web_endpoints` via `./manage.py startapp web_endpoints` and `mv` it to `apps` +2. Add `web_endpoints` to our `INSTALLED_APPS` list +3. Ensure that `[rest_framework](http://www.django-rest-framework.org)` has been added to `INSTALLED_APPS` +3. Create serializers for our Album and Song models in `web_endpoints/serializers.py`. +4. We then use ViewSets and Routers to link everything else up. +5. We will also write a custom creation method for the nested serializer. diff --git a/apps/django_music/settings.py b/apps/django_music/settings.py index c975701..244fac2 100644 --- a/apps/django_music/settings.py +++ b/apps/django_music/settings.py @@ -38,13 +38,18 @@ 'django.contrib.staticfiles', ] +THIRD_PARTY_APPS = [ + 'rest_framework' +] + OUR_APPS = [ 'web_pages', 'web_app', - 'web_db' + 'web_db', + 'web_endpoints' ] -INSTALLED_APPS = DJANGO_APPS + OUR_APPS +INSTALLED_APPS = DJANGO_APPS + THIRD_PARTY_APPS + OUR_APPS MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', diff --git a/apps/django_music/urls.py b/apps/django_music/urls.py index 9054f8e..f3901c6 100644 --- a/apps/django_music/urls.py +++ b/apps/django_music/urls.py @@ -19,6 +19,10 @@ from web_pages.views import basic_web_page from web_app.views import basic_web_app, dynamic_web_app +apipatterns = [ + url(r'^v1/', include('web_endpoints.urls', namespace='v1')), +] + urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^pages/$', basic_web_page), # the web_pages app. We call the view's callable function @@ -27,4 +31,6 @@ url(r'^app/song/$', dynamic_web_app), # the web_db app. In this case, we'll include instead of specifying each view url(r'^db/', include('web_db.urls', namespace='db')), + # And finally, our endpoints + url(r'^api/', include(apipatterns, namespace='api')), ] diff --git a/apps/web_endpoints/__init__.py b/apps/web_endpoints/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/apps/web_endpoints/admin.py b/apps/web_endpoints/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/apps/web_endpoints/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/apps/web_endpoints/apps.py b/apps/web_endpoints/apps.py new file mode 100644 index 0000000..deb0c3d --- /dev/null +++ b/apps/web_endpoints/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class WebEndpointsConfig(AppConfig): + name = 'web_endpoints' diff --git a/apps/web_endpoints/migrations/__init__.py b/apps/web_endpoints/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/apps/web_endpoints/models.py b/apps/web_endpoints/models.py new file mode 100644 index 0000000..71a8362 --- /dev/null +++ b/apps/web_endpoints/models.py @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. diff --git a/apps/web_endpoints/serializers.py b/apps/web_endpoints/serializers.py new file mode 100644 index 0000000..a9e614e --- /dev/null +++ b/apps/web_endpoints/serializers.py @@ -0,0 +1,33 @@ +from rest_framework import serializers + +from web_db.models import Album, Song + + +class BasicSongSerializer(serializers.ModelSerializer): + + class Meta: + model = Song + fields = ('title', 'track', 'duration',) + + +class AlbumSerializer(serializers.ModelSerializer): + songs = BasicSongSerializer(many=True, source='song_set') + + class Meta: + model = Album + fields = ('title', 'artist', 'year', 'songs') + + def create(self, data): + songs = data.pop('song_set') + album = Album.objects.create(**data) + for song in songs: + Song.objects.create(album=album, **song) + return album + + +class SongSerializer(serializers.ModelSerializer): + album = AlbumSerializer() + + class Meta: + model = Song + fields = ('title', 'track', 'duration', 'album',) diff --git a/apps/web_endpoints/tests.py b/apps/web_endpoints/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/apps/web_endpoints/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/apps/web_endpoints/urls.py b/apps/web_endpoints/urls.py new file mode 100644 index 0000000..07cea05 --- /dev/null +++ b/apps/web_endpoints/urls.py @@ -0,0 +1,11 @@ +from django.conf.urls import url, include +from web_endpoints.views import AlbumViewSet, SongViewSet +from rest_framework.routers import DefaultRouter + +router = DefaultRouter() +router.register(r'albums', AlbumViewSet) +router.register(r'songs', SongViewSet) + +urlpatterns = [ + url(r'', include(router.urls)), +] diff --git a/apps/web_endpoints/views.py b/apps/web_endpoints/views.py new file mode 100644 index 0000000..aad0e78 --- /dev/null +++ b/apps/web_endpoints/views.py @@ -0,0 +1,15 @@ +from rest_framework import viewsets + +from web_db.models import Album, Song + +from web_endpoints.serializers import AlbumSerializer, SongSerializer + + +class AlbumViewSet(viewsets.ModelViewSet): + queryset = Album.objects.all() + serializer_class = AlbumSerializer + + +class SongViewSet(viewsets.ModelViewSet): + queryset = Song.objects.all() + serializer_class = SongSerializer diff --git a/requirements.txt b/requirements.txt index 9788972..277ed0e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,4 @@ Django==1.11.4 ipython==6.1.0 +djangorestframework==3.6.4 +ipdb==0.10.3