Django Rest API
Django Rest API
1) API
2) Web API/Web Service
3) REST
4) REST API
5) DJango Rest Framework
API:
API Application Programming Interface
The main objective of API is two applications can communicate with each other. API
allows external agent to communicate (integrate and exchange information) with our
application.
Eg1: By using API a java application can communicate with python application.
Bookmyshow application can communicate with Payment gateway application to
complete our booking.
Note: Interface of communication between the user and application is nothing but API.
The user can be Human user, an android app or desktop application etc
By using REST, we can develop web APIs very easily in concise way.
Hence REST is the most popular Architecture to develop Web Services.
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
1 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
RESTFul API:
The API which is developed by using REST Architecture is nothing but RESTFul API. i.e
interface between the user and application where API implements REST Architecture.
Note: REST is basically an architecture where as RESTFul API is an API that implements
REST.
.Net Java
By using Web Services, Any application in the world can communicates with any other
application irrespective of language (like Java, Python, .Net etc) and platform (like
windows,Linux,MAC etc).
The applications can communicate by using HTTP Protocol as the common language.
The Message Format is XML or JSON.
REST: It is an architecture, which provides several guidelines to develop web APIs very
easily and effectively.
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
2 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
RESTful API: The Web API which implements REST principles is called RESTful API.
Note: The most common data representation in web API is Java Script Object Notation
(JSON). It is a collection of key-value pairs just like python dictionaries.
{'eno':100,'ename':'durga','esal':1000,'eaddr':'hyd'}
The main advantage of JSON over XML is, it is Machine Friendly and Human Friendly Form.
HTTP Verbs:
HTTP Verbs represent the type of operation what we required.
Based on requirement we have to use the corresponding HTTP verb.
Note: These are only important HTTP Verbs. The following are not that much important
verbs.
OPTIONS
HEAD
CONNECT
TRACE
LOCK
MOVE
PROFIND
etc
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
3 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
HTTP Verbs vs Database CRUD Operations:
C (CREATE) POST
R (RETRIEVE/READ) GET
U (UPDATE) PUT/PATCH
D (DELETE) DELETE
2) django:
File Settings Install In the searchbox just type djanngo atom-django
Limitations:
1) SOAP Based web services will always provide data only in XML format. Parsing of this
XML data is very slow, which creates performance problems.
2) Transfter of XML data over network requires more bandwidth.
3) Implementing SOAP Based Web Services is very difficult.
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
4 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
Note: Because of heavy weight, less performance and more bandwidth requirements,
SOAP based web services are not commonly used these days.
Limitations:
1) It is less secured.
2) It provide support only for the protocols which can provide URI, mostly HTTP.
Note: Because of ligth weight, high performance, less bandwidth requirements, easy
development, human understandable message format, this type of web services are most
commonly used type of web services.
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
5 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
Web Service Provider vs WebService Consumer:
The application which is providing web services is called Web Service Provider.
The application which is consuming web data through web services, is called Web
service consumer.
def employee_data_jsonview(request):
employee_data={'eno':100,'ename':'Sunny Leone','esal':1000,'eaddr':'Hyderabad'}
json_data=json.dumps(employee_data)
return HttpResponse(json_data,content_type='application/json')
Note: This way of sending JSON response is very old. Newer versions of Django dprovided
a special class JsonResponse.
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
6 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
test.py:
1) import requests
2) BASE_URL='http://127.0.0.1:8000/'
3) ENDPOINT='api'
4) r=requests.get(BASE_URL+ENDPOINT)
5) data=r.json()
6) print('Employee Number:',data['eno'])
7) print('Employee Name:',data['ename'])
8) print('Employee Salary:',data['esal'])
9) print('Employee Address:',data['eaddr'])
Note: In the above case, python application communicates with django application to get
employee data. For this common language used is: Http and common message format
used is JSON.
HTTPie Module:
We can use this module to send http request from commond prompt.
We can install as follows
1) C:\Users\LENOVO>http http://127.0.0.1:8000
2) HTTP/1.0 200 OK
3) Content-Length: 72
4) Content-Type: application/json
5) Date: Thu, 13 Dec 2018 10:17:54 GMT
6) Server: WSGIServer/0.2 CPython/3.6.5
7) X-Frame-Options: SAMEORIGIN
8)
9) {
10) "eaddr": "Hyderabad",
11) "ename": "Sunny Leone",
12) "eno": 100,
13) "esal": 1000
14) }
django.views.generic
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
7 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
Within the class we have to provide http methods like get(),post() etc
Whenever we are sending the request, the corresponding method will be executed.
urls.py
url(r'^cbv1/', views.JsonCBV.as_view()),
*args vs **kwargs:
*args Variable Length Arguments
f1(*args) We can call this function by passing any number of arguments.
Internally this variable-length argument will be converted into tuple.
1) def sum(*args):
2) total=0
3) for x in args:
4) total=total+x
5) print('The Sum:',total)
6)
7) sum()
8) sum(10)
9) sum(10,20)
10) sum(10,20,30,40)
Output:
The Sum: 0
The Sum: 10
The Sum: 30
The Sum: 100
1) def f1(**x):
2) print(x)
3)
4) f1(name='durga',rollno=101,marks=80,gf1='sunny')
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
8 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
Mixin(Mixed In):
Mixins are special type of inheritance in Python.
It is limited version of Multiple inheritance.
In multiple inheritance, we can create object for parent class and parent class can
extend other classes. But in Mixins, for the parent class we cannot create object and it
should be direct child class of object.i.e parent class cannot extend any other classes.
In Multiple inheritance, parent class can contain instance variables.But in Mixins,
parent class cannot contain instance variable but can contain class level static
variables.
Hence the main purpose of parent class in Mixins is to provide functions to the child
classes.
Note:
1) Mixins are reusable classes in django.
2) Mixins are available only in languages which provide support for multiple inheritance
like Python,Ruby,Scala etc
3) Mixins are not applicable for Java and C#, because these languages won't support
multiple inheritance.
mixins.py:
CBV:
models.py
admin.py
views.py
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
10 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
16) json_data=json.dumps(data)
17) return HttpResponse(json_data,content_type='application/json')
1) def get(self,request,id,*args,**kwargs):
2) emp=Employee.objects.get(id=id)
3) ....
urls.py
url(r'^api/(?P<id>\d+)/$', views.EmployeeCRUDCBV.as_view()),
test.py
1) import requests
2) BASE_URL='http://127.0.0.1:8000/'
3) ENDPOINT='api/'
4) n=input('Enter required id:')
5) r=requests.get(BASE_URL+ENDPOINT+n+'/')
6) data=r.json()
7) print(data)
Serialization:
The process of converting object from one form to another form is called serialization.
1) def get(self,request,id,*args,**kwargs):
2) emp=Employee.objects.get(id=id)
3) json_data=serialize('json',[emp,],fields=('eno','ename'))
4) return HttpResponse(json_data,content_type='application/json')
If we are not specifying fields attribute, then all fields will be included in json data. For
security reasons, if we don't want to provide access to some fields then this fields
attribute is very helpful.
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
11 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
To get all Records:
1) class EmployeeListCBV(View):
2) def get(self,request,*args,**kwargs):
3) qs=Employee.objects.all()
4) json_data=serialize('json',qs)
5) return HttpResponse(json_data,content_type='application/json')
urls.py
url(r'^api/$', views.EmployeeListCBV.as_view()),
test.py
1) import requests
2) BASE_URL='http://127.0.0.1:8000/'
3) ENDPOINT='api/'
4) r=requests.get(BASE_URL+ENDPOINT)
5) data=r.json()
6) print(data)
Note: In the output we are getting some extra meta information also.
[{'model': 'testapp.employee', 'pk': 1, 'fields': {'eno': 100, 'ename': 'Sunny', 'esal': 1000.0,
'eaddr': 'Mumbai'}}, {'model': 'testapp.employee', 'pk': 2, 'fields': {'eno': 200, 'ename':
'Bunny', 'esal': 2000.0, 'eaddr
': 'Hyderabad'}}, {'model': 'testapp.employee', 'pk': 3, 'fields': {'eno': 300, 'ename':
'Chinny', 'esal': 3000.0, 'eaddr': 'Hyderabad'}}, {'model': 'testapp.employee', 'pk': 4,
'fields': {'eno': 400, 'ename': 'Vinny', '
esal': 4000.0, 'eaddr': 'Bangalore'}}]
1) class EmployeeListCBV(View):
2) def get(self,request,*args,**kwargs):
3) qs=Employee.objects.all()
4) json_data=serialize('json',qs)
5) pdict=json.loads(json_data)
6) final_list=[]
7) for obj in pdict:
8) final_list.append(obj['fields'])
9) json_data=json.dumps(final_list)
10) return HttpResponse(json_data,content_type='application/json')
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
12 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
Output:
[{'eno': 100, 'ename': 'Sunny', 'esal': 1000.0, 'eaddr': 'Mumbai'}, {'eno': 200, 'ename':
'Bunny', 'esal': 2000.0, 'eaddr': 'Hyderabad'}, {'eno': 300, 'ename': 'Chinny', 'esal': 3000.0,
'eaddr': 'Hyderabad'}, {'eno': 400, 'ename': 'Vinny', 'esal': 4000.0, 'eaddr': 'Bangalore'}]
views.py
1) class EmployeeListCBV(SerializeMixin,View):
2) def get(self,request,*args,**kwargs):
3) qs=Employee.objects.all()
4) json_data=self.serialize(qs)
5) return HttpResponse(json_data,content_type='application/json')
1) class EmployeeCRUDCBV(SerializeMixin,View):
2) def get(self,request,id,*args,**kwargs):
3) emp=Employee.objects.get(id=id)
4) json_data=self.serialize([emp,])
5) return HttpResponse(json_data,content_type='application/json')
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
13 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
Error Handling in the API:
It is not recommended to display our django error information directly to the partner
applications.Hence it is highly recommened to perform error handling.
1) class EmployeeCRUDCBV(SerializeMixin,View):
2) def get(self,request,id,*args,**kwargs):
3) try:
4) emp=Employee.objects.get(id=id)
5) except Employee.DoesNotExist:
6) json_data=json.dumps({'msg':'Specified Record Not Found'})
7) else:
8) json_data=self.serialize([emp,])
9) return HttpResponse(json_data,content_type='application/json')
Status Codes:
Status code represents the status of HttpResponse. The following are various possible
status codes.
1XX Informational
2XX Successful
3XX Redirection
4XX Client Error
5XX Server Error
Eg: HttpResponse(json_data,content_type='application/json',status=403)
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
14 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
How to render HttpResponse By using Mixin:
views.py:
1) class EmployeeCRUDCBV(SerializeMixin,HttpResponseMixin,View):
2) def get(self,request,id,*args,**kwargs):
3) try:
4) emp=Employee.objects.get(id=id)
5) except Employee.DoesNotExist:
6) json_data=json.dumps({'msg':'Specified Record Not Available'})
7) return self.render_to_http_response(json_data,404)
8) else:
9) json_data=self.serialize([emp,])
10) return self.render_to_http_response(json_data)
Commands:
1) py manage.py dumpdata testapp.Employee
Print data to the console in json format without identation
2) py manage.py dumpdata testapp.Employee --indent 4
Print data to the console in json format with identation
3) py manage.py dumpdata testapp.Employee >emp.json --indent 4
Write data to emp.json file instead of displaying to the console
4) py manage.py dumpdata testapp.Employee --format json >emp.json --indent 4
We are specifying format as json explicitly
5) py manage.py dumpdata testapp.Employee --format xml --indent 4
Print data to the console in xml format with identation
6) py manage.py dumpdata testapp.Employee --format xml > emp.xml --indent 4
Write data to emp.xml file instead of displaying to the console
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
15 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
YAML is a human readable data serialization language, which is supported by multiple
languages.
test.py(Partner Application)
1) import json
2) import requests
3) BASE_URL='http://127.0.0.1:8000/'
4) ENDPOINT='api/'
5) def create_resource():
6) new_emp={
7) 'eno':600,
8) 'ename':'Shiva',
9) 'esal':6000,
10) 'eaddr':'Chennai',
11) }
12) r=requests.post(BASE_URL+ENDPOINT,data=json.dumps(new_emp))
13) print(r.status_code)
14) print(r.text)
15) print(r.json())
16) create_resource()
Note: For POST Requests, compulsory CSRF verification should be done.If it fails our
request will be aborted.
Error:
<h1>Forbidden <span>(403)</span></h1>
<p>CSRF verification failed. Request aborted.</p>
@csrf_exempt
def my_view(request):
body
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
16 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
This approach is helpful for Function Based Views(FBVs)
Code:
from django.views.decorators.csrf import csrf_exempt
from django.utils.decorators import method_decorator
@method_decorator(csrf_exempt,name='dispatch')
class EmployeeListCBV(SerializeMixin,View):
utils.py:
1) import json
2) def is_json(data):
3) try:
4) real_data=json.loads(data)
5) valid=True
6) except ValueError:
7) valid=False
8) return valid
views.py:
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
17 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
7) data=request.body
8) if not is_json(data):
9) return self.render_to_http_response(json.dumps({'msg':'plz send valid json
data only'}),status=400)
10) json_data=json.dumps({'msg':'post method'})
11) return self.render_to_http_response(json_data)
views.py
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
18 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
9) qs=Employee.objects.all()
10) json_data=self.serialize(qs)
11) return HttpResponse(json_data,content_type='application/json')
12) def post(self,request,*args,**kwargs):
13) data=request.body
14) if not is_json(data):
15) return self.render_to_http_response(json.dumps({'msg':'plz send valid json
data only'}),status=400)
16) empdata=json.loads(request.body)
17) form=EmployeeForm(empdata)
18) if form.is_valid():
19) obj = form.save(commit=True)
20) return self.render_to_http_response(json.dumps({'msg':'resource created su
ccessfully'}))
21) if form.errors:
22) json_data=json.dumps(form.errors)
23) return self.render_to_http_response(json_data,status=400)
Partner Application(test.py)
1) import requests
2) import json
3) BASE_URL='http://127.0.0.1:8000/'
4) ENDPOINT='api/'
5) def update_resource():
6) new_data={
7) eaddr:'Ameerpet',
8) }
9) r=requests.put(BASE_URL+ENDPOINT+'8/',data=json.dumps(new_data))
10) print(r.status_code)
11) # print(r.text)
12) print(r.json())
13) update_resource()
views.py
1) @method_decorator(csrf_exempt,name='dispatch')
2) class EmployeeCRUDCBV(SerializeMixin,HttpResponseMixin,View):
3) def get_object_by_id(self,id):
4) try:
5) emp=Employee.objects.get(id=id)
6) except Employee.DoesNotExist:
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
19 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
7) emp=None
8) return emp
9) def put(self,request,id,*args,**kwargs):
10) obj=self.get_object_by_id(id)
11) if obj is None:
12) json_data=json.dumps({'msg':'No matched record found, Not possible to per
form updataion'})
13) return self.render_to_http_response(json_data,status=404)
14) data=request.body
15) if not is_json(data):
16) return self.render_to_http_response(json.dumps({'msg':'plz send valid json
data only'}),status=400)
17) new_data=json.loads(data)
18) old_data={
19) 'eno':obj.eno,
20) 'ename':obj.ename,
21) 'esal':obj.esal,
22) 'eaddr':obj.eaddr,
23) }
24) for k,v in new_data.items():
25) old_data[k]=v
26) form=EmployeeForm(old_data,instance=obj)
27) if form.is_valid():
28) form.save(commit=True)
29) json_data=json.dumps({'msg':'Updated successfully'})
30) return self.render_to_http_response(json_data,status=201)
31) if form.errors:
32) json_data=json.dumps(form.errors)
33) return self.render_to_http_response(json_data,status=400)
Note:
1) form = EmployeeForm(old_data)
form.save(commit=True)
The above code will create a new record
2) form = EmployeeForm(old_data,instance=obj)
form.save(commit=True)
The above code will perform updations to existing object instead of creating new object.
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
20 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
Performing Delete Operation:
partner application(test.py)
1) import requests
2) import json
3) BASE_URL='http://127.0.0.1:8000/'
4) ENDPOINT='api/'
5) def delete_resource():
6) r=requests.delete(BASE_URL+ENDPOINT+'9/')
7) print(r.status_code)
8) # print(r.text)
9) print(r.json())
10) delete_resource()
views.py
1) def delete(self,request,id,*args,**kwargs):
2) obj=self.get_object_by_id(id)
3) if obj is None:
4) json_data=json.dumps({'msg':'No matched record found, Not possible to per
form deletion'})
5) return self.render_to_http_response(json_data,status=404)
6) status,deleted_item=obj.delete()
7) if status==1:
8) json_data=json.dumps({'msg':'Resource Deleted successfully'})
9) return self.render_to_http_response(json_data,status=201)
10) json_data=json.dumps({'msg':'unable to delete ...plz try again'})
11) return self.render_to_http_response(json_data,status=500)
Note:
1) obj.delete() returns a tuple with 2 values.
2) The first value represents the status of the delete. If the deletion is success then its
value will be 1.
3) The secord value represents the deleted object.
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
21 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
According industry standard, in all rest api frameworks, endpoint should be same for all
CRUD operations. In our application we are violating this rule.
1) import requests
2) import json
3) BASE_URL='http://127.0.0.1:8000/'
4) ENDPOINT='api/'
5) def get_resources(id=None):
6) data={}
7) if id is not None:
8) data={
9) 'id':id
10) }
11) resp=requests.get(BASE_URL+ENDPOINT,data=json.dumps(data))
12) print(resp.status_code)
13) print(resp.json())
views.py
1) class EmployeeCRUDCBV(HttpResponseMixin,SerializeMixin,View):
2) def get_object_by_id(self,id):
3) try:
4) emp=Employee.objects.get(id=id)
5) except Employee.DoesNotExist:
6) emp=None
7) return emp
8) def get(self,request,*args,**kwargs):
9) data=request.body
10) if not is_json(data):
11) return self.render_to_http_response(json.dumps({'msg':'plz send valid json
data only'}),status=400)
12) data=json.loads(request.body)
13) id=data.get('id',None)
14) if id is not None:
15) obj=self.get_object_by_id(id)
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
22 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
16) if obj is None:
17) return self.render_to_http_response(json.dumps({'msg':'No Matched Record
Found with Specified Id'}),status=404)
18) json_data=self.serialize([obj,])
19) return self.render_to_http_response(json_data)
20) qs=Employee.objects.all()
21) json_data=self.serialize(qs)
22) return self.render_to_http_response(json_data)
test.py
1) def create_resource():
2) new_emp={
3) 'eno':2000,
4) 'ename':'Katrina',
5) 'esal':20000,
6) 'eaddr':'Mumbai',
7) }
8) r=requests.post(BASE_URL+ENDPOINT,data=json.dumps(new_emp))
9) print(r.status_code)
10) # print(r.text)
11) print(r.json())
12) create_resource()
views.py
1) def post(self,request,*args,**kwargs):
2) data=request.body
3) if not is_json(data):
4) return self.render_to_http_response(json.dumps({'msg':'plz send valid json
data only'}),status=400)
5) empdata=json.loads(request.body)
6) form=EmployeeForm(empdata)
7) if form.is_valid():
8) obj = form.save(commit=True)
9) return self.render_to_http_response(json.dumps({'msg':'resource created su
ccessfully'}))
10) if form.errors:
11) json_data=json.dumps(form.errors)
12) return self.render_to_http_response(json_data,status=400)
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
23 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
Update Resource (put Method):
test.py
1) def update_resource(id):
2) new_data={
3) 'id':id,
4) 'eno':7777,
5) 'ename':'Kareena',
6) 'eaddr':'Lanka',
7) 'esal':15000
8) }
9) r=requests.put(BASE_URL+ENDPOINT,data=json.dumps(new_data))
10) print(r.status_code)
11) # print(r.text)
12) print(r.json())
13) update_resource(14)
views.py
1) def put(self,request,*args,**kwargs):
2) data=request.body
3) if not is_json(data):
4) return self.render_to_http_response(json.dumps({'msg':'plz send valid json
data only'}),status=400)
5) data=json.loads(request.body)
6) id=data.get('id',None)
7) if id is None:
8) return self.render_to_http_response(json.dumps({'msg':'To perform updatio
n id is mandatory,you should provide'}),status=400)
9) obj=self.get_object_by_id(id)
10) if obj is None:
11) json_data=json.dumps({'msg':'No matched record found, Not possible to per
form updataion'})
12) return self.render_to_http_response(json_data,status=404)
13) new_data=data
14) old_data={
15) 'eno':obj.eno,
16) 'ename':obj.ename,
17) 'esal':obj.esal,
18) 'eaddr':obj.eaddr,
19) }
20) # for k,v in new_data.items():
21) # old_data[k]=v
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
24 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
22) old_data.update(new_data)
23) form=EmployeeForm(old_data,instance=obj)
24) if form.is_valid():
25) form.save(commit=True)
26) json_data=json.dumps({'msg':'Updated successfully'})
27) return self.render_to_http_response(json_data,status=201)
28) if form.errors:
29) json_data=json.dumps(form.errors)
30) return self.render_to_http_response(json_data,status=400)
1) def delete_resource(id):
2) data={
3) 'id':id,
4) }
5) r=requests.delete(BASE_URL+ENDPOINT,data=json.dumps(data))
6) print(r.status_code)
7) # print(r.text)
8) print(r.json())
9) delete_resource(13)
views.py
1) def delete(self,request,*args,**kwargs):
2) data=request.body
3) if not is_json(data):
4) return self.render_to_http_response(json.dumps({'msg':'plz send valid json
data only'}),status=400)
5) data=json.loads(request.body)
6) id=data.get('id',None)
7) if id is None:
8) return self.render_to_http_response(json.dumps({'msg':'To perform delete,
id is mandatory,you should provide'}),status=400)
9) obj=self.get_object_by_id(id)
10) if obj is None:
11) json_data=json.dumps({'msg':'No matched record found, Not possible to per
form delete operation'})
12) return self.render_to_http_response(json_data,status=404)
13) status,deleted_item=obj.delete()
14) if status==1:
15) json_data=json.dumps({'msg':'Resource Deleted successfully'})
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
25 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
16) return self.render_to_http_response(json_data,status=201)
17) json_data=json.dumps({'msg':'unable to delete ...plz try again'})
18) return self.render_to_http_response(json_data,status=500)
models.py
admin.py
forms.py
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
26 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
mixins.py
utils.py
1) import json
2) def is_json(data):
3) try:
4) real_data=json.loads(data)
5) valid=True
6) except ValueError:
7) valid=False
8) return valid
urls.py
views.py
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
28 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
44) if form.is_valid():
45) obj = form.save(commit=True)
46) return self.render_to_http_response(json.dumps({'msg':'resource created su
ccessfully'}))
47) if form.errors:
48) json_data=json.dumps(form.errors)
49) return self.render_to_http_response(json_data,status=400)
50) def put(self,request,*args,**kwargs):
51) data=request.body
52) if not is_json(data):
53) return self.render_to_http_response(json.dumps({'msg':'plz send valid json
data only'}),status=400)
54) data=json.loads(request.body)
55) id=data.get('id',None)
56) if id is None:
57) return self.render_to_http_response(json.dumps({'msg':'To perform updatio
n id is mandatory,you should provide'}),status=400)
58) obj=self.get_object_by_id(id)
59) if obj is None:
60) json_data=json.dumps({'msg':'No matched record found, Not possible to per
form updataion'})
61) return self.render_to_http_response(json_data,status=404)
62)
63) new_data=data
64) old_data={
65) 'eno':obj.eno,
66) 'ename':obj.ename,
67) 'esal':obj.esal,
68) 'eaddr':obj.eaddr,
69) }
70) # for k,v in new_data.items():
71) # old_data[k]=v
72) old_data.update(new_data)
73) form=EmployeeForm(old_data,instance=obj)
74) if form.is_valid():
75) form.save(commit=True)
76) json_data=json.dumps({'msg':'Updated successfully'})
77) return self.render_to_http_response(json_data,status=201)
78) if form.errors:
79) json_data=json.dumps(form.errors)
80) return self.render_to_http_response(json_data,status=400)
81) def delete(self,request,*args,**kwargs):
82) data=request.body
83) if not is_json(data):
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
29 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
84) return self.render_to_http_response(json.dumps({'msg':'plz send valid json
data only'}),status=400)
85) data=json.loads(request.body)
86) id=data.get('id',None)
87) if id is None:
88) return self.render_to_http_response(json.dumps({'msg':'To perform delete,
id is mandatory,you should provide'}),status=400)
89) obj=self.get_object_by_id(id)
90) if obj is None:
91) json_data=json.dumps({'msg':'No matched record found, Not possible to per
form delete operation'})
92) return self.render_to_http_response(json_data,status=404)
93) status,deleted_item=obj.delete()
94) if status==1:
95) json_data=json.dumps({'msg':'Resource Deleted successfully'})
96) return self.render_to_http_response(json_data,status=201)
97) json_data=json.dumps({'msg':'unable to delete ...plz try again'})
98) return self.render_to_http_response(json_data,status=500)
test.py
1) import requests
2) import json
3) BASE_URL='http://127.0.0.1:8000/'
4) ENDPOINT='api/'
5) def get_resources(id=None):
6) data={}
7) if id is not None:
8) data={
9) 'id':id
10) }
11) resp=requests.get(BASE_URL+ENDPOINT,data=json.dumps(data))
12) print(resp.status_code)
13) print(resp.json())
14) def create_resource():
15) new_emp={
16) 'eno':2000,
17) 'ename':'Katrina',
18) 'esal':20000,
19) 'eaddr':'Mumbai',
20) }
21) r=requests.post(BASE_URL+ENDPOINT,data=json.dumps(new_emp))
22) print(r.status_code)
23) # print(r.text)
24) print(r.json())
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
30 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
25) create_resource()
26) def update_resource(id):
27) new_data={
28) 'id':id,
29) 'eno':7777,
30) 'ename':'Kareena',
31) 'eaddr':'Lanka',
32) 'esal':15000
33) }
34) r=requests.put(BASE_URL+ENDPOINT,data=json.dumps(new_data))
35) print(r.status_code)
36) # print(r.text)
37) print(r.json())
38) def delete_resource(id):
39) data={
40) 'id':id,
41) }
42) r=requests.delete(BASE_URL+ENDPOINT,data=json.dumps(data))
43) print(r.status_code)
44) # print(r.text)
45) print(r.json())
models.py
admin.py
mixins.py
utils.py
1) import json
2) def is_json(data):
3) try:
4) real_data=json.loads(data)
5) valid=True
6) except ValueError:
7) valid=False
8) return valid
forms.py
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
32 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
urls.py
views.py
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
33 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
31) return self.render_to_http_response(json.dumps({'msg':'No Matched Res
ource Found for the given id'}),status=400)
32) json_data=self.serialize([std,])
33) return self.render_to_http_response(json_data)
34) qs=Student.objects.all()
35) json_data=self.serialize(qs)
36) return self.render_to_http_response(json_data)
37) def post(self,request,*args,**kwargs):
38) data=request.body
39) valid_json=is_json(data)
40) if not valid_json:
41) return self.render_to_http_response(json.dumps({'msg':'please send valid js
on only'}),status=400)
42) std_data=json.loads(data)
43) form=StudentForm(std_data)
44) if form.is_valid():
45) form.save(commit=True)
46) return self.render_to_http_response(json.dumps({'msg':'Resource Created S
uccessfully'}))
47) if form.errors:
48) json_data=json.dumps(form.errors)
49) return self.render_to_http_response(json_data,status=400)
50) def put(self,request,*args,**kwargs):
51) data=request.body
52) valid_json=is_json(data)
53) if not valid_json:
54) return self.render_to_http_response(json.dumps({'msg':'please send valid js
on only'}),status=400)
55) provided_data=json.loads(data)
56) id=provided_data.get('id',None)
57) if id is None:
58) return self.render_to_http_response(json.dumps({'msg':'To perform updatio
n id is mandatory,plz provide id'}),status=400)
59) std=self.get_object_by_id(id)
60) original_data={
61) 'name':std.name,
62) 'rollno':std.rollno,
63) 'marks':std.marks,
64) 'gf':std.gf,
65) 'bf':std.bf
66) }
67) original_data.update(provided_data)
68) form=StudentForm(original_data,instance=std)
69) if form.is_valid():
70) form.save(commit=True)
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
34 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
71) return self.render_to_http_response(json.dumps({'msg':'Resource Updated
Successfully'}))
72) if form.errors:
73) json_data=json.dumps(form.errors)
74) return self.render_to_http_response(json_data,status=400)
75)
76) def delete(self,request,*args,**kwargs):
77) data=request.body
78) if not is_json(data):
79) return self.render_to_http_response(json.dumps({'msg':'plz send valid json
data only'}),status=400)
80) data=json.loads(request.body)
81) id=data.get('id',None)
82) if id is None:
83) return self.render_to_http_response(json.dumps({'msg':'To perform delete,
id is mandatory,you should provide'}),status=400)
84) obj=self.get_object_by_id(id)
85) if obj is None:
86) json_data=json.dumps({'msg':'No matched record found, Not possible to per
form delete operation'})
87) return self.render_to_http_response(json_data,status=404)
88) status,deleted_item=obj.delete()
89) if status==1:
90) json_data=json.dumps({'msg':'Resource Deleted successfully'})
91) return self.render_to_http_response(json_data)
92) json_data=json.dumps({'msg':'unable to delete ...plz try again'})
93) return self.render_to_http_response(json_data,status=500)
test.py
1) import requests
2) import json
3) BASE_URL='http://127.0.0.1:8000/'
4) ENDPOINT='api/'
5) def get_resources(id=None):
6) data={}
7) if id is not None:
8) data={
9) 'id':id
10) }
11) resp=requests.get(BASE_URL+ENDPOINT,data=json.dumps(data))
12) print(resp.status_code)
13) print(resp.json())
14) #get_resources()
15) def create_resource():
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
35 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
16) new_std={
17) 'name':'Dhoni',
18) 'rollno':105,
19) 'marks':32,
20) 'gf':'Deepika',
21) 'bf':'Yuvraj'
22) }
23) r=requests.post(BASE_URL+ENDPOINT,data=json.dumps(new_std))
24) print(r.status_code)
25) # print(r.text)
26) print(r.json())
27) # create_resource()
28) def update_resource(id):
29) new_data={
30) 'id':id,
31) 'gf':'Sakshi',
32)
33) }
34) r=requests.put(BASE_URL+ENDPOINT,data=json.dumps(new_data))
35) print(r.status_code)
36) # print(r.text)
37) print(r.json())
38) # update_resource(5)
39) def delete_resource(id):
40) data={
41) 'id':id,
42) }
43) r=requests.delete(BASE_URL+ENDPOINT,data=json.dumps(data))
44) print(r.status_code)
45) # print(r.text)
46) print(r.json())
47) delete_resource(5)
1) Tastify
2) Django REST Framework(DRF)
etc
But DRF is the most commonly used and easy to use framework ti build REST APIs for
Django Applications.
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
36 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
Speciality of DRF:
Some reasons you might want to use REST framework:
1) The Web browsable API is a huge usability win for your developers.
2) Authentication policies including packages for OAuth1a and OAuth2.
3) Serialization that supports both ORM and non-ORM data sources.
4) Customizable all the way down
5) Extensive documentation and great community support.
6) Used and trusted by internationally recognised companies including Mozilla, Red Hat,
Heroku, and Eventbrite.
Requirements:
REST framework requires the following:
Python (2.7, 3.4, 3.5, 3.6, 3.7)
Django (1.11, 2.0, 2.1)
Installation:
Step-1: Install DRF
pip install djangorestframework
pip install markdown # Markdown support for the browsable API.
pip install django-filter # Filtering support
Note: After installing all required softwares, it is highly recommended to save installed
software information inside a file, so that, it is helpful for production environment to
know version requirements.
requirements.txt:
argon2-cffi==18.3.0
attrs==18.1.0
bcrypt==3.1.4
certifi==2018.11.29
.....
urlpatterns = [
...
url(r'^api-auth/', include('rest_framework.urls'))
]
Serializers:
DRF Serializers are responsible for the following activities
1) Serialization
2) Deserialization
3) Validation
Note: DRF Serializers will work very similar to Django Forms and ModelForm classes.
1) Serialization:
The process of converting complex objects like Model objects and QuerySets to Python
native data types like dictionary etc,is called Serialization.
The main advantage of converting to python native data types is we can
convert(render) very easily to JSON,XML etc
models.py
serializers.py
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
38 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
Converting Employee Object to Python Native Data Type By using
EmployeeSerializer (Serialization Process):
>>> from testapp.models import Employee
>>> from testapp.serializers import EmployeeSerializer
>>> emp=Employee(eno=100,ename='Durga',esal=1000,eaddr='Hyd')
>>> eserializer=EmployeeSerializer(emp)
>>> eserializer.data
{'eno': 100, 'ename': 'Durga', 'esal': 1000.0, 'eaddr': 'Hyd'}
2) Deserialization:
The process of converting python native data types complex data types like Model
objects is called deserialization.
First we have to convert json_data to python native data type.
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
39 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
1) import io
2) from rest_framework.parsers import JSONParser
3) stream=io.BytesIO(json_data)
4) data=JSONParser().parse(stream)
Now, we have to convert python native data type to database supported complex type
(deserialization)
1) serializer=EmployeeSerializer(data=data)
2) serializer.is_valid()
3) serializer.validated_data
Python Deserialization
Native Database
Json Supported
Data Data
Types Form
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
40 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
admin.py
serializers.py
views.py
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
41 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
test.py
1) import requests
2) import json
3) BASE_URL='http://127.0.0.1:8000/'
4) ENDPOINT='api/'
5) def get_resources(id=None):
6) data={}
7) if id is not None:
8) data={
9) 'id':id
10) }
11) resp=requests.get(BASE_URL+ENDPOINT,data=json.dumps(data))
12) print(resp.status_code)
13) print(resp.json())
14) get_resources()
views.py(post method):
1) def post(self,request,*args,**kwargs):
2) json_data=request.body
3) stream=io.BytesIO(json_data)
4) data=JSONParser().parse(stream)
5) serializer=EmployeeSerializer(data=data)
6) if serializer.is_valid():
7) serializer.save()
8) msg={'msg':'Resource Created Succesfully'}
9) json_data=JSONRenderer().render(msg)
10) return HttpResponse(json_data,content_type='application/json')
11) json_data=JSONRenderer().render(serializer.errors)
12) return HttpResponse(json_data,content_type='application/json')
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
42 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
Note:
1) To send post request csrf verification should be disabled
2) Before calling save() method,compulsory we should call is_valid() method, otherwise
we will get error.
AssertionError: You must call .is_valid() before calling .save()
3) After validation we can print validated data by using
serializer.validated_data variable
print(serializer.validated_data)
views.py
1) def put(self,request,*args,**kwargs):
2) json_data=request.body
3) stream=io.BytesIO(json_data)
4) data=JSONParser().parse(stream)
5) id=data.get('id')
6) emp=Employee.objects.get(id=id)
7) #serializer=EmployeeSerializer(emp,data=data)
8) serializer=EmployeeSerializer(emp,data=data,partial=True)
9) if serializer.is_valid():
10) serializer.save()
11) msg={'msg':'Resource Updated Succesfully'}
12) json_data=JSONRenderer().render(msg)
13) return HttpResponse(json_data,content_type='application/json')
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
43 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
14) json_data=JSONRenderer().render(serializer.errors)
15) return HttpResponse(json_data,content_type='application/json')
Note: By default for update operation, we have to provide all fields. If any field is
missing, then we will get ValidationError.
If we don't want to provide all fields, then we have to use 'partial' attribute.
serializer = EmployeeSerializer(emp,data=data)
In this case we have to provide all fields for updation
serializer = EmployeeSerializer(emp,data=data,partial=True)
In this case we have to provide only required fields but not all.
Note: By using serializers, we can perform get(),post() and put() operations. There is role
of serializers in delete operation.
1) class EmployeeSerializer(serializers.Serializer):
2) ....
3)
4) def validate_esal(self,value):
5) if value<5000:
6) raise serializers.ValidationError('Employee Salaray Should be Minimum 5000')
7) return value
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
44 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
1) def validate(self,data):
2) ename=data.get('ename')
3) esal=data.get('esal')
4) if ename.lower()=='sunny':
5) if esal<60000:
6) raise serializers.ValidationError('Sunny Salary should be minimum 60K')
7) return data
Use Cases:
1) First entered pwd and re-entered pwd must be same.
2) First entered account number and re-entered account number must be same
views.py
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
46 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
15) json_data=request.body
16) stream=io.BytesIO(json_data)
17) data=JSONParser().parse(stream)
18) id=data.get('id',None)
19) if id is not None:
20) emp=Employee.objects.get(id=id)
21) serializer=EmployeeSerializer(emp)
22) json_data=JSONRenderer().render(serializer.data)
23) return HttpResponse(json_data,content_type='application/json')
24) qs=Employee.objects.all()
25) serializer=EmployeeSerializer(qs,many=True)
26) json_data=JSONRenderer().render(serializer.data)
27) return HttpResponse(json_data,content_type='application/json')
28) def post(self,request,*args,**kwargs):
29) json_data=request.body
30) stream=io.BytesIO(json_data)
31) data=JSONParser().parse(stream)
32) serializer=EmployeeSerializer(data=data)
33) if serializer.is_valid():
34) serializer.save()
35) msg={'msg':'Resource Created Succesfully'}
36) json_data=JSONRenderer().render(msg)
37) return HttpResponse(json_data,content_type='application/json')
38) json_data=JSONRenderer().render(serializer.errors)
39) return HttpResponse(json_data,content_type='application/json')
40) def put(self,request,*args,**kwargs):
41) json_data=request.body
42) stream=io.BytesIO(json_data)
43) data=JSONParser().parse(stream)
44) id=data.get('id')
45) emp=Employee.objects.get(id=id)
46) serializer=EmployeeSerializer(emp,data=data,partial=True)
47) if serializer.is_valid():
48) serializer.save()
49) msg={'msg':'Resource Updated Succesfully'}
50) json_data=JSONRenderer().render(msg)
51) return HttpResponse(json_data,content_type='application/json')
52) json_data=JSONRenderer().render(serializer.errors)
53) return HttpResponse(json_data,content_type='application/json')
test.py
1) import requests
2) import json
3) BASE_URL='http://127.0.0.1:8000/'
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
47 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
4) ENDPOINT='api/'
5) # def get_resources(id=None):
6) # data={}
7) # if id is not None:
8) # data={
9) # 'id':id
10) # }
11) # resp=requests.get(BASE_URL+ENDPOINT,data=json.dumps(data))
12) # print(resp.status_code)
13) # print(resp.json())
14) # get_resources()
15) # def create_resource():
16) # new_emp={
17) # 'eno':300,
18) # 'ename':'Kareena',
19) # 'esal':3000,
20) # 'eaddr':'Hyderabad',
21) # }
22) # r=requests.post(BASE_URL+ENDPOINT,data=json.dumps(new_emp))
23) # print(r.status_code)
24) # # print(r.text)
25) # print(r.json())
26) # create_resource()
27) def update_resource(id):
28) new_data={
29) 'id':id,
30) # 'eno':700,
31) 'ename':'Sunny123',
32) 'esal':15000,
33) # 'eaddr':'Hyd'
34)
35) }
36) r=requests.put(BASE_URL+ENDPOINT,data=json.dumps(new_data))
37) print(r.status_code)
38) # print(r.text)
39) print(r.json())
40) update_resource(3)
41) # def delete_resource(id):
42) # data={
43) # 'id':id,
44) # }
45) # r=requests.delete(BASE_URL+ENDPOINT,data=json.dumps(data))
46) # print(r.status_code)
47) # # print(r.text)
48) # print(r.json())
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
48 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
49) # delete_resource(5)
ModelSerializers:
If our serializable objects are Django model objects, then it is highly recommended to
go for ModelSerializer.
ModelSerializer class is exactly same as regular serializer classe except the following
differences
1) The fields will be considered automatically based on the model and we are not
required to specify explicitly.
2) It provides default implementation for create() and update() methods.
Note: ModelSerializer won't provide any extra functionality and it is just for typing
shortcut.
1) class EmployeeSerializer(serializers.ModelSerializer):
2) class Meta:
3) model=Employee
4) fields='__all__'
Here we are not required to specify fields and these will be considered automatically
based on Model class. We are not required to implement create() and update() methods,
because ModelSerializer class will provide these methods.
***Note: If we want to define validations for any field then that particular field we have
to declare explicitly.
1) def multiples_of_1000(value):
2) print('validations by using validator')
3) if value % 1000 != 0:
4) raise serializers.ValidationError('Salary should be multiples of 1000s')
5) class EmployeeSerializer(serializers.ModelSerializer):
6) esal=serializers.FloatField(validators=[multiples_of_1000,])
7) class Meta:
8) model=Employee
9) fields='__all__'
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
49 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
2) To include only some fields
fields = ('eno','ename','eaddr')
This approach is helpful if we want to include very less number of fields.
1) APIView
2) ViewSet
1) APIView:
It is the most basic class to build REST APIs. It is similar to Django traditional View
class.
It is the child class of Django's View class.
It allows us to use standard HTTP methods as functions like get(),post(),put() etc
Here, we have to write complete code for business logic and hence programmer
having complete control on the logic. We can understand flow of execution very
clearly.
Best suitable for complex operations like working with multiple datasources, calling
other APIs etc
We have to define url mappings manually.
serializers.py
views.py
1) def post(self,request):
2) serializer=NameSerializer(data=request.data)
3) if serializer.is_valid():
4) name=serializer.data.get('name')
5) msg='Hello {} Wish You Happy New Year !!!'.format(name)
6) return Response({'msg':msg})
7) return Response(serializer.errors,status=400)
1) input: {"name":"Sunny"}
2) response:
3)
4) HTTP 200 OK
5) Allow: GET, POST, HEAD, OPTIONS
6) Content-Type: application/json
7) Vary: Accept
8)
9) {
10) "msg": "Hello Sunny Wish You Happy New Year !!!"
11) }
12)
13) input: {"name":"Sunny Leone"}
14) response:
15)
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
51 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
16) HTTP 400 Bad Request
17) Allow: GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS
18) Content-Type: application/json
19) Vary: Accept
20)
21) {
22) "name": [
23) "Ensure this field has no more than 7 characters."
24) ]
25) }
Complete Application:
views.py
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
52 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
17) def put(self,request,pk=None):
18) return Response({'msg':'Response from put method'})
19) def patch(self,request,pk=None):
20) return Response({'msg':'Response from patch method'})
21) def delete(self,request,pk=None):
22) return Response({'msg':'Response from delete method'})
serializers.py
urls.py
2) ViewSets:
By using ViewSets, we can provide business logic for our API views.
It is alternative to APIView class.
In the case of APIView, we can use HTTP Methods as functions like get(), post() etc. But
in ViewSet, We have to use Model class actions/operations for function names.
list() To get all resources/records/objects
retrieve() To get a specific resource
create() To create a new resource
update() To update a resource
partial_update() To perform partial updation of resource.
destroy() To delete a resource.
Mapping:
get() list() and retrieve()
post() create()
put() update()
patch() partial_update()
delete() destroy()
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
53 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
In APIViews, we have to write total logic. But in ViewSets most of the logic will be
provided automatically. Hence we can provide more functionality with less code and we
can develop API very quickly in less time.
urls.py
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
54 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
7)
8) urlpatterns = [
9) url(r'^admin/', admin.site.urls),
10) # url(r'^api/', views.TestApiView.as_view()),
11) url(r'',include(router.urls))
12) ]
Complete Application:
views.py
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
55 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
13) return Response({'msg':msg})
14) return Response(serializer.errors,status=400)
15) def retrieve(self,request,pk=None):
16) return Response({'msg':'Response from retrieve method'})
17) def update(self,request,pk=None):
18) return Response({'msg':'Response from update method'})
19) def partial_update(self,request,pk=None):
20) return Response({'msg':'Response from partial_update method'})
21) def destroy(self,request,pk=None):
22) return Response({'msg':'Response from destroy method'})
serializers.py
urls.py
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
56 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
get(),post(),put(),patch(),delete() list(),retrieve(),create(),update(),partial_update()
and destroy()
3) We have to map views to urls 3) We are not required to map views to urls
explicitly. explicitly. DefaultRouter will takes care url
maapings automatically.
4) Most of the business logic we have 4) Most of the business logic will be generated
to write explicitly. automatically.
5) Length of the code is more 5) Length of the code is less.
6) API Development time is more 6) API Development time is less
7) Developer has complete control 7) Developer won't have complete control over
over the logic the logic.
8) Clear Execution Flow is possible 8) Clear Execution Flow is not possible
9) Best suitable for complex operations 9) Best suitable for developing simple APIs like
like using multiple data sources developing CRUD interface for database models.
simultaneously, calling other APIs etc
models.py
admin.py
serializers.py
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
57 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
4) class Meta:
5) model=Employee
6) fields='__all__'
views.py
Note: In the above example, serializer is responsible to convert queryset to python native
data type(dict) and Response object is responsible to convert that dict to json.
urls.py
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
58 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
How to implement Search Operation:
If we want to implement search operation, we have to override get_queryset() method in
our view class.
Note: If we override get_queryset() method then we are not required to specify queryset
variable.
To list out all employee records where ename contains Sunny, the endpoint url is:
http://127.0.0.1:8000/api/?ename=Sunny
class EmployeeCreateAPIView(generics.CreateAPIView):
queryset=Employee.objects.all()
serializer_class=EmployeeSerializer
url(r'^api/', views.EmployeeCreateAPIView.as_view()),
class EmployeeDetailAPIView(generics.RetrieveAPIView):
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
59 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
queryset=Employee.objects.all()
serializer_class=EmployeeSerializer
url(r'^api/(?P<pk>\d+)/$', views.EmployeeDetailAPIView.as_view()),
In the url pattern compulsory we should use 'pk',otherwise we will get the following error.
AssertionError at /api/2/
Expected view EmployeeDetailAPIView to be called with a URL keyword argument named
"pk". Fix your URL conf, or set the '.lookup_field' attribute on the view correctly.
If we want to use anyother name instead of 'pk' then we have to use lookup_field
attribute in the view class.
class EmployeeDetailAPIView(generics.RetrieveAPIView):
queryset=Employee.objects.all()
serializer_class=EmployeeSerializer
lookup_field='id'
url(r'^api/(?P<id>\d+)/$', views.EmployeeDetailAPIView.as_view()),
class EmployeeUpdateAPIView(generics.UpdateAPIView):
queryset=Employee.objects.all()
serializer_class=EmployeeSerializer
lookup_field='id'
url(r'^api/(?P<id>\d+)/$', views.EmployeeUpdateAPIView.as_view()),
Note: In the browsable API, for PUT operation we have to provide values for all fields.
But for PATCH operation we have to provide only required fields.
class EmployeeDeleteAPIView(generics.DestroyAPIView):
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
60 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
queryset=Employee.objects.all()
serializer_class=EmployeeSerializer
lookup_field='id'
url(r'^api/(?P<id>\d+)/$', views.EmployeeDeleteAPIView.as_view()),
Note:
ListAPIView Specially designed class for List operation
CreateAPIView Specially designed class for Create operation
RetrieveAPIView Specially designed class for Detail operation
UpdateAPIView Specially designed class for Update operation
DestroyAPIView Specially designed class for delete operation
class EmployeeListCreateAPIView(generics.ListCreateAPIView):
queryset=Employee.objects.all()
serializer_class=EmployeeSerializer
url(r'^api/', views.EmployeeListCreateAPIView.as_view()),
class EmployeeRetrieveUpdateAPIView(generics.RetrieveUpdateAPIView):
queryset=Employee.objects.all()
serializer_class=EmployeeSerializer
lookup_field='id'
url(r'^api/(?P<id>\d+)/$', views.EmployeeRetrieveUpdateAPIView.as_view()),
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
61 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
class EmployeeRetrieveDestroyAPIView(generics.RetrieveDestroyAPIView):
queryset=Employee.objects.all()
serializer_class=EmployeeSerializer
lookup_field='id'
url(r'^api/(?P<id>\d+)/$', views.EmployeeRetrieveDestroyAPIView.as_view()),
class EmployeeRetrieveUpdateDestroyAPIView(generics.RetrieveUpdateDestroyAPIView):
queryset=Employee.objects.all()
serializer_class=EmployeeSerializer
lookup_field='id'
url(r'^api/(?P<id>\d+)/$', views.EmployeeRetrieveUpdateDestroyAPIView.as_view()),
views.py
1) class EmployeeListCreateAPIView(generics.ListCreateAPIView):
2) queryset=Employee.objects.all()
3) serializer_class=EmployeeSerializer
4) class EmployeeRetrieveUpdateDestroyAPIView(generics.RetrieveUpdateDestroyAP
IView):
5) queryset=Employee.objects.all()
6) serializer_class=EmployeeSerializer
7) lookup_field='id'
urls.py
url(r'^api/$', views.EmployeeListCreateAPIView.as_view()),
url(r'^api/(?P<id>\d+)/$', views.EmployeeRetrieveUpdateDestroyAPIView.as_view()),
Note: The following are various predefined APIView classes to build our API very easily
ListAPIView
CreateAPIView
RetrieveAPIView
UpdateAPIView
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
62 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
DestroyAPIView
ListCreateAPIView
RetrieveUpdateAPIView
RetrieveDestroyAPIView
RetrieveUpdateDestroyAPIView
Mixins:
Mixins are reusable components. DRF provides several mixins to provide basic view
behaviour. Mixin classes provide several action methods like create(), list() etc which are
useful while implementing handling methods like get(), post() etc
The mixin classes can be imported from rest_framework.mixins.
1) ListModelMixin
2) CreateModelMixin
3) RetrieveModelMixin
4) UpdateModelMixin
5) DestroyModelMixin
1) ListModelMixin:
It can be used to implement list operation (get method handler).
It provides list() method
list(request,*args,**kwargs)
2) CreateModelMixin:
It can be used for implementing create operation. ie for creating and saving new
model instance(post method handler).It provides create() method.
create(request,*args,**kwargs)
3) RetrieveModelMixin:
It can be used to implement retrieve/detail operation(get method handler). It provides
retrieve() method
retrieve(request,*args,**kwargs)
4) UpdateModelMixin:
It can be used to implement update operation(both put and patch)
It provides update() method to implement put method handler.
update(request,*args,**kwargs)
It provides partial_update() method to implement patch method handler
partial_update(request,*args,**kwargs)
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
63 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
5) DestroyModelMixin:
It can be used to implement destroy operation(delete method handler)
It provide destroy() method
destroy(request,*args,**kwargs)
Demo Application:
1) from rest_framework import mixins
2) class EmployeeListModelMixin(mixins.CreateModelMixin,generics.ListAPIView):
3) queryset=Employee.objects.all()
4) serializer_class=EmployeeSerializer
5) def post(self,request,*args,**kwargs):
6) return self.create(request,*args,**kwargs)
7)
8) class EmployeeDetailAPIViewMixin(mixins.UpdateModelMixin,mixins.DestroyMod
elMixin,generics.RetrieveAPIView):
9) queryset=Employee.objects.all()
10) serializer_class=EmployeeSerializer
11) def put(self,request,*args,**kwargs):
12) return self.update(request,*args,**kwargs)
13) def patch(self,request,*args,**kwargs):
14) return self.partial_update(request,*args,**kwargs)
15) def delete(self,request,*args,**kwargs):
16) return self.destroy(request,*args,**kwargs)
17)
18) url(r'^api/$', views.EmployeeListModelMixin.as_view()),
19) url(r'^api/(?P<pk>\d+)/$', views.EmployeeDetailAPIViewMixin.as_view()),
models.py
admin.py
serializers.py
views.py
urls.py
Note:
1) If we want to develop simple APIs very quickly then ViewSet is the best choice
2) In the case of normal ViewSet, at the time of registration with router, base_name
attribute is mandatory. But if we are using ModelViewSet then this base_name
attribute is optional.
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
65 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
Eg:
router.register('api',views.EmployeeCRUDCBV,base_name='api')
router.register('api',views.EmployeeCRUDCBV)
Partner
Application
POST MAN
API
Browsable
API
From Command
Prompt By Using
Httpie OR URL
1) Partner Application
2) Browsable API
3) POSTMAN
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
66 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
Authentication and Authorization:
The APIs, which are developed up to this can be accessed by every one.
By using ENDPOINT, any one can create a new resource,can modify and delete any
existing resource. It causes security problems. To provide Security for our API, we should
go for Authentication and Authorization.
Authentication:
The process of validating user is called authentication. Most of the times we can perform
authentication by using username and password combination or by using tokens etc
Note: By using DRF, we can implement our own custom authentication mechanism also
Authorization:
The process of validating access permissions of user is called authorization.
DRF provides several permission classes for authorization.
1) AllowAny
2) IsAuthenticated
3) IsAdminUser
4) IsAuthenticatedOrReadOnly
5) DjangoModelPermissions
6) DjangoModelPermissionsOrAnonReadOnly
etc
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
67 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
Steps to implement TokenAuthentication:
1) We have to include authtoken application in INSTALLED_APPS list inside settings.py
file.
1) INSTALLED_APPS = [
2) ....
3) 'rest_framework',
4) 'rest_framework.authtoken',
5) 'testapp'
6) ]
authtoken application will validate this username and password.After valiation, it will
check is any token already generated for this user or not. If it is already generated then
return existing token from Tokens table.
If it is not yet generated, then authtoken application will generate Token and save in
Tokens table and then send that token to the client.
Note: From the postman also,we can send the request. But username and password we
have to provide in Body section.
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
68 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
We have to enable authentication and authorization for our view classes either locally
OR globally.
Enabling Locally:
Our application may contain several view classes. If we want to enable authentication and
authorization for a particular view class then we have to use this local approach.
Note: Now,if we want to access ENDPOINT compulsory we should send Token, otherwise
we will get 401 Unauthorized error response.
1) D:\durgaclasses>http http://127.0.0.1:8000/api/
2) HTTP/1.0 401 Unauthorized
3) Allow: GET, POST, HEAD, OPTIONS
4) Content-Length: 58
5) Content-Type: application/json
6) Date: Mon, 21 Jan 2019 11:43:07 GMT
7) Server: WSGIServer/0.2 CPython/3.6.5
8) Vary: Accept
9) WWW-Authenticate: Token
10) X-Frame-Options: SAMEORIGIN
11)
12) {
13) "detail": "Authentication credentials were not provided."
14) }
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
69 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
10) X-Frame-Options: SAMEORIGIN
11)
12) [
13) {
14) "eaddr": "Mumbai",
15) "ename": "Sunny",
16) "eno": 100,
17) "esal": 1000.0,
18) "id": 1
19) },
20) {
21) "eaddr": "Hyderabad",
22) "ename": "Bunny",
23) "eno": 200,
24) "esal": 2000.0,
25) "id": 2
26) }
27) ]
Enabling Globally:
If we want to enable authentication and authorization for all view classes, we have to
use this approach.
We have to add the following lines inside settings.py file.
1) REST_FRAMEWORK={
2) 'DEFAULT_AUTHENTICATION_CLASSES':('rest_framework.authentication.TokenAut
hentication',),
3) 'DEFAULT_PERMISSION_CLASSES':('rest_framework.permissions.IsAuthenticated',)
4) }
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
70 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
To access this end point now authentication and authorization is not required. Any one
can access.
1) AllowAny
2) IsAuthenticated
3) IsAdminUser
4) IsAuthenticatedOrReadOnly
5) DjangoModelPermissions
6) DjangoModelPermissionsOrAnonReadOnly
1) AllowAny:
The AllowAny permission class will allow unrestricted access irrespective of whether
request is authenticated or not.
This is default value for permission-class. It is very helpful to allow unrestricted access
for a particular view class if global settings are enabled.
2) IsAuthenticated:
The IsAuthenticated permission class will deny permissions to any unauthorized user.
ie only authenticated users are allowed to access endpoint.
This permission is suitable, if we want our API to be accessible by only registered
users.
Note:
We can send Token in postman inside Headers Section
Key: Authorization
Value: Token 3639020972202cc1d25114ab4a5f54e6078184a4
3) IsAdminUser:
If we use IsAdminUser permission class then only AdminUser is allowed to access.i.e
the users where is_staff property is True.
This type of permission is best suitable if we want our API to be accessible by only
trusted administrators.
If the user is not admin and if he is trying to access endpoint then we will get 403
status code error response saying:
{
"detail": "You do not have permission to perform this action."
}
4) IsAuthenticatedOrReadOnly:
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
71 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
To perform read operation (safe methods:GET,HEAD,OPTIONS) authentication is not
required. But for the remaining operations (POST,PUT,PATCH,DELETE) authentication
must be required.
If any person is allowed to perform read operation and only registered users are
allowed to perform write operation then we should go for this permission class.
Eg: In IRCTC application, to get trains information (read operation) registration is not
required. But to book tickets (write operation) login must be required.
5) DjangoModelPermissions:
This is the most powerful permission class. Authorization will be granted iff user is
authenticated and has the relevant model permissions.
DjangoModelPermissions = Authentication + Model Permissions.
If the user is not authenticated(we are not providing token) then we will get 401
Unauthorized error message saying
{
"detail": "Authentication credentials were not provided."
}
If we are providing Token (authenticated) but not having model permissions then we can
perform only GET operation. But to perform POST,PUT,PATCH,DELETE compulsory model
permissions must be required,otherwise we will get 403 Forbidden error message saying
{
"detail": "You do not have permission to perform this action."
}
We have to provide these model permissions in admin interface under User permissions:
6) DjangoModelPermissionsOrAnonReadOnly:
It is exactly same as DjangoModelPermissions class except that it allows
unauthenticated users to have read-only access to the API.
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
72 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
1) from rest_framework.viewsets import ModelViewSet
2) from testapp.models import Employee
3) from testapp.serializers import EmployeeSerializer
4) from rest_framework.authentication import TokenAuthentication
5) from rest_framework.permissions import IsAuthenticated,AllowAny,IsAdminUser,I
sAuthenticatedOrReadOnly,DjangoModelPermissions,DjangoModelPermissionsOr
AnonReadOnly
6) class EmployeeCRUDCBV(ModelViewSet):
7) queryset=Employee.objects.all()
8) serializer_class=EmployeeSerializer
9) authentication_classes=[TokenAuthentication,]
10) permission_classes=[DjangoModelPermissionsOrAnonReadOnly,]
Custom Permissions:
Based on our programming requirement, we can define our own permission classes also.
We have to create child class for BasePermission class and we have to override
has_permission() method.
permissions.py
views.py
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
73 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
9) serializer_class=EmployeeSerializer
10) authentication_classes=[TokenAuthentication,]
11) permission_classes=[IsReadOnly,]
Eg 2: Defining our own permission class which allows only GET and PATCH methods.
1) INSTALLED_APPS = [
2) ....
3) 'rest_framework',
4) 'rest_framework.authtoken',
5) 'testapp'
6) ]
7) REST_FRAMEWORK={
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
74 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
8) 'DEFAULT_AUTHENTICATION_CLASSES':('rest_framework.authentication.
TokenAuthentication',),
9) 'DEFAULT_PERMISSION_CLASSES':('rest_framework.permissions.IsAuthenticated',)
10) }
models.py
admin.py
serializers.py
permissions.py
views.py
urls.py
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
76 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
7) router.register('api',views.EmployeeCRUDCBV)
8) from rest_framework.authtoken import views
9)
10) urlpatterns = [
11) url(r'^admin/', admin.site.urls),
12) url(r'', include(router.urls)),
13) url(r'^get-api-token/', views.obtain_auth_token,name='get-api-token'),
14) ]
To over come this problem, we should go for JWT Authentication. The main advantage of
JWT Authentication over TokenAuthentication is database interaction is not required to
identify user. From the token itself, DRF can identify user, which improves performance
and scalability of the application.
Because of this advantage, JWTAuthentication is the most commonly used type of
authentication in real time.
djangorestframework-jwt
django-rest-framework-simplejwt
etc
1) Access Token:
☻ This token can used to access our end point. The default expiration time is 5 minutes.
Ofcourse, it is customizable.
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
77 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
1) from rest_framework_jwt.views import obtain_jwt_token
2) urlpatterns = [
3) ...
4)
5) url(r'^api-token-auth/', obtain_jwt_token),
6) ]
2) Refresh Token:
☻ Non-expired tokens can be "refreshed" to obtain a brand new token with renewed
expiration time. For this compulsory we should set JWT_ALLOW_REFRESH is True.
3) Verify Token:
☻ We can verify whether the token is expired or not by using the following url
configurations in urls.py.
☻ Passing a token to the verification endpoint will return a 200 response and the token if
it is valid. Otherwise, it will return a 400 Bad Request as well as an error identifying
why the token was invalid.
Note: This tokens and expiration time concept is required to provide security.
JWT Token holds more information than Tokens of TokenAuthentication.
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
78 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
How to implement JWT Authentication?
1) We have to install djangorestframework-jwt by using pip command.
pip install djangorestframework-jwt
2) We have to configure the following url-patterns to perform access token, refresh
token and verify token in urls.py file
urls.py
{
"token":
"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJ1c2VybmFtZSI6ImR1cmdhIiw
iZXhwIjoxNTQ4NjcyNzA5LCJlbWFpbCI6IiIsIm9yaWdfaWF0IjoxNTQ4NjcyNDA5fQ.OxAMEKb
HTH9Kyk1Lh6OXl7UAs8el_sSEiLb9vDpf03E"
}
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
79 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
From the postman tool:
POST http://127.0.0.1:8000/auth-jwt/
Body section:
Key: username value:durga
Key: password value:durga123
{
"token":
"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJ1c2VybmFtZSI6ImR1cmdhIiw
iZXhwIjoxNTQ4NjcyOTU2LCJlbWFpbCI6IiIsIm9yaWdfaWF0IjoxNTQ4NjcyNjU2fQ.8aKbA36Z
EcHtwWmbii48jUJuFHrzNA2qth6s3xOqw0M"
}
Refresh Token:
To perform refresh token compulsory we required to set JWT_ALLOW_REFRESH as True.
Inside settings.py the following configurations are required.
JWT_AUTH={
...
'JWT_ALLOW_REFRESH': True,
}
{
"token":
"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJ1c2VybmFtZSI6ImR1cmdhIiw
iZXhwIjoxNTQ4NjczNTUzLCJlbWFpbCI6IiIsIm9yaWdfaWF0IjoxNTQ4NjczMTgzfQ.a045-
Tl43mGGfsTK608p-UCN1s92lfjJjRzGKW-s9Xo"
}
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
80 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
Note: Refresh should be done before expiring the access token. Once access token we
cannot perform refresh.
{
"non_field_errors": [
"Signature has expired."
]
}
Headers section:
Key: Content-Type value: application/json
Body Section:
KEY: token
value:eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJ1c2VybmFtZSI6ImR1cm
dhIiwiZXhwIjoxNTQ4NjczNDgzLCJlbWFpbCI6IiIsIm9yaWdfaWF0IjoxNTQ4NjczMTgzfQ.tdC5
css67Ix8v4Tci4q5YjhobQoLnaSqOOh6wfl2qpk (existing access token)
{
"token":
"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJ1c2VybmFtZSI6ImR1cmdhIiw
iZXhwIjoxNTQ4Njc0MzgyLCJlbWFpbCI6IiIsIm9yaWdfaWF0IjoxNTQ4Njc0MDUwfQ.bQOZPD
1mTeT7yziBSCFkFSjvsoy0LxV9B9a8GyEVXlM"
}
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
81 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
Verify Token:
Passing a token to the verification endpoint will return a 200 response and the token if it
is valid. Otherwise, it will return a 400 Bad Request as well as an error identifying why the
token was invalid.
{
"token":
"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJ1c2VybmFtZSI6ImR1cmdhIiw
iZXhwIjoxNTQ4Njc0NTY1LCJlbWFpbCI6IiIsIm9yaWdfaWF0IjoxNTQ4Njc0MjY1fQ._Sx2JJ3FG
wV8Xt3Cj-qmEB4rbE0Z-iq6CpSWQVzRwwM"
}
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
82 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
From postman tool:
POST http://127.0.0.1:8000/auth-jwt-verify/
Headers section:
Key: Content-Type value: application/json
Body Section:
KEY: token
value:eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJ1c2VybmFtZSI6ImR1cm
dhIiwiZXhwIjoxNTQ4Njc0NTY1LCJlbWFpbCI6IiIsIm9yaWdfaWF0IjoxNTQ4Njc0MjY1fQ._Sx2
JJ3FGwV8Xt3Cj-qmEB4rbE0Z-iq6CpSWQVzRwwM
{
"non_field_errors": [
"Signature has expired."
]
}
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.
eyJ1c2VyX2lkIjoxLCJ1c2VybmFtZSI6ImR1cmdhIiwiZXhwIjoxNTQ4Njc0NTY1LCJlbWFpbCI6IiI
sIm9yaWdfaWF0IjoxNTQ4Njc0MjY1fQ.
_Sx2JJ3FGwV8Xt3Cj-qmEB4rbE0Z-iq6CpSWQVzRwwM
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
83 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
Note: The default JWT_AUTH_HEADER_PREFIX is JWT. But we can configured our own
prefix in settings.py as follows
JWT_AUTH={
....
'JWT_AUTH_HEADER_PREFIX':'Bearer'
}
'JWT_DECODE_HANDLER':
'rest_framework_jwt.utils.jwt_decode_handler',
'JWT_PAYLOAD_HANDLER':
'rest_framework_jwt.utils.jwt_payload_handler',
'JWT_PAYLOAD_GET_USER_ID_HANDLER':
'rest_framework_jwt.utils.jwt_get_user_id_from_payload_handler',
'JWT_RESPONSE_PAYLOAD_HANDLER':
'rest_framework_jwt.utils.jwt_response_payload_handler',
'JWT_SECRET_KEY': settings.SECRET_KEY,
'JWT_GET_USER_SECRET_KEY': None,
'JWT_PUBLIC_KEY': None,
'JWT_PRIVATE_KEY': None,
'JWT_ALGORITHM': 'HS256',
'JWT_VERIFY': True,
'JWT_VERIFY_EXPIRATION': True,
'JWT_LEEWAY': 0,
'JWT_EXPIRATION_DELTA': datetime.timedelta(seconds=300),
'JWT_AUDIENCE': None,
'JWT_ISSUER': None,
'JWT_ALLOW_REFRESH': False,
'JWT_REFRESH_EXPIRATION_DELTA': datetime.timedelta(days=7),
'JWT_AUTH_HEADER_PREFIX': 'JWT',
'JWT_AUTH_COOKIE': None,
}
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
84 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
JWT_AUTH = {
....
'JWT_EXPIRATION_DELTA': datetime.timedelta(seconds=300),
'JWT_ALLOW_REFRESH': False,
'JWT_REFRESH_EXPIRATION_DELTA': datetime.timedelta(days=7),
....
}
Process:
1) We have to write our Custom Authentication class by extending from
BaseAuthentication.
2) We have to override authenticate() method.
3) Returns a tuple of (user,None) for successful authentication
4) Raise AuthenticationFailed exception for failed authentication.
authentications.py
views.py
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
85 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
We can send request for the endpoint as follows
http://127.0.0.1:8000/api/?username=durga
Eg:
username: durga
secrete key: a7ZXd98
http://127.0.0.1:8000/api/?username=durga&key=a7ZXd98
authentications.py
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
86 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
views.py
OAUTH2 Authentication:
Just refer the following links and documentation to implement social authentication by
using OAUTH2.
https://github.com/RealmTeam/django-rest-framework-social-oauth2
https://python-social-auth.readthedocs.io/en/latest/
https://django-oauth-toolkit.readthedocs.io/en/latest/
https://aaronparecki.com/oauth-2-simplified/
Basic Authentication:
It is very easy to setup.
But it is not recommended for production and we can use this Basic Authentication just
for testing purpose.
With every request we have to send username and password in base 64 encoded format
with Authorization Header.
Eg: durga:durga123
Encoded string is : ZHVyZ2E6ZHVyZ2ExMjM=
views.py
1) ..
2) from rest_framework.authentication import BasicAuthentication
3) class EmployeeCRUDCBV(ModelViewSet):
4) queryset=Employee.objects.all()
5) serializer_class=EmployeeSerializer
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
87 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
6) authentication_classes=[BasicAuthentication,]
7) permission_classes=[IsAuthenticated,]
Headers Section:
Key: Authorization value: Basic ZHVyZ2E6ZHVyZ2ExMjM=
Note: We can do encoding of username and password in postman tool itself and we are
not required to use any third party websites.
GET http://localhost:8000/api/
Authorization Section:
Session Authentication:
Session Based authentication is the traditional authentication mechanism,what ever we
used in django.
Session authentication is implemented by the following class
rest_framework.authentication.SessionAuthentication
Internally authentication will be performed by Django inbuilt auth application.
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
88 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
Demo Application:
models.py
admin.py
serializers.py
views.py
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
89 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
11) permission_classes=[IsAuthenticated,]
projectname/templates/registration/login.html
1) <!DOCTYPE html>
2) <html lang="en" dir="ltr">
3) <head>
4) <meta charset="utf-8">
5) <title></title>
6) </head>
7) <body>
8) <h1>Login to access API</h1><hr>
9) <form method="post">
10) {%csrf_token%}
11) {{form.as_p}}
12) <button type="submit" >Login</button>
13) </form>
14) </body>
15) </html>
urls.py
settings.py
1) INSTALLED_APPS = [
2) ....,
3) 'rest_framework',
4) 'testapp'
5) ]
6) TEMPLATE_DIR=os.path.join(BASE_DIR,'templates')
7) ...
8) TEMPLATES = [
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
90 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
9) {
10) 'BACKEND': 'django.template.backends.django.DjangoTemplates',
11) 'DIRS': [TEMPLATE_DIR],
12) ...
13) },
14) ]
15) LOGIN_REDIRECT_URL='/api/'
DRF-Pagination:
Pagination is the splitting of large datasets into separated pages.
Whenever we are performing list operation(GET), if the number of resources is very huge,
then we should go for pagination.
1) PageNumberPagination
2) LimitOffsetPagination
3) CursorPagination
1) REST_FRAMEWORK={
2) 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.
PageNumberPagination',
3) 'PAGE_SIZE':10,
4) }
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
91 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
This pagination is applicable for all view classes.
Note: default pagination concept is avaialble only for generic views and viewsets. If we
are using regular APIView, then we have to write pagination code explicitly.
admin.py
serializers.py
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
92 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
pagination.py
views.py
urls.py
populate.py
This script can be used to populate Employee table with fake data by using faker and
random modules
1) import os
2) os.environ.setdefault('DJANGO_SETTINGS_MODULE','paginationproject1.settings')
3) import django
4) django.setup()
5)
6) from testapp.models import *
7) from faker import Faker
8) from random import *
9) faker=Faker()
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
93 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
10) def populate(n):
11) for i in range(n):
12) feno=randint(1001,9999)
13) fename=faker.name()
14) fesal=randint(10000,20000)
15) feaddr=faker.city()
16) emp_record=Employee.objects.get_or_create(eno=feno,ename=fename,esal=f
esal,eaddr=feaddr)
17) populate(120)
2) page_query_param:
A string value indicating the name of the query parameter to use for the pagination
control. The default value is 'page'
http://127.0.0.1:8000/api/?page=4
Eg: page_query_param='mypage'
http://127.0.0.1:8000/api/?mypage=4
3) page_size_query_param:
If set, this is a string value indicating the name of a query parameter that allows the
client to set the page size on a per-request basis. Defaults to None, indicating that the
client may not control the requested page size.
Eg: page_size_query_param = 'required_page_size'
http://127.0.0.1:8000/api/?required_page_size=10
4) max_page_size:
If set, this is a numeric value indicating the maximum allowable requested page size.
This attribute is only valid if page_size_query_param is also set. If client requesting
page size which is greater than this value then only max_page_size will be considered.
5) last_page_strings:
A list or tuple of string values indicating values that may be used with the
page_query_param to request the final page in the set. Default value is ('last',)
Eg: last_page_strings = ('end_page',)
http://127.0.0.1:8000/api/?page=end_page
http://127.0.0.1:8000/api/?required_page_size=10&page=end_page
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
94 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
2) LimitOffsetPagination:
If the partner application (client application) wants a limited number of resources
starts from the given offset then we should go for LimitOffsetPagination.
Eg: Client application required 20 resources starts from offset 10 (i.e from 10th index
onwards)
http://127.0.0.1:8000/api/?limit=20&offset=10
It returns the resources from 11th id to 30th id.
Note: The offset is zero based. i.e the offset of first record is 0
views.py
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
95 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
3) offset_query_param: It represents the query parameter name which can be used
to provide offset value by the client. The default parameter name is 'offset'
4) max_limit: We can use this parameter to limit maximum number of resources per
page.If the client requests more than this value then, it returns the number of
resources specified by max_limit only.
3) CursorPagination:
If we want resources based on some 'ordering' then we should go for
CursorPagination.
Eg: To get aAll records according to ascending order of employee salaries but 5
resources per page.
views.py
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
96 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
3) cursor_query_param:
It can be used to specify the name of the cursor query parameter. Default value is
'cursor'
GET /api/?cursor=cD0xOTQwNi4w
HTTP 200 OK
Allow: GET, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept
{
"next": "http://127.0.0.1:8000/api/?cursor=cD0xODczMy4w",
"previous": "http://127.0.0.1:8000/api/?cursor=cj0xJnA9MTkzNTYuMA%3D%3D",
"results": [
{
"id": 27,
"eno": 1354,
"ename": "David Reid",
....
}
Eg: cursor_query_param='mycursor'
GET /api/?mycursor=cD0xOTQwNi4w
HTTP 200 OK
Allow: GET, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept
{
"next": "http://127.0.0.1:8000/api/?mycursor=cD0xODczMy4w",
"previous": "http://127.0.0.1:8000/api/?mycursor=cj0xJnA9MTkzNTYuMA%3D%3D",
"results": [
{
"id": 27,
"eno": 1354,
"ename": "David Reid",
...
}
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
97 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
PageNumberPagination vs LimitOffsetPagination vs
CursorPagination:
1) If we want all resources page by page then we should go for PageNumberPagination.
Here we can specify only page_size and we cannot specify offset and ordering.
2) If we want the resources based on specified limit and offset then we should go for
LimitOffsetPagination. Here we have choice to specify offset value from where we
have to consider resources. We cannot specify ordering.
3) If we want all resources based on some ordering then we should go for
CursorPagination. Here we can specify page_size and orderning and we cannot specify
offset value.
DRF-Filtering:
We can implement Search/Filter operation in the following 2 ways
1) Planin Vanilla Filtering
2) By using Django RestFramework API
views.py
1) class EmployeeAPIView(generics.ListAPIView):
2) #queryset =Employee.objects.all()
3) serializer_class =EmployeeSerializer
4) def get_queryset(self):
5) qs=Employee.objects.all()
6) name=self.request.GET.get('ename')
7) if name is not None:
8) qs=qs.filter(ename__icontains=name)
9) return qs
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
98 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
For the request: http://127.0.0.1:8000/api/?ename=Jhon
Returns Employee records where ename contains 'Jhon'.
In this case the records will be filtered.
The default value for 'SEARCH_PARAM' is 'search', which can be used by partner
application to send value for the search.
Note:
1) search_fields=('eno',)
http://127.0.0.1:8000/api/?mysearch=2
It returns all Employee records where eno contains '2'
2) search_fields=('=eno',)
http://127.0.0.1:8000/api/?mysearch=2
It returns all Employee records where eno is exactly equals to '2'
3) search_fields=('^eno',)
http://127.0.0.1:8000/api/?mysearch=2
It returns all Employee records where eno is starts with '2'
Note:
'=' means exact match
'^' means starts with
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
99 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
Note: search_fields=('eno$',)
ends with specified digit --->won't work
settings.py
1) REST_FRAMEWORK={
2) 'DEFAULT_FILTER_BACKENDS':('rest_framework.filters.SearchFilter','rest_framewo
rk.filters.OrderingFilter'),
3) 'SEARCH_PARAM':'mysearch',
4) 'ORDERING_PARAM':'myordering'
5) }
Ordering
ID - ascending
ID - descending
Eno - ascending
Eno - descending
Ename - ascending
Ename - descending
Esal - ascending
Esal - descending
Eaddr - ascending
Eaddr - descending
But, we can specify our own ordering fields also based on our requirement.
class EmployeeAPIView(generics.ListAPIView):
queryset =Employee.objects.all()
serializer_class =EmployeeSerializer
search_fields=('ename',)
ordering_fields=('eno','esal')
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
100 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
ordering based on spcified parameters.
Client can send request with search and ordering parameters as follows
http://127.0.0.1:8000/api/?mysearch=R
http://127.0.0.1:8000/api/?myordering=-esal
http://127.0.0.1:8000/api/?mysearch=R&myordering=-esal
Nested Serializers:
Sometimes we can use one serializer inside another serializer to serialize dependent
Model fields, such type of serializers are called Nested Serializers.
If Model mappings are there (like OneToOne, ManyToOne, ManyToMany) then we should
go for Nested Serializers.
Eg 1: Assume there are two Models named with Author and Book. Book model has
ForiegnKey reference to Author. While listing Author information, the corresponding
Books information also required to provide. Hence inside AuthorSerializer, we required
use BookSerializer. This concept is nothing but Nested Serializers.
Syntax:
class AuthorSerializer(serializers.ModelSerializer):
books_by_author = BookSerializer(read_only=True,many=True)
....
Eg 2: Assume there are two Models named with Musician and Album. Album model has
ForiegnKey reference to Musician. While listing Musician information, the corresponding
Albums information also required to provide. Hence inside MusicianSerializer, we
required use AlbumSerializer. This concept is nothing but Nested Serializers.
Syntax:
class MusicianSerializer(serializers.ModelSerializer):
albums_by_musician = AlbumSerializer(read_only=True,many=True)
....
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
101 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
Complete Demo Application-1:
models.py
admin.py
serializers.py
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
102 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
10) class Meta:
11) model=Author
12) fields='__all__'
views.py
urls.py
setttings.py
1) INSTALLED_APPS = [
2) ...
3) 'rest_framework',
4) 'testapp'
5) ]
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
103 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
In the above example, whenever we are sending the request to Author API, it will display
Author information including corresponding Books information also.
Demo Application-2:
models.py
admin.py
serializers.py
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
104 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
8) class MusicianSerializer(serializers.ModelSerializer):
9) album_musician=AlbumSerializer(read_only=True,many=True)
10) class Meta:
11) model=Musician
12) # fields=('first_name','last_name','instrument','album_musician')
13) fields='__all__'
views.py
urls.py
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
105 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
settings.py
1) INSTALLED_APPS = [
2) ...
3) 'rest_framework',
4) 'testapp'
5) ]
In the above example, whenever we are sending the request to Musician API, it will
display Musician information including corresponding album information also.
http://api.ipstack.com/183.82.219.127?access_key=3dc63ae05b2288d3bdb6ceaf97f18505
{"ip":"183.82.219.127","type":"ipv4","continent_code":"AS","continent_name":"Asia","c
ountry_code":"IN","country_name":"India","region_code":"TG","region_name":"Telanga
na","city":"Prakashamnagar","zip":"500016","latitude":17.4427,"longitude":78.4751,"loc
ation":{"geoname_id":10524299,"capital":"New
Delhi","languages":[{"code":"hi","name":"Hindi","native":"\u0939\u093f\u0928\u094d\
u0926\u0940"},{"code":"en","name":"English","native":"English"}],"country_flag":"http:\
/\/assets.ipstack.com\/flags\/in.svg","country_flag_emoji":"\ud83c\uddee\ud83c\uddf3
","country_flag_emoji_unicode":"U+1F1EE U+1F1F3","calling_code":"91","is_eu":false}}
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
106 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
Demo Application:
views.py
projectname/templates/testapp/info.html
1) <!DOCTYPE html>
2) <html lang="en" dir="ltr">
3) <head>
4) <meta charset="utf-8">
5) <title></title>
6) </head>
7) <body>
8) <h1>Consuming External API Demo</h1><hr>
9) <h2>Your Geographic Information</h2>
10) <h3>Your IP Address:{{ip}}</h3>
11) <h3>Your continent_name:{{continent_name}}</h3>
12) <h3>Your country_name:{{country_name}}</h3>
13) <h3>Your region_name:{{region_name}}</h3>
14) <h3>Your city:{{city}}</h3>
15) <h3>Your zip:{{zip}}</h3>
16) <h3>Your longitude:{{longitude}}</h3>
17) <h3>Your latitude:{{latitude}}</h3>
18) </body>
19) </html>
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
107 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
urls.py
Note:
venkataprasad.pythonanywhere.com/info
venkataprasad
prasad1247
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
108 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
|-urls.py
|-admin.py
models.py
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
109 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
admin.py
testapp/views.py
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
110 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
21) def blorejobs(request):
22) return render(request,'testapp/blorejobs.html')
23)
24) def punejobs(request):
25) return render(request,'testapp/punejobs.html')
26)
27) def chennaijobs(request):
28) return render(request,'testapp/chennaijobs.html')
index1.html
1) <!DOCTYPE html>
2) {%load staticfiles%}
3) <html lang="en" dir="ltr">
4) <head>
5) <meta charset="utf-8">
6) <title></title>
7) <!-- Latest compiled and minified CSS -->
8) <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/cs
s/bootstrap.min.css" integrity="sha384-
BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" c
rossorigin="anonymous">
9) <link rel="stylesheet" href="{%static "css/newfile.css"%}">
10) </head>
11) <body>
12) <div class="container" align='center'>
13) <div class="jumbotron">
14) <h1>WELCOME TO DURGAJOBS</h1>
15) <p>continuous Job Updates for every hour...</p>
16) <a href="/hydjobs" class='btn btn-primary btn-lg'>HYD JOBS</a>
17) <a href="#" class='btn btn-primary btn-lg'>BANGALORE JOBS</a>
18) <a href="#" class='btn btn-primary btn-lg'>PUNE JOBS</a>
19) <a href="#" class='btn btn-primary btn-lg'>CHENNAI JOBS</a>
20) </div>
21) </div>
22) </body>
23) </html>
hydjobs.html
1) <!DOCTYPE html>
2) {%load staticfiles%}
3) <html lang="en" dir="ltr">
4) <head>
5) <meta charset="utf-8">
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
111 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
6) <link rel="stylesheet" href="{% static "css/demodjproject.css" %}">
7) <title></title>
8) </head>
9) <body>
10) <h1>Hyderabad Jobs Information</h1>
11)
12) <img src="{%static "images/hyd2.jpg"%}" alt="">
13) <img src="{%static "images/hyd1.jpg"%}" alt="">
14) <img src="{%static "images/hyd3.jpg"%}" alt="">
15) <hr>
16) {% if jobs_list %}
17) <table id='tab'>
18) <thead>
19) <th>Date</th>
20) <th>Company</th>
21) <th>Title</th>
22) <th>Eligibility</th>
23) <th>Address</th>
24) <th>Email</th>
25) <th>Phone Number</th>
26) </thead>
27) {%for job in jobs_list %}
28) <tr>
29) <td>{{job.date}}</td>
30) <td>{{job.company}}</td>
31) <td>{{job.title}}</td>
32) <td>{{job.eligibility}}</td>
33) <td>{{job.address}}</td>
34) <td>{{job.email}}</td>
35) <td>{{job.phonenumber}}</td>
36) </tr>
37) {% endfor %}
38) </table>
39) {%include 'testapp/pagination.html' with page=jobs_list%}
40) {%else %}
41) <p>No Jobs Found in Hyderabad</p>
42) {% endif %}
43) </body>
44) </html>
pagination.html
1) <div class="paginator">
2) <span>
3) {%if page.has_previous%}
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
112 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
4) <a href="?page={{page.previous_page_number}}">Previous</a>
5) {%endif%}
6) </span>
7) <span class='current'>
8) page {{page.number}} of {{page.paginator.num_pages}}
9) </span>
10) <span>
11) {%if page.has_next%}
12) <a href="?page={{page.next_page_number}}">Next</a>
13) {%endif%}
14) </span>
15) </div>
newfile.css
1) body{
2) background: url(https://images.unsplash.com/photo-1512665591-
75fa7ba868d7?ixlib=rb-
0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=9fff1ea450ba4c7242b1bd207630469f&aut
o=format&fit=crop&w=667&q=80);
3) }
4) .container .jumbotron{
5) margin-top: 200px;
6) background: red;
7) color:white;
8) }
9) .container .jumbotron a{
10) background:yellow;
11) color:blue;
12) border:2px solid green;
13) }
demodjproject.css
1) .container .jumbotron{
2) background: red;
3) color:white;
4) }
5) body{
6) background: url(https://images.unsplash.com/photo-1512665591-
75fa7ba868d7?ixlib=rb-
0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=9fff1ea450ba4c7242b1bd207630469f&aut
o=format&fit=crop&w=667&q=80)
7) }
8) .container{
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
113 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
9) margin-top: 200px;
10) }
11) .jumbotron a{
12) background: yellow;
13) color:red;
14) border:2px solid green;
15) }
16) img{
17) height: 200px;
18) width:30%;
19) float:left;
20) margin:1.5%;
21) border:2px solid red;
22) }
23) .imagesb
24) {
25) border:3px solid red;
26) }
27) h1{
28) color:white;
29) text-align: center;
30) background:red;
31) }
32) table,thead,th,tr,td{
33) color:yellow;
34) border:2px solid white;
35) font-size: 20px;
36) margin:auto;
37) background:red;
38) }
39) thead,th{
40) color:white;
41) border:2px solid white;
42) font-size: 20px;
43) margin:auto;
44) background:blue;
45) }
settings.py
1) TEMPLATE_DIR=os.path.join(BASE_DIR,'templates')
2) STATIC_DIR=os.path.join(BASE_DIR,'static')
3) INSTALLED_APPS = [
4) ...
5) 'rest_framework',
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
114 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
6) 'testapp'
7) ]
8) TEMPLATES = [
9) {
10) 'BACKEND': 'django.template.backends.django.DjangoTemplates',
11) 'DIRS': [TEMPLATE_DIR],
12)
13) STATIC_URL = '/static/'
14) STATICFILES_DIRS=[
15) STATIC_DIR,
16) ]
API Development
testapp/api/serializers.py
testapp/api/views.py
testapp/api/urls.py
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
115 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
project level urls.py
'rest_framework_swagger'
url(r'^docs/$',schema_view)
Step 1:
$ pip install django-rest-swagger
Step 2:
Add 'rest_framework_swagger' to INSTALLED_APPS in Django
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
116 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com
settings.py
1) INSTALLED_APPS = [
2) ...
3) 'rest_framework_swagger',
4) ...
5) ]
Step 3:
open urls.py file and add the code like
nd
DURGASOFT, # 202, 2 Floor, HUDA Maitrivanam, Ameerpet, Hyderabad - 500038,
117 040 – 64 51 27 86, 80 96 96 96 96, 92 46 21 21 43 | www.durgasoft.com