Django Rest API PDF
Django Rest API PDF
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
Note:
1) In the case of POST, PUT and PATCH Requests,we have to provide input data as the
part of Body in Postman.
2) Authentication information we have to provide in Headers part in 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:
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