Blog > Develop RESTful API with Django Ninja.

Card image cap

Develop RESTful API with Django Ninja.

  • Sept. 15, 2022, 3:03 p.m.

Django Ninja is a web framework for building APIs with Django and Python 3.6+ type hints.

Key features:

  • Easy: Designed to be easy to use and intuitive.
  • FAST execution: Very high performance thanks to Pydantic and async support.
  • Fast to code: Type hints and automatic docs lets you focus only on business logic.
  • Standards-based: Based on the open standards for APIs: OpenAPI (previously known as Swagger) and JSON Schema.
  • Django friendly: (obviously) has good integration with the Django core and ORM.
  • Production ready: Used by multiple companies on live projects (If you use Django Ninja and would like to publish your feedback, please email ppr.vitaly@gmail.com).

Benchmarks:

Django Ninja REST Framework

Installation

pip install django-ninja

Create a Django Ninja project

(If you already have an existing Django project, skip to the next step).

Start a new Django project (or use an existing one).

We are going to create the Project by the name of sample_api, our project will provide API for creating contracts and Retrieving contacts.

django-admin startproject sample_api

First steps

Let's create An App for all main operations in our Sample_api project, by the name of core

django-admin startapp core

Then our core app will have the following files: __init__.py   admin.py  models.py
  tests.py  apps.py and views.py

now we need to add models in the models.py file, but let's get to know some details about Django Models because Django Ninja uses Models from Django Framework.

Models

A model is the single, definitive source of information about your data. It contains the essential fields and behaviors of the data you’re storing. Generally, each model maps to a single database table.

The basics:

  • Each model is a Python class that subclasses django.db.models.Model.
  • Each attribute of the model represents a database field.
  • With all of this, Django gives you an automatically-generated database-access API; see Making queries.

During model creation we use Fields, let's get to know about Models Fields

Fields

The most important part of a model – and the only required part of a model – is the list of database fields it defines. Fields are specified by class attributes. Be careful not to choose field names that conflict with the models API like cleansave, or delete.

Field types

Each field in your model should be an instance of the appropriate Field class. Django uses the field class types to determine a few things:

  • The column type, which tells the database what kind of data to store (e.g. INTEGERVARCHARTEXT).
  • The default HTML widget to use when rendering a form field (e.g. <input type="text"><select>).
  • The minimal validation requirements, used in Django’s admin and in automatically-generated forms.

Django ships with dozens of built-in field types; you can find the complete list in the model field reference. You can easily write your own fields if Django’s built-in ones don’t do the trick; see How to create custom model fields.

Field options

Each field takes a certain set of field-specific arguments (documented in the model field reference). For example, CharField (and its subclasses) require a max_length the argument which specifies the size of the VARCHAR database field used to store the data.

There’s also a set of common arguments available to all field types. All are optional. They’re fully explained in the reference, but here’s a quick summary of the most often-used ones:

null

If True, Django will store empty values as NULL in the database. Default is False.

blank
If True, the field is allowed to be blank. Default is False.
Note that this is different than nullnull is purely database-related, whereas blank is validation-related. If a field has blank=True, form validation will allow entry of an empty value. If a field has blank=False, the field will be required.
 
Now let's create our core app models.py
core/models.py:

Using models

Once we have defined your models, we need to tell Django we’re going to use those models. we do this by editing our settings file and changing the INSTALLED_APPS setting to add the name of the module that contains our models.py.

For example, if the models for your application live in the module myapp.models (the package structure that is created for an application by the manage.py startapp script), 
INSTALLED_APPS
 should read, in part:

INSTALLED_APPS = [
    #...
    'core',
    #...
]

When you add new apps to INSTALLED_APPS, be sure to run manage.py migrate, optionally making migrations for them first with manage.py makemigrations.

Now we have the Database model by the name of Contact, then after creating the model we need to make migrations and migrating so as to create a database table and persist the changes of our project.

