|
| 1 | +Building a Polls API with Django |
| 2 | +============================= |
| 3 | + |
| 4 | +In this tutorial we will walk through a process of creating an API for a basic poll application. We will be using python 2.7, Django 1.8 and Django Rest Framework for creating API. |
| 5 | + |
| 6 | +First things first, lets install the required modules with virtual environment created and activated. |
| 7 | + |
| 8 | + mkvirtualenv pollsapi |
| 9 | + pip install Django |
| 10 | + pip install djangorestframework |
| 11 | + |
| 12 | +Creating a project |
| 13 | +-------------------- |
| 14 | + |
| 15 | +Earliest in order, to create a project we should move to the directory where we would like to store our code. For this go to command line and use cd command. Then trigger the start prject command. |
| 16 | + |
| 17 | + django-admin startproject django_pollsapi |
| 18 | + |
| 19 | +The above mentioned command results us a 'django_pollsapi' directoy. |
| 20 | + |
| 21 | +Database setup |
| 22 | +------------------ |
| 23 | + |
| 24 | +For ease of use we shall choose SQlite database which is already included in python. The "django_pollsapi/settings.py" file should reflect the following Database settings |
| 25 | + |
| 26 | + DATABASES = { |
| 27 | + 'default': { |
| 28 | + 'ENGINE': 'django.db.backends.sqlite3', |
| 29 | + 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), |
| 30 | + } |
| 31 | +} |
| 32 | + |
| 33 | +Now, use the migrate command which builds the needed database tables in regard to the "django_pollsapi/settings.py" file. |
| 34 | + |
| 35 | + python manage.py migrate |
| 36 | + |
| 37 | + |
| 38 | +Creating models |
| 39 | +--------------------- |
| 40 | + |
| 41 | +Before creating our database models, let us create our pollsapi App. |
| 42 | + |
| 43 | + python manage.py startapp pollsapi |
| 44 | + |
| 45 | +The above command resluts a 'pollsapi' directory containing different files, i.e 'admin.py', 'models.py', 'tests.py', 'views.py'. |
| 46 | +Step in to 'models.py' file and start writing the models. For creating the polls api we are going to create a Poll model, a Choice model and a Vote model. Once we are done with designing our models, the 'models.py' file should look like this: |
| 47 | + |
| 48 | + from django.db import models |
| 49 | + from django.contrib.auth.models import User |
| 50 | + |
| 51 | + |
| 52 | + class Poll(models.Model): |
| 53 | + question = models.CharField(max_length=100) |
| 54 | + created_by = models.ForeignKey(User) |
| 55 | + pub_date = models.DateTimeField(auto_now=True) |
| 56 | + |
| 57 | + def __unicode__(self): |
| 58 | + return self.question |
| 59 | + |
| 60 | + |
| 61 | + class Choice(models.Model): |
| 62 | + poll = models.ForeignKey(Poll, related_name='choices') |
| 63 | + choice_text = models.CharField(max_length=100) |
| 64 | + |
| 65 | + def __unicode__(self): |
| 66 | + return self.choice_text |
| 67 | + |
| 68 | + |
| 69 | + class Vote(models.Model): |
| 70 | + choice = models.ForeignKey(Choice, related_name='votes') |
| 71 | + poll = models.ForeignKey(Poll) |
| 72 | + voted_by = models.ForeignKey(User) |
| 73 | + |
| 74 | + class Meta: |
| 75 | + unique_together = ("poll", "voted_by") |
| 76 | + |
| 77 | +The above models have been designed in such a way that, it would make our API bulding a smooth process. |
| 78 | + |
| 79 | +Activating models |
| 80 | +---------------------- |
| 81 | + |
| 82 | +With the simple lines of code in the 'models.py' Django can create a database schema and a Python database-access API which has the capablity to access the objects of Poll, Choice, Vote. To create the database tables to our models, 'rest_framework' and 'pollsapi' app needs to be added to the "INSTALLED_APPS" in the 'django_pollsapi/settings' file. |
| 83 | + |
| 84 | + INSTALLED_APPS = ( |
| 85 | + ... |
| 86 | + 'rest_framework', |
| 87 | + 'pollsapi', |
| 88 | + ) |
| 89 | + |
| 90 | + |
| 91 | +Now, run the makemigrations command which will notify Django that new models have been created and those changes needs to be applied to the migration. |
| 92 | + |
| 93 | + python manage.py makemigrations pollsapi |
| 94 | + |
| 95 | +Go to URls in the root folder i.e django_pollsapi and include the app urls. |
| 96 | + |
| 97 | + urlpatterns = [ |
| 98 | + url(r'^', include('pollsapi.urls')), |
| 99 | + ] |
| 100 | + |
| 101 | + |
| 102 | +Part 2: |
| 103 | +======== |
| 104 | + |
| 105 | +Django-rest-framework makes the process of building web API's simple and flexible. With its batteries included it won't be a tedious task to create an API. |
| 106 | + |
| 107 | + |
| 108 | +Serialization and Deserialization |
| 109 | +-------------------------------------- |
| 110 | + |
| 111 | +The first part in the process of building an API is to provide a way to serialize and deserialize the instances into representations. Serialization is the process of making a streamable representation of the data which will help in the data transfer over the network. Deserialization is its reverse process. In our project of building an API we render data into JSON format. To achieve this, Django-rest-framework provides 'JSONRenderer' and 'JSONParser'. 'JSONRenderer' renders the request data into 'json' using utf-8 encoding and JSONParser parses the JSON request content. |
| 112 | + |
| 113 | + |
| 114 | +Creating Serializers |
| 115 | +----------------------- |
| 116 | + |
| 117 | +Lets get started with creating serializer class which will serialize and deserialize the pollsapi instances in to different representations. Create a file named "pollsapi/serializers.py". Let us make use of model serializers which will decrease replication of code by automatically determing the set of fields and by creating simple default implementations of the create() and update() methods. |
| 118 | + |
| 119 | + |
| 120 | + from rest_framework import serializers |
| 121 | + |
| 122 | + from django.contrib.auth.models import User |
| 123 | + |
| 124 | + from .models import Poll, Choice, Vote |
| 125 | + |
| 126 | + |
| 127 | + |
| 128 | + class ChoiceSerializer(serializers.ModelSerializer): |
| 129 | + votes = VoteSerializer(many=True, required=False) |
| 130 | + |
| 131 | + class Meta: |
| 132 | + model = Choice |
| 133 | + |
| 134 | + |
| 135 | + class PollSerializer(serializers.ModelSerializer): |
| 136 | + choices = ChoiceSerializer(many=True, read_only=True, required=False) |
| 137 | + |
| 138 | + class Meta: |
| 139 | + model = Poll |
| 140 | + |
| 141 | + |
| 142 | + class VoteSerializer(serializers.ModelSerializer): |
| 143 | + class Meta: |
| 144 | + model = Vote |
| 145 | + |
| 146 | + |
| 147 | + class UserSerializer(serializers.ModelSerializer): |
| 148 | + |
| 149 | + class Meta: |
| 150 | + model = User |
| 151 | + fields = ('username', 'email', 'password') |
| 152 | + |
| 153 | + |
| 154 | +In the above lines of code we created a Choice Serializer in such a way that whenever we create a choice it does need to have the votes model connected to it and if a poll is created the choices needs to be created simultaneously. We will be needing a user for dealing with the polls and voting for that we used the Django's User. |
| 155 | + |
| 156 | +Creating Views |
| 157 | +---------------- |
| 158 | + |
| 159 | +Let us use generic views of Django Rest Framework for creating our views which will help us in code reusablity. The generic views alos aid us in building the API quickly and in mapping the database models. |
| 160 | + |
| 161 | + |
| 162 | + from rest_framework import generics |
| 163 | + |
| 164 | + from .models import Poll, Choice |
| 165 | + from .serializers import PollSerializer, ChoiceSerializer,\ |
| 166 | + VoteSerializer |
| 167 | + |
| 168 | + |
| 169 | + class PollList(generics.ListCreateAPIView): |
| 170 | + |
| 171 | + """ |
| 172 | + List all polls, or create a new poll. |
| 173 | + """ |
| 174 | + |
| 175 | + queryset = Poll.objects.all() |
| 176 | + serializer_class = PollSerializer |
| 177 | + |
| 178 | + |
| 179 | + class PollDetail(generics.RetrieveDestroyAPIView): |
| 180 | + """ |
| 181 | + Create a Poll, delete a poll |
| 182 | + """ |
| 183 | + |
| 184 | + queryset = Poll.objects.all() |
| 185 | + serializer_class = PollSerializer |
| 186 | + |
| 187 | + |
| 188 | + class ChoiceDetail(generics.RetrieveUpdateAPIView): |
| 189 | + """ |
| 190 | + Retrieves a Choice, Updates a Choice |
| 191 | + """ |
| 192 | + |
| 193 | + queryset = Choice.objects.all() |
| 194 | + serializer_class = ChoiceSerializer |
| 195 | + |
| 196 | + |
| 197 | + class CreateVote(generics.CreateAPIView): |
| 198 | + """ |
| 199 | + Create a vote |
| 200 | + """ |
| 201 | + |
| 202 | + serializer_class = VoteSerializer |
| 203 | + |
| 204 | + class UserCreate(generics.CreateAPIView): |
| 205 | + """ |
| 206 | + Create an User |
| 207 | + """ |
| 208 | + |
| 209 | + serializer_class = UserSerializer |
| 210 | + |
| 211 | + |
| 212 | + class UserDetail(generics.RetrieveAPIView): |
| 213 | + """ |
| 214 | + Retrieve a User |
| 215 | + """ |
| 216 | + |
| 217 | + queryset = User.objects.all() |
| 218 | + serializer_class = UserSerializer |
| 219 | + |
| 220 | + |
| 221 | +When writting a generic view we will override the view and set several calss attributes. |
| 222 | + |
| 223 | +Let us have a look in to the important parts in the code. |
| 224 | + |
| 225 | +1. queryset: This will be used to return objects from the view. |
| 226 | +2. serializer_class: This will be used for validating and deserializing the input and for seraizling the output. |
| 227 | + |
| 228 | + |
| 229 | +Part 3: |
| 230 | +=========== |
| 231 | + |
| 232 | +Creating URLs |
| 233 | +-------------- |
| 234 | + |
| 235 | +It's time to wire up the views to specific URLs |
| 236 | + |
| 237 | + |
| 238 | + from django.conf.urls import include, url |
| 239 | + from django.contrib import admin |
| 240 | + |
| 241 | + import pollsapi.views |
| 242 | + |
| 243 | + urlpatterns = [ |
| 244 | + |
| 245 | + url(r'^admin/', include(admin.site.urls)), |
| 246 | + url(r'^polls/$', pollsapi.views.PollList.as_view()), |
| 247 | + url(r'polls/(?P<pk>[0-9]+)/$', pollsapi.views.PollDetail.as_view()), |
| 248 | + url(r'^create_user/$', pollsapi.views.UserCreate.as_view()), |
| 249 | + url(r'^choices/(?P<pk>[0-9]+)/$', pollsapi.views.ChoiceDetail.as_view()), |
| 250 | + url(r'^create_vote/$', pollsapi.views.CreateVote.as_view()), |
| 251 | + url(r'^users/(?P<pk>[0-9]+)/$', pollsapi.views.UserDetail.as_view()), |
| 252 | + |
| 253 | + ] |
| 254 | + |
| 255 | +In the above lines of code we have created URLs for all the views according to our requirement. |
| 256 | + |
0 commit comments