python manage.py makemigrations

Then we need to migrate:

python manage.py migrate

Second Step we need to create Schema based on our Models.py, but let's get to know about Schema

Schemas from Django models

Schemas are very useful to define our validation rules and responses, but sometimes we need to reflect your database models into schemas and keep changes in sync.

ModelSchema

ModelSchema is a special base class that can automatically generate schemas from models.

All we need is to set model and model_fields attributes on our schema Config

 

Using ALL model fields

To use all fields from a model - we can pass __all__ to model_field

Excluding model fields

To use all fields except a few, we can use model_exclude configuration

Overriding fields

To change default annotation for some field, or to add a new field, we just use annotated attributes as usual.

Now let's create our Schema.

core/schema.py

After creating our schema now let's create our views.py, but before we create it lets get some introduction about Django views

Writing views

A view function, or view for short, is a Python function that takes a web request and returns a web response. This response can be the HTML contents of a web page, or a redirect, or a 404 error, or an XML document, or an image . . . or anything, really. The view itself contains whatever arbitrary logic is necessary to return that response. This code can live anywhere we want, as long as it’s on our Python path. There’s no other requirement–no “magic,” so to speak. For the sake of putting the code somewhere, the convention is to put views in a file called views.py, placed in your project or application directory.

In our project we are going to use class-based views, so let's get some intro about class-based views.

class-based views

Class-based views provide an alternative way to implement views as Python objects instead of functions. They do not replace function-based views, but have certain differences and advantages when compared to function-based views:

  • Organization of code related to specific HTTP methods (GETPOST, etc.) can be addressed by separate methods instead of conditional branching.
  • Object-oriented techniques such as mixins (multiple inheritances) can be used to factor code into reusable components.

At its core, a class-based view allows us to respond to different HTTP request methods with different class instance methods, instead of with conditionally branching code inside a single view function.

our views - core/views.py:

Now we have our views the next step is to create, APIs based on created views so as to create and retrieve contacts to and from the database.

To create API from our core app we need to use Routers.

Routers

Real-world applications can almost never fit all logic into a single file.

Django Ninja comes with an easy way to split your API into multiple modules using Routers.

To add API's to each of the Django applications, we create a api.py module in each app

There are also times when you need to split your logic up even more. Django Ninja makes it possible to include a router into another router as many times as you like, and finally include the top-level router into the main API instance.

Defining operation methods

"Operation" can be one of the HTTP "methods":

  • GET
  • POST
  • PUT
  • DELETE
  • PATCH
  • ... and more

Django Ninja comes with a decorator for each method:

@api.get("/path")
def get_operation(request):
    ...

@api.post("/path")
def post_operation(request):
    ...

@api.put("/path")
def put_operation(request):
    ...

@api.delete("/path")
def delete_operation(request):
    ...

@api.patch("/path")
def patch_operation(request):
    ...

If you need to handle multiple methods with a single function for a given path, you can use the api_operation method:

@api.api_operation(["POST", "PATCH"], "/path")
def mixed(request):
    ...

This feature can also be used to implement other HTTP methods that don't have corresponding django-ninja methods, such as HEAD or OPTIONS.

@api.api_operation(["HEAD", "OPTIONS"], "/path")
def mixed(request):
    ...

let's see our core/api.py:

now we have our core app APIs, the thing that remains is to add our APIs to the main project sample_api/urls.py:

After all of these processes, now we need to start our project so as to view our APIs for testing.

to start the project we need to run the following command:


python manage.py runserver

to view APIs, we need to go to the browser and write http://127.0.0.1:8000/api/docs

by adding /docs this will provide us Swagger UI which is user friendly for API testing

 

Thanks,

Any suggestions, questions leave in the comment area below or email me via mail@ismohamedi.dev

 The whole project source code is available on Github  Sample APIs Github and LIVE view   Sample APIs LIVE

 

Blog Comments

Comments

Группа объявления в Иркутске в телеграмм. Размещение частных объявлений бесплатно! Коммерческие и рекламные объявления, согласно правил группы. #Иркутск #ОбъявленияИркутск #БесплатныеОбъявления #объявление #доскаобъявлений #барахолка #телеграм #телеграмм #telegram Присоединяйся, чтобы быть в курсе... объявление в Иркутске куплю Чаты остальных можно увидеть здесь!! бесплатные объявления

1976 on: Aug. 6, 2024, 2:24 p.m.

https://justpaste.it/b22ns

GalenCrepeXZ on: June 17, 2024, 1:41 a.m.

<a href="https://blyadsk.ru/">интим досуг в иркутске</a>

RickyPakLU on: June 12, 2024, 9:45 p.m.

<a href="https://sex-138.ru/">sex-138.ru</a>

AllanbotGZ on: June 11, 2024, 2:06 a.m.

<a href="https://dosuchki1.ru">проститутки индивидуалки иркутск</a>

BrandonEcoriQV on: June 10, 2024, 5:28 a.m.

<a href="https://love74.ru/">снять проститутку</a>

GarrettcoonsWJ on: June 8, 2024, 1:45 a.m.

<a href="https://sosamba-spb1.ru/sadovaya">проститутки садовая</a>

CarmineidopsVT on: June 7, 2024, 8:14 a.m.

http://sniperprojects.freehostia.com/e107_plugins/forum/forum_viewtopic.php?735003.last

WilliammaimeFS on: June 6, 2024, 5:42 a.m.

https://post.news/@/fishingtri

DwayneAffipIH on: May 31, 2024, 2:05 a.m.

https://avenue18.ru/

EdwardassofDI on: May 29, 2024, 4:17 p.m.

https://1x-bet-india.com

MicahSpivaDF on: April 27, 2024, 4:08 a.m.

It is interesting. Tell to me, please - where I can read about it?

Avenue 17HC on: April 25, 2024, 11:25 a.m.

https://www.shtfsocial.com/rentcarfycom

FelixpalKI on: April 24, 2024, 2:53 a.m.

<a href="https://wedding-como.com/">оператор на свадьбу комо италия</a>

DavidhorKU on: April 21, 2024, 2:20 a.m.

https://virtual-local-numbers.com/countries/21-mexico.html

RobertMorSM on: April 20, 2024, 6:39 a.m.

123456

123456'/**/and/**/DBMS_PIPE.RECEIVE_MESSAGE('y',2)='y on: Jan. 18, 2024, 6:30 p.m.

123456

123456'/**/and/**/DBMS_PIPE.RECEIVE_MESSAGE('p',0)='p on: Jan. 18, 2024, 6:30 p.m.

123456

123456/**/and/**/0=DBMS_PIPE.RECEIVE_MESSAGE('u',2) on: Jan. 18, 2024, 6:30 p.m.

123456

123456/**/and/**/4=DBMS_PIPE.RECEIVE_MESSAGE('z',0) on: Jan. 18, 2024, 6:30 p.m.

123456

123456'and(select+1)>0waitfor/**/delay'0:0:2 on: Jan. 18, 2024, 6:30 p.m.

123456

123456'and(select+1)>0waitfor/**/delay'0:0:0 on: Jan. 18, 2024, 6:30 p.m.

123456

123456/**/and(select+1)>0waitfor/**/delay'0:0:2'/**/ on: Jan. 18, 2024, 6:30 p.m.

123456

123456/**/and(select+1)>0waitfor/**/delay'0:0:0'/**/ on: Jan. 18, 2024, 6:30 p.m.

123456

123456'/**/and(select'1'from/**/pg_sleep(2))::text>'0 on: Jan. 18, 2024, 6:30 p.m.

123456

123456'/**/and(select'1'from/**/pg_sleep(0))::text>'0 on: Jan. 18, 2024, 6:30 p.m.

123456

123456/**/and(select+1/**/from/**/pg_sleep(2))>0/**/ on: Jan. 18, 2024, 6:30 p.m.

123456

123456/**/and(select+1/**/from/**/pg_sleep(0))>0/**/ on: Jan. 18, 2024, 6:30 p.m.

123456

123456"and(select*from(select+sleep(2))a/**/union/**/select+1)=" on: Jan. 18, 2024, 6:30 p.m.

123456

123456"and(select*from(select+sleep(0))a/**/union/**/select+1)=" on: Jan. 18, 2024, 6:30 p.m.

123456

123456'and(select*from(select+sleep(2))a/**/union/**/select+1)=' on: Jan. 18, 2024, 6:30 p.m.

123456

123456'and(select*from(select+sleep(0))a/**/union/**/select+1)=' on: Jan. 18, 2024, 6:30 p.m.

123456

(select*from(select+sleep(2)union/**/select+1)a) on: Jan. 18, 2024, 6:30 p.m.

123456

(select*from(select+sleep(0)union/**/select+1)a) on: Jan. 18, 2024, 6:30 p.m.

123456

123456"and"z"="h on: Jan. 18, 2024, 6:30 p.m.

123456

123456"and"g"="g on: Jan. 18, 2024, 6:30 p.m.

123456

123456'and's'='t on: Jan. 18, 2024, 6:30 p.m.

123456

123456'and'r'='r on: Jan. 18, 2024, 6:30 p.m.

123456

123456/**/and+0=8 on: Jan. 18, 2024, 6:30 p.m.

123456

123456/**/and+3=3 on: Jan. 18, 2024, 6:30 p.m.

123456'/**/and/**/DBMS_PIPE.RECEIVE_MESSAGE('o',2)='o

123456 on: Jan. 18, 2024, 6:30 p.m.

123456'/**/and/**/DBMS_PIPE.RECEIVE_MESSAGE('d',0)='d

123456 on: Jan. 18, 2024, 6:30 p.m.

123456

123456'"\( on: Jan. 18, 2024, 6:30 p.m.

123456/**/and/**/4=DBMS_PIPE.RECEIVE_MESSAGE('p',2)

123456 on: Jan. 18, 2024, 6:30 p.m.

123456

123456鎈'"\( on: Jan. 18, 2024, 6:30 p.m.

123456/**/and/**/3=DBMS_PIPE.RECEIVE_MESSAGE('g',0)

123456 on: Jan. 18, 2024, 6:30 p.m.

123456

123456'and/**/convert(int,sys.fn_sqlvarbasetostr(HashBytes('MD5','1512539544')))>'0 on: Jan. 18, 2024, 6:30 p.m.

123456'and(select+1)>0waitfor/**/delay'0:0:2

123456 on: Jan. 18, 2024, 6:30 p.m.

123456

convert(int,sys.fn_sqlvarbasetostr(HashBytes('MD5','1818486092'))) on: Jan. 18, 2024, 6:30 p.m.

123456'and(select+1)>0waitfor/**/delay'0:0:0

123456 on: Jan. 18, 2024, 6:30 p.m.

123456

123456/**/and/**/cast(md5('1131592440')as/**/int)>0 on: Jan. 18, 2024, 6:30 p.m.

123456/**/and(select+1)>0waitfor/**/delay'0:0:2'/**/

123456 on: Jan. 18, 2024, 6:30 p.m.

123456

123456'and(select'1'from/**/cast(md5(1104135831)as/**/int))>'0 on: Jan. 18, 2024, 6:30 p.m.

123456/**/and(select+1)>0waitfor/**/delay'0:0:0'/**/

123456 on: Jan. 18, 2024, 6:30 p.m.

123456

extractvalue(1,concat(char(126),md5(1777691728))) on: Jan. 18, 2024, 6:30 p.m.

123456'/**/and(select'1'from/**/pg_sleep(2))::text>'0

123456 on: Jan. 18, 2024, 6:30 p.m.

123456

123456"and/**/extractvalue(1,concat(char(126),md5(1533601842)))and" on: Jan. 18, 2024, 6:30 p.m.

123456'/**/and(select'1'from/**/pg_sleep(0))::text>'0

123456 on: Jan. 18, 2024, 6:30 p.m.

123456

123456'and/**/extractvalue(1,concat(char(126),md5(1676954526)))and' on: Jan. 18, 2024, 6:30 p.m.

123456/**/and(select+1/**/from/**/pg_sleep(2))>0/**/

123456 on: Jan. 18, 2024, 6:30 p.m.

123456/**/and(select+1/**/from/**/pg_sleep(0))>0/**/

123456 on: Jan. 18, 2024, 6:30 p.m.

123456"and(select*from(select+sleep(2))a/**/union/**/select+1)="

123456 on: Jan. 18, 2024, 6:30 p.m.

123456"and(select*from(select+sleep(0))a/**/union/**/select+1)="

123456 on: Jan. 18, 2024, 6:30 p.m.

123456'and(select*from(select+sleep(2))a/**/union/**/select+1)='

123456 on: Jan. 18, 2024, 6:30 p.m.

123456'and(select*from(select+sleep(0))a/**/union/**/select+1)='

123456 on: Jan. 18, 2024, 6:30 p.m.

<%- 900434287+991209460 %>

123456 on: Jan. 18, 2024, 6:30 p.m.

(select*from(select+sleep(2)union/**/select+1)a)

123456 on: Jan. 18, 2024, 6:30 p.m.

123456

expr 907716840 + 862912972 on: Jan. 18, 2024, 6:30 p.m.

(select*from(select+sleep(0)union/**/select+1)a)

123456 on: Jan. 18, 2024, 6:30 p.m.

#set($c=863851269+869585257)${c}$c

123456 on: Jan. 18, 2024, 6:30 p.m.

123456

123456&set /A 950869263+996425648 on: Jan. 18, 2024, 6:30 p.m.

123456

123456 on: Jan. 18, 2024, 6:30 p.m.

${(846736249+822183643)?c}

123456 on: Jan. 18, 2024, 6:30 p.m.

123456'"\(

123456 on: Jan. 18, 2024, 6:30 p.m.

123456

123456$(expr 994346371 + 909436220) on: Jan. 18, 2024, 6:30 p.m.

123456

123456 on: Jan. 18, 2024, 6:30 p.m.

${890890727+801776975}

123456 on: Jan. 18, 2024, 6:30 p.m.

123456鎈'"\(

123456 on: Jan. 18, 2024, 6:30 p.m.

123456

123456|expr 806242837 + 901219516 on: Jan. 18, 2024, 6:30 p.m.

123456

123456 on: Jan. 18, 2024, 6:30 p.m.

/*1*/{{830739370+962934228}}

123456 on: Jan. 18, 2024, 6:30 p.m.

123456'and/**/convert(int,sys.fn_sqlvarbasetostr(HashBytes('MD5','1269860965')))>'0

123456 on: Jan. 18, 2024, 6:30 p.m.

123456

123456 expr 883813331 + 937517967 on: Jan. 18, 2024, 6:30 p.m.

123456"and"p"="v

123456 on: Jan. 18, 2024, 6:30 p.m.

123456

<%- 854797950+881558199 %> on: Jan. 18, 2024, 6:30 p.m.

convert(int,sys.fn_sqlvarbasetostr(HashBytes('MD5','1487053833')))

123456 on: Jan. 18, 2024, 6:30 p.m.

123456

#set($c=900606529+876609190)${c}$c on: Jan. 18, 2024, 6:30 p.m.

123456"and"o"="o

123456 on: Jan. 18, 2024, 6:30 p.m.

123456/**/and/**/cast(md5('1067385058')as/**/int)>0

123456 on: Jan. 18, 2024, 6:30 p.m.

123456

${(842931786+801774442)?c} on: Jan. 18, 2024, 6:30 p.m.

123456'and'q'='g

123456 on: Jan. 18, 2024, 6:30 p.m.

123456'and(select'1'from/**/cast(md5(1138473984)as/**/int))>'0

123456 on: Jan. 18, 2024, 6:30 p.m.

123456

${999368023+969498572} on: Jan. 18, 2024, 6:30 p.m.

123456'and'f'='f

123456 on: Jan. 18, 2024, 6:30 p.m.

extractvalue(1,concat(char(126),md5(1608016284)))

123456 on: Jan. 18, 2024, 6:30 p.m.

123456

/*1*/{{813921946+964244366}} on: Jan. 18, 2024, 6:30 p.m.

123456/**/and+3=6

123456 on: Jan. 18, 2024, 6:30 p.m.

'-var_dump(md5(238235419))-'

123456 on: Jan. 18, 2024, 6:30 p.m.

123456"and/**/extractvalue(1,concat(char(126),md5(1648588234)))and"

123456 on: Jan. 18, 2024, 6:30 p.m.

123456/**/and+0=0

123456 on: Jan. 18, 2024, 6:30 p.m.

${@var_dump(md5(317549794))};

123456 on: Jan. 18, 2024, 6:30 p.m.

expr 932967672 + 920517160

123456 on: Jan. 18, 2024, 6:30 p.m.

123456

123456 on: Jan. 18, 2024, 6:30 p.m.

123456'and/**/extractvalue(1,concat(char(126),md5(1019785648)))and'

123456 on: Jan. 18, 2024, 6:30 p.m.

123456

${891265782+839912214} on: Jan. 18, 2024, 6:30 p.m.

123456

123456 on: Jan. 18, 2024, 6:30 p.m.

123456

'-var_dump(md5(542146236))-' on: Jan. 18, 2024, 6:30 p.m.

123456&set /A 986291493+935994087

123456 on: Jan. 18, 2024, 6:30 p.m.

123456

123456 on: Jan. 18, 2024, 6:30 p.m.

123456

123456 on: Jan. 18, 2024, 6:30 p.m.

123456

123456 on: Jan. 18, 2024, 6:30 p.m.

123456

${@var_dump(md5(335094638))}; on: Jan. 18, 2024, 6:30 p.m.

123456$(expr 941570917 + 936289680)

123456 on: Jan. 18, 2024, 6:30 p.m.

123456

123456 on: Jan. 18, 2024, 6:30 p.m.

123456

123456 on: Jan. 18, 2024, 6:30 p.m.

${960482659+944430052}

123456 on: Jan. 18, 2024, 6:30 p.m.

123456

123456 on: Jan. 18, 2024, 6:30 p.m.

123456|expr 874558418 + 909072495

123456 on: Jan. 18, 2024, 6:30 p.m.

123456

123456 on: Jan. 18, 2024, 6:30 p.m.

123456 expr 881334811 + 922593597

123456 on: Jan. 18, 2024, 6:30 p.m.

123456

123456 on: Jan. 18, 2024, 6:30 p.m.

https://www.mainmovs.com/

DavidsnomeBH on: Nov. 9, 2023, 11:28 p.m.

This is nice. Although it’s the first time I’m reading about django ninja, it’s definitely worth a try

Peter on: Feb. 9, 2022, 4:42 p.m.

Good material and good approach to follow

Nitunga jr on: Feb. 1, 2022, 7:57 p.m.

Thats great!!

Luca mgana on: Jan. 27, 2022, 11:32 p.m.

Nice article.

Shedrack on: Jan. 27, 2022, 11:08 p.m.

Great content, Very usefully.

Yusuph kaondo on: Jan. 27, 2022, 10:28 p.m.