Django Ninja - Fast Django REST Framework

Overview

Fast to learn, fast to code, fast to run

Test Coverage PyPI version

Django Ninja - Fast Django REST Framework

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 [email protected]).

Django Ninja REST Framework

Documentation: https://django-ninja.rest-framework.com


Installation

pip install django-ninja

Usage

In your django project next to urls.py create new api.py file:

from ninja import NinjaAPI

api = NinjaAPI()


@api.get("/add")
def add(request, a: int, b: int):
    return {"result": a + b}

Now go to urls.py and add the following:

...
from .api import api

urlpatterns = [
    path("admin/", admin.site.urls),
    path("api/", api.urls),  # <---------- !
]

That's it !

Now you've just created an API that:

  • receives an HTTP GET request at /api/add
  • takes, validates and type-casts GET parameters a and b
  • decodes the result to JSON
  • generates an OpenAPI schema for defined operation

Interactive API docs

Now go to http://127.0.0.1:8000/api/docs

You will see the automatic interactive API documentation (provided by Swagger UI):

Swagger UI

What next?

Issues
  • Unable to upload file (always get 'field required' message)

    Unable to upload file (always get 'field required' message)

    Hi @vitalik, I'm trying to upload a file but it's always getting a "field required" message.

    Screenshot from 2021-08-15 08-55-14

    Handler:

    FileParam = File
    def file_create(request: HttpRequest,
            name: str = FileParam(..., max_length=100),
            description: Optional[str] = FileParam(None, max_length=500),
            file: UploadedFile = FileParam(...),
            folder: Optional[UUID] = FileParam(None)
        ):
    

    Has anything been missed?

    opened by aprilahijriyan 16
  • Authentication Docs Error

    Authentication Docs Error

    image image

    I am trying to use Django Auth system, but the Docs are not working on POST/PUT requests and also on Django core admin requests.

    Config:

    api = NinjaAPI(csrf=True, auth=[django_auth])
    

    The only way I could do to access and execute a POST on the Swagger documentation is by adding @csrf_exempt decorator from django.views.decorators.csrf

    @router.delete('/v1/auth/logout/', auth=None)
    def auth_logout(request):
        logout(request)
        resp = HttpResponseRedirect('/')
        # trocar o método para GET -> 303
        resp.status_code = 303
        return resp
    
    
    @router.post('/v1/auth/status/')
    @csrf_exempt
    def auth_status(request):
        if request.user.is_authenticated:
            return True
        else:
            return HttpError(401, 'Unauthenticated')
    

    I already tryed commenting django.middleware.csrf.CsrfViewMiddleware, but doest work.

    Is there a way to use django_sessions with documentation working on POST requests and default admin endpoints? if not, just allow us to use django_auth without forcing to enable CSRF token pls.

    opened by luizfelipevbll 13
  • Smarter schema that handles dotted aliases and resolver methods

    Smarter schema that handles dotted aliases and resolver methods

    Fixes #291 (even though it was closed) and fixes #250 and adds in new functionality to allow calculated fields via resolve_ static methods on the response schema class.

    Includes tests and docs.

    opened by SmileyChris 12
  • Looks like you created multiple NinjaAPIs

    Looks like you created multiple NinjaAPIs

    Hi there, I was playing around a bit with the basic tutorial (it worked perfectly in the beginning) and got this error at some point:

      File "/django/django_aia_backend/django_aia_backend/urls.py", line 31, in <module>
        path('api/', include(api.urls)),
      File "/djangovenv/lib/python3.9/site-packages/ninja/main.py", line 314, in urls
        self._validate()
      File "/djangovenv/lib/python3.9/site-packages/ninja/main.py", line 398, in _validate
        raise ConfigError("\n".join(msg))
    ninja.errors.ConfigError: Looks like you created multiple NinjaAPIs
    To let ninja distinguish them you need to set either unique version or url_namespace
     - NinjaAPI(..., version='2.0.0')
     - NinjaAPI(..., urls_namespace='otherapi')
    Already registered: ['api-1.0.0']
    

    not sure what is the problem here. I only have one instantiation of NinjaAPI. I tried giving it a specific version name but that does not change anything.

    To be fair, I played around a bit before, among other things creating a django app called 'api' for using standard DRF. I deleted this and every reference to it, but even after starting a brand new django project, the error persists. Does the api instantiation get persisted somewhere in venv? I cannot explain otherwise why this happens.

    opened by Raketuv 11
  • Please make the response model optional!

    Please make the response model optional!

    I always get this on openapi.

    ninja.errors.ConfigError: Schema for status 400 is not set in response dict_keys([200])
    

    when I don't add a specific response model, it shouldn't be validated!

    opened by aprilahijriyan 10
  • foreign-key value failed to be valid integer in NinjaResponseSchema

    foreign-key value failed to be valid integer in NinjaResponseSchema

    ValidationError at /api/order/orders
    6 validation errors for NinjaResponseSchema
    response -> 0 -> customer_id
      value is not a valid integer (type=type_error.integer)
    response -> 0 -> vendor_id
      value is not a valid integer (type=type_error.integer)
    response -> 0 -> vender_product_id
      value is not a valid integer (type=type_error.integer)
    response -> 1 -> customer_id
      value is not a valid integer (type=type_error.integer)
    response -> 1 -> vendor_id
      value is not a valid integer (type=type_error.integer)
    response -> 1 -> vender_product_id
      value is not a valid integer (type=type_error.integer)
    

    my schema is like this:

    class OrderSchema(Schema):
        customer_id: int
        vendor_id: int
        vender_product_id: int
        total_product: int
        total_price: int
        created_on: datetime
        updated_on: datetime
    
    opened by ismohamedi 10
  • ATOMIC_REQUESTS and async views

    ATOMIC_REQUESTS and async views

    First of all, thank you very much for your work on this project. I sincerely hope that you and your family are doing well and I sincerely pray for the resolution of the conflict in Ukraine.

    Describe the bug I'm getting a RuntimeError on my django ninja async views when ATOMIC_REQUESTS is true

    Versions

    • Python version: 3.10
    • Django version: 4.0.3
    • Django-Ninja version: 0.17.0
    # settings.py
    DATABASES["default"]["ATOMIC_REQUESTS"] = True
    
    # api.py
    
    
    @transaction.non_atomic_requests
    @router.post("/flight-hotel-search", response=FlightHotelSearchResult)
    async def flight_hotel_search(request:HttpRequest, criteria: FlightHotelSearchCriteria):
      # there is zero database call done by me in this view
      ...
    
    
    
    # Error
    # RuntimeError: You cannot use ATOMIC_REQUESTS with async views.
    
    opened by Tobi-De 9
  • Why flint instead of poetry? How to contribute?

    Why flint instead of poetry? How to contribute?

    Hi! I want to contribute, but i found that project depends on flint and it seems very unfriendly to me.

    It gave 2 questions to me:

    • Could we add some docs for contributors?
    • Could we move to poetry?
    opened by al-stefanitsky-mozdor 9
  • Add custom schemas to Swagger UI

    Add custom schemas to Swagger UI

    Hey!

    Is there a way to append schemas which aren't shown in Swagger?

    I've coded a trick from #86 to use a complex object in the GET query but a schema I've specified is not in generated Swagger docs as it's not a real Schema for django-ninja, it's just a string field. I had a look at Router and NinjaAPI methods but couldn't find something similar to "add_schema".

    opened by igoose1 9
  • create_schema: ValueError: cannot specify both default and default_factory

    create_schema: ValueError: cannot specify both default and default_factory

    Hi, i have this error, after clone my repo and run python manage.py migrate

    Watching for file changes with StatReloader
    Performing system checks...
    
    Exception in thread django-main-thread:
    Traceback (most recent call last):
      File "/home/me/.pyenv/versions/3.8.9/lib/python3.8/threading.py", line 932, in _bootstrap_inner
        self.run()
      File "/home/me/.pyenv/versions/3.8.9/lib/python3.8/threading.py", line 870, in run
        self._target(*self._args, **self._kwargs)
      File "/home/me/myproject/.venv/lib/python3.8/site-packages/django/utils/autoreload.py", line 64, in wrapper
        fn(*args, **kwargs)
      File "/home/me/myproject/.venv/lib/python3.8/site-packages/django/core/management/commands/runserver.py", line 118, in inner_run
        self.check(display_num_errors=True)
      File "/home/me/myproject/.venv/lib/python3.8/site-packages/django/core/management/base.py", line 419, in check
        all_issues = checks.run_checks(
      File "/home/me/myproject/.venv/lib/python3.8/site-packages/django/core/checks/registry.py", line 76, in run_checks
        new_errors = check(app_configs=app_configs, databases=databases)
      File "/home/me/myproject/.venv/lib/python3.8/site-packages/django/core/checks/urls.py", line 13, in check_url_config
        return check_resolver(resolver)
      File "/home/me/myproject/.venv/lib/python3.8/site-packages/django/core/checks/urls.py", line 23, in check_resolver
        return check_method()
      File "/home/me/myproject/.venv/lib/python3.8/site-packages/django/urls/resolvers.py", line 412, in check
        for pattern in self.url_patterns:
      File "/home/me/myproject/.venv/lib/python3.8/site-packages/django/utils/functional.py", line 48, in __get__
        res = instance.__dict__[self.name] = self.func(instance)
      File "/home/me/myproject/.venv/lib/python3.8/site-packages/django/urls/resolvers.py", line 598, in url_patterns
        patterns = getattr(self.urlconf_module, "urlpatterns", self.urlconf_module)
      File "/home/me/myproject/.venv/lib/python3.8/site-packages/django/utils/functional.py", line 48, in __get__
        res = instance.__dict__[self.name] = self.func(instance)
      File "/home/me/myproject/.venv/lib/python3.8/site-packages/django/urls/resolvers.py", line 591, in urlconf_module
        return import_module(self.urlconf_name)
      File "/home/me/.pyenv/versions/3.8.9/lib/python3.8/importlib/__init__.py", line 127, in import_module
        return _bootstrap._gcd_import(name[level:], package, level)
      File "<frozen importlib._bootstrap>", line 1014, in _gcd_import
      File "<frozen importlib._bootstrap>", line 991, in _find_and_load
      File "<frozen importlib._bootstrap>", line 975, in _find_and_load_unlocked
      File "<frozen importlib._bootstrap>", line 671, in _load_unlocked
      File "<frozen importlib._bootstrap_external>", line 783, in exec_module
      File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
      File "/home/me/myproject/backend/urls.py", line 4, in <module>
        from .api import api
      File "/home/me/myproject/backend/api.py", line 3, in <module>
        from backend.product.api import router as product_router
      File "/home/me/myproject/backend/product/api.py", line 11, in <module>
        ProductSchema = create_schema(Product)
      File "/home/me/myproject/.venv/lib/python3.8/site-packages/ninja/orm/factory.py", line 57, in create_schema
        create_pydantic_model(name, __base__=Schema, **definitions),  # type: ignore
      File "pydantic/main.py", line 990, in pydantic.main.create_model
      File "pydantic/main.py", line 299, in pydantic.main.ModelMetaclass.__new__
      File "pydantic/fields.py", line 403, in pydantic.fields.ModelField.infer
      File "pydantic/fields.py", line 388, in pydantic.fields.ModelField._get_field_info
      File "pydantic/fields.py", line 173, in pydantic.fields.FieldInfo._validate
    ValueError: cannot specify both default and default_factory
    
    opened by rg3915 9
  • [proposal] Models to Schemas

    [proposal] Models to Schemas

    Read full proposal here - http://django-ninja.rest-framework.com/proposals/models/

    To make it possible to convert django models to ninja Schemas:

    from ninja import ModelSchema
    
    class UserOut(ModelSchema):
        class Meta:
            model = User
            fields = ['email', 'first_name', 'last_name']
    
    

    This feature will definitely land soon to production code

    But there is just one open question:

    configuration class - should it be Meta (django way) or Config (pydantic way) ?

    design 
    opened by vitalik 9
  • Bump actions/setup-python from 2 to 4

    Bump actions/setup-python from 2 to 4

    Bumps actions/setup-python from 2 to 4.

    Release notes

    Sourced from actions/setup-python's releases.

    v4.0.0

    What's Changed

    • Support for python-version-file input: #336

    Example of usage:

    - uses: actions/[email protected]
      with:
        python-version-file: '.python-version' # Read python version from a file
    - run: python my_script.py
    

    There is no default python version for this setup-python major version, the action requires to specify either python-version input or python-version-file input. If the python-version input is not specified the action will try to read required version from file from python-version-file input.

    • Use pypyX.Y for PyPy python-version input: #349

    Example of usage:

    - uses: actions/[email protected]
      with:
        python-version: 'pypy3.9' # pypy-X.Y kept for backward compatibility
    - run: python my_script.py
    
    • RUNNER_TOOL_CACHE environment variable is equal AGENT_TOOLSDIRECTORY: #338

    • Bugfix: create missing pypyX.Y symlinks: #347

    • PKG_CONFIG_PATH environment variable: #400

    • Added python-path output: #405 python-path output contains Python executable path.

    • Updated zeit/ncc to vercel/ncc package: #393

    • Bugfix: fixed output for prerelease version of poetry: #409

    • Made pythonLocation environment variable consistent for Python and PyPy: #418

    • Bugfix for 3.x-dev syntax: #417

    • Other improvements: #318 #396 #384 #387 #388

    Update actions/cache version to 2.0.2

    In scope of this release we updated actions/cache package as the new version contains fixes related to GHES 3.5 (actions/setup-python#382)

    Add "cache-hit" output and fix "python-version" output for PyPy

    This release introduces new output cache-hit (actions/setup-python#373) and fix python-version output for PyPy (actions/setup-python#365)

    The cache-hit output contains boolean value indicating that an exact match was found for the key. It shows that the action uses already existing cache or not. The output is available only if cache is enabled.

    ... (truncated)

    Commits
    • d09bd5e fix: 3.x-dev can install a 3.y version (#417)
    • f72db17 Made env.var pythonLocation consistent for Python and PyPy (#418)
    • 53e1529 add support for python-version-file (#336)
    • 3f82819 Fix output for prerelease version of poetry (#409)
    • 397252c Update zeit/ncc to vercel/ncc (#393)
    • de977ad Merge pull request #412 from vsafonkin/v-vsafonkin/fix-poetry-cache-test
    • 22c6af9 Change PyPy version to rebuild cache
    • 081a3cf Merge pull request #405 from mayeut/interpreter-path
    • ff70656 feature: add a python-path output
    • fff15a2 Use pypyX.Y for PyPy python-version input (#349)
    • Additional commits viewable in compare view

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    dependencies 
    opened by dependabot[bot] 0
  • Is there any document or helps to migrate from drf to django-ninja?

    Is there any document or helps to migrate from drf to django-ninja?

    It is not related to issue. I am really thanksful to the founder of django-ninja I was shocked it's really fast and easy and simplified comparing DRF So I choosed to use django-ninja + ninja-extra to my new project. But I already made some projects with drf so nowadays I want to migrate all project from DRF to django-ninja , improving performance also simplify code structures.

    Is there any tutorials or examples to acheive that? or supposed to make it?

    opened by quroom 0
  • Add exception `MethodNotAllowedError` and handler for it

    Add exception `MethodNotAllowedError` and handler for it

    Instead of a direct answer from the b"Method not allowed", I propose to process the resulting exception, like other exceptions. Added a MethodNotAllowedError error, as well as a handler for this error.

    opened by redlovv 1
  • [BUG] - Inferred model foreign key relationships aren't defined appropriately when ninja.orm.create_schema is used.

    [BUG] - Inferred model foreign key relationships aren't defined appropriately when ninja.orm.create_schema is used.

    Describe the bug In the documentation for the CRUD example found here: https://django-ninja.rest-framework.com/tutorial/crud/ it suggests that a create can be accomplished by:

    class EmployeeIn(Schema):
        first_name: str
        last_name: str
        department_id: int = None
        birthdate: date = None
    

    in conjunction with

    @api.post("/employees")
    def create_employee(request, payload: EmployeeIn):
        employee = Employee.objects.create(**payload.dict())
        return {"id": employee.id}
    

    I've made an attempt to abstract this logic for general crud operations into a router for each model:

    from asgiref.sync import sync_to_async
    from django.shortcuts import get_object_or_404  # type: ignore
    from typing import List, Any
    from ninja.orm import create_schema
    from ninja import Router
    
    def _get_model_router(model, name):
    
        router = Router(tags=[name])
    
        ModelPost = create_schema(model = model, name = f"{name.title()}Post", exclude=['id'])
        ModelGet = create_schema(model = model, name = f"{name.title()}Get")
    
        @router.post(f"/{name}")
        async def create_instance(request, payload: ModelPost):
            """Create a new instance based on input."""
            instance = await sync_to_async(model.objects.create)(**payload.dict())
            return ModelGet.from_orm(instance)
    
        @router.get(f"/{name}/" + "{model_id}", response=ModelGet)
        async def get_instance(request, model_id: int):
            """Return an instance for the ID specified."""
            instance = await sync_to_async(get_object_or_404)(model, id=model_id)
            return ModelGet.from_orm(instance)
    
        @router.get(f"/{name}", response=List[ModelGet])
        async def list_instances(request):
            """Return a list of all model instances."""
            qs = await sync_to_async(list)(model.objects.all())
            return qs
    
        @router.put(f"/{name}/" + "{model_id}")
        async def update_instance(request, model_id: int, payload: ModelPost):
            """Update the model instance with the payload."""
            instance = await sync_to_async(get_object_or_404)(model, id=model_id)
            for attr, value in payload.dict().items():
                setattr(instance, attr, value)
            await sync_to_async(instance.save)()
            return ModelGet.from_orm(instance)
    
        @router.patch(f"/{name}/" + "{model_id}")
        async def patch_instance(request, model_id: int, payload: ModelPost):
            """Update the model instance with the payload."""
            instance = await sync_to_async(get_object_or_404)(model, id=model_id)
            for attr, value in payload.dict().items():
                setattr(instance, attr, value)
            await sync_to_async(instance.save)()
            return ModelGet.from_orm(instance)
    
        @router.delete(f"/{name}/" + "{model_id}")
        async def delete_instance(request, model_id: int):
            """Delete the model instance."""
            instance = await sync_to_async(get_object_or_404)(model, id=model_id)
            await sync_to_async(instance.delete)()
            return {"success": True}
    
        return router
    
    
    def add_model_crud_route(api, name, model):
        """Add a deafult crud router with url `name` for model `model` to the api."""
        api.add_router(f'/{name}/', _get_model_router(model, name))
    

    And then in the main URLS:

    from django.contrib import admin  # type: ignore
    from django.urls import path  # type: ignore
    from ninja import NinjaAPI
    from .models import Employee, Department, KeyArea, Competency, FunctionalArea, Level, LevelDescription
    from django.conf.urls.static import static  # type: ignore
    from django.conf import settings  # type: ignore
    from django.views.generic import TemplateView  # type: ignore
    from skill_matrix_api.crud.utils import add_model_crud_route
    
    api = NinjaAPI()
    
    add_model_crud_route(api, 'employees', Employee)
    add_model_crud_route(api, 'departments', Department)
    add_model_crud_route(api, 'keyarea', KeyArea)
    add_model_crud_route(api, 'competency', Competency)
    add_model_crud_route(api, 'functonalarea', FunctionalArea)
    add_model_crud_route(api, 'level', Level)
    add_model_crud_route(api, 'leveldescription', LevelDescription)
    
    urlpatterns = [
        path("admin/", admin.site.urls),
        path("api/", api.urls),
        path('', TemplateView.as_view(template_name="index.html")),
    ] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
    

    In theory, the logic is identical between the post methods to create an object - when I use the example, the id field resolves to it's foreign key with no issues - however when I use the abstracted code it appears to lose that relationship and I'm left with this error:

    Traceback (most recent call last):
      File "/usr/local/lib/python3.11/site-packages/ninja/operation.py", line 259, in run
        result = await self.view_func(request, **values)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      File "/usr/src/skill_matrix_api/skill_matrix_api/crud/utils.py", line 17, in create_instance
        instance = await sync_to_async(model.objects.create)(**payload.dict())
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      File "/usr/local/lib/python3.11/site-packages/asgiref/sync.py", line 435, in __call__
        ret = await asyncio.wait_for(future, timeout=None)
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      File "/usr/local/lib/python3.11/asyncio/tasks.py", line 451, in wait_for
        return await fut
               ^^^^^^^^^
      File "/usr/local/lib/python3.11/site-packages/asgiref/current_thread_executor.py", line 22, in run
        result = self.fn(*self.args, **self.kwargs)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      File "/usr/local/lib/python3.11/site-packages/asgiref/sync.py", line 476, in thread_handler
        return func(*args, **kwargs)
               ^^^^^^^^^^^^^^^^^^^^^
      File "/usr/local/lib/python3.11/site-packages/django/db/models/manager.py", line 85, in manager_method
        return getattr(self.get_queryset(), name)(*args, **kwargs)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      File "/usr/local/lib/python3.11/site-packages/django/db/models/query.py", line 512, in create
        obj = self.model(**kwargs)
              ^^^^^^^^^^^^^^^^^^^^
      File "/usr/local/lib/python3.11/site-packages/django/db/models/base.py", line 541, in __init__
        _setattr(self, field.name, rel_obj)
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      File "/usr/local/lib/python3.11/site-packages/django/db/models/fields/related_descriptors.py", line 235, in __set__
        raise ValueError(
        ^^^^^^^^^^^^^^^^^
    ValueError: Cannot assign "1": "Employee.department" must be a "Department" instance.
    

    While I CAN find some workarounds in this by inferring the model name from the foreign key information from the model, it seems like it's supposed to resolve. It DOES work fine if I explicitly create the pydantic model with the Schema object as the base - it only fails to resolve when using the ninja.orm.create_schema method. It appears that the create_schema function is not using the department_id but is rather using the department foreign key directly, so it expects the object itself, not the ID.

    Versions (please complete the following information):

    /usr/src/skill_matrix_api # python -V
    Python 3.11.0b3
    /usr/src/skill_matrix_api # python -m django --version
    4.0.5
    /usr/src/skill_matrix_api # pip freeze | grep ninja
    django-ninja==0.18.0
    /usr/src/skill_matrix_api #
    
    opened by bubthegreat 3
  • [BUG] Optional Not Respected on ModelSchema Fields

    [BUG] Optional Not Respected on ModelSchema Fields

    Describe the bug Assume the following Model and ModelSchema:

    class Car(models.Model):
        car_model = models.CharField(max_length=120)
        year = models.IntegerField()
        vin_number = models.CharField(max_length=17)
        manufacturer = models.ForeignKey(to='Manufacturer', on_delete=models.CASCADE)
        drivers = models.ManyToManyField(to='Driver')
    
    class CarSchemaIn(ModelSchema):
        manufacturer: Optional[ManufacturerSchemaIn]
        manufacturer_id: Optional[int]
        drivers: Optional[List[DriverSchemaIn]]
        drivers_ids: Optional[List[int]]
    
        class Config:
            model = models.Car
            model_fields = ['car_model', 'year', 'vin_number']
    
    

    django-ninja does not obey the Optional type and generates a schema where the manually declared optional fields are required.

    image

    Versions:

    • Python version: 3.10
    • Django version: 4.0
    • Django-Ninja version: 0.18.0
    • Pydantic Version: 1.9.1
    opened by tspanos 1
Releases(v.0.19.0)
  • v.0.19.0(Jun 29, 2022)

    What's Changed

    • docs decorator by @vitalik in https://github.com/vitalik/django-ninja/pull/488
    • Allow arbitrary Pagination Output ( alternative #464 @rafonseca ) by @vitalik in https://github.com/vitalik/django-ninja/pull/483
    • Update Redoc related documents by @tssujt in https://github.com/vitalik/django-ninja/pull/462
    • Improves authentication validation to throw an exception by @duducp in https://github.com/vitalik/django-ninja/pull/454
    • Add TestClient note to multiple APIs warning by @srcreigh in https://github.com/vitalik/django-ninja/pull/416
    • Implement implicit reverse url name generation by @SmileyChris in https://github.com/vitalik/django-ninja/pull/361
      • Also pass the router to get_operation_url_name by @SmileyChris in https://github.com/vitalik/django-ninja/pull/486
    • [feat] add superuser session authentication only by @areski in https://github.com/vitalik/django-ninja/pull/351

    New Contributors

    • @tssujt made their first contribution in https://github.com/vitalik/django-ninja/pull/462
    • @duducp made their first contribution in https://github.com/vitalik/django-ninja/pull/454
    • @srcreigh made their first contribution in https://github.com/vitalik/django-ninja/pull/416
    • @areski made their first contribution in https://github.com/vitalik/django-ninja/pull/351

    Full Changelog: https://github.com/vitalik/django-ninja/compare/v.0.18.0...v.0.19.0

    Source code(tar.gz)
    Source code(zip)
  • v.0.18.0(Jun 3, 2022)

    Hello

    Please welcome the new Django Ninja version it has lot of fixes and improvements

    Most notable a HttpResponse typed argument by @SmileyChris

    Now you can manage response behaviour (cookies, headers, streaming) flixible:

    @api.post("/boop")
    def boop(request, response: HttpResponse): # !
        response.set_cookie("beep", "boop") # !
        return True
    

    All changes

    • Provide a temporal HttpResponse typed argument to views by @SmileyChris in https://github.com/vitalik/django-ninja/pull/336
    • UploadedFile inherit from Django's UploadedFile by @OtherBarry in https://github.com/vitalik/django-ninja/pull/400
    • Allow path parameters to be specified at router level by @kaschnit in https://github.com/vitalik/django-ninja/pull/369
    • Added support for postgress specific fields to Model Schema #353
    • Fixed openapi/pydantic versions compatibility #418
    • pre-commit config by @SmileyChris in https://github.com/vitalik/django-ninja/pull/364
    • Access to test response attributes by @stephane in https://github.com/vitalik/django-ninja/pull/402
    • Small optimization and typing improvements by @SmileyChris in https://github.com/vitalik/django-ninja/pull/367
    • Minor typo in tutorial by @stephane in https://github.com/vitalik/django-ninja/pull/387
    • Specify mypy in CONTRIBUTING.md by @OtherBarry in https://github.com/vitalik/django-ninja/pull/401
    • ConfigError: ModelSchema classes requires a 'Config' subclass by @sebastian-philipp in https://github.com/vitalik/django-ninja/pull/382
    • Fix a typing issue by @HoJin9622 in https://github.com/vitalik/django-ninja/pull/404
    • Fix a few typos by @dy3l in https://github.com/vitalik/django-ninja/pull/426
    • Add Redoc support by @kxxoling in https://github.com/vitalik/django-ninja/pull/427
    • Fix typo in docs by @sho918 in https://github.com/vitalik/django-ninja/pull/432
    • Handle class instances in signature.details.is_collection_type by @flaeppe in https://github.com/vitalik/django-ninja/pull/434
    • Upgrade versions of pre-commit hooks by @flaeppe in https://github.com/vitalik/django-ninja/pull/435

    New Contributors

    • @kaschnit made their first contribution in https://github.com/vitalik/django-ninja/pull/369
    • @stephane made their first contribution in https://github.com/vitalik/django-ninja/pull/387
    • @OtherBarry made their first contribution in https://github.com/vitalik/django-ninja/pull/400
    • @sebastian-philipp made their first contribution in https://github.com/vitalik/django-ninja/pull/382
    • @HoJin9622 made their first contribution in https://github.com/vitalik/django-ninja/pull/404
    • @dy3l made their first contribution in https://github.com/vitalik/django-ninja/pull/426
    • @kxxoling made their first contribution in https://github.com/vitalik/django-ninja/pull/427
    • @sho918 made their first contribution in https://github.com/vitalik/django-ninja/pull/432
    • @flaeppe made their first contribution in https://github.com/vitalik/django-ninja/pull/434

    Full Changelog: https://github.com/vitalik/django-ninja/compare/v0.17.0...v0.18.0

    Source code(tar.gz)
    Source code(zip)
  • v0.17.0(Feb 3, 2022)

    This release brings few long awaited features:

    Smarter schema

    Now you can access orm instance attributes inside schema with resolvers:

    class TaskSchema(Schema):
        title: str
        is_completed: bool
        owner: Optional[str]
        lower_title: str
    
        @staticmethod
        def resolve_owner(obj):  # <------- !!!!!!
            if not obj.owner:
                return
            return f"{obj.owner.first_name} {obj.owner.last_name}"
    
        def resolve_lower_title(self, obj):   # <-------- !!!!!!
            return self.title.lower()
    

    Field aliases now support django template variables dotted syntax:

    class TaskSchema(Schema):
        ...
        last_comment: str = Field(..., alias="comment_set.0.text")
    

    Thanks to @SmileyChris

    Pagination output

    Now default paginated output returns a dict with items and count

    You can now override both input and output schemas for custom pagination:

    class CustomPagination(PaginationBase):
    
        class Input(Schema):
            page: int
            
        class Output(Schema):
            items: List[Any]
            total_pages: int
            current_page: int
        
        def paginate_queryset(self, queryset, pagination: Input, **params):
            return {
                'items': ...,
                'total_pages': ...,
                'current_page': ...,
            }
    

    All updates:

    • Improved pagination by @vitalik
    • Smarter schema that handles dotted aliases and resolver methods by @SmileyChris #317
    • Add support for union type in payload by @AkeemMcLennon #301
    • Export OpenAPI schema management cmd by @stefanitsky #288
    • First key derivation optimization by @mom1 #344
    • **kwargs not required anymore for pagination by @mom1 #285

    New Contributors

    • @AkeemMcLennon
    • @stefanitsky
    • @mom1

    Full Changelog: https://github.com/vitalik/django-ninja/compare/v0.16.2...v0.17.0

    Source code(tar.gz)
    Source code(zip)
  • v0.16.2(Jan 20, 2022)

    • Pydantic 1.9.0 support #310 by @antonrh
    • Fix params descriptions visualization in swagger ui #331 by @ldbenitez
    • Improve TestClient json argument-serialization #315 by @johnbergvall
    • Add python 3.10 to test matrix #273 by @jairhenrique
    • Automate github actions update. #274 by @jairhenrique

    Many documentaion fixes and improvements by:

    • @daviddavis
    • @shamaevnn
    • @SmileyChris
    • @antonrh
    • @s3lcuk
    • @idahogray
    • @TaeHyoungKwon
    • @dekoza
    Source code(tar.gz)
    Source code(zip)
  • v0.16.1(Oct 12, 2021)

    • Resolve #229 & #240 reporting dev errors under django dev-server (#242 by @stephenrauch)
    • Allow NOT_SET to survive copy.deepcopy() (#241 by @stephenrauch)
    Source code(tar.gz)
    Source code(zip)
  • v0.16.0(Oct 6, 2021)

    OpenAPI schemas names

    Generating OpenAPI automatically created schema names changed for duplicated names (see #230) Now instead of silence (or exceptions on other cases) django-ninja will just add sequential number suffix to the schema name in OpenAPI spec. For example if you already have schema called "User" and in some other module you create another "User" schema - the second will have name "User2" in openapi json.

    Other

    • Dot in query regression #238 (#239 by @stephenrauch)
    • Fix openapi schema title and description propagation for query, cookie, header, etc #123 (#233 from @stephenrauch)
    • Fix form schema single param #236 (#237 from @stephenrauch)
    • Improve #181, query with list type (#234 by @stephenrauch)
    • Path signature check (#232 by @stephenrauch)
    • Document how to handle empty form fields (#228 by @stephenrauch)
    • Misc fixes (#231 by @ehdgua01)
    Source code(tar.gz)
    Source code(zip)
  • v0.15.0(Sep 18, 2021)

    Major changes

    • Introduced ModelSchema - declarative way to create schemas from django models
    • Allow arbitrary mix of params Body, Form & File w/ multipart. (#226 by @stephenrauch) (also fixes #134, #162, #201)
    • Path params now support Django path converters (#187 by @stephenrauch)

    Other changes

    • Fixed #208 - Missing schema in requestBody (#209 by @stephenrauch)
    • UploadedFile usability #120
    • Types for "urls" property #155
    • Optimize tests (#217 by @mawassk)
    • Better error message for duplicate orm schema names #214 (#215 @stephenrauch)
    • Test coverage for branches (#211 @stephenrauch)
    • Formatting & styling for test files (#218 by @stephenrauch)
    • Documentation improvements (#207 by @eadwinCode, #205 #206 by @johnthagen )
    Source code(tar.gz)
    Source code(zip)
  • v0.14.0(Aug 14, 2021)

    Hello Everyone,

    This is a very nice release, which includes some new functionality and fixes And more important there are lot of people contributed to this update Thank you

    • Added experimental Pagination support - allows you easely paginate your querysets and customize pages (note - this feature currently in beta and may change a bit in future udpates)
    • Added support for streaming responses (#149 by @ErwinJunge )
    • Mixing simple arguments and models arguments in GET parameters (#178 by @stephenrauch )
    • Handle custom exceptions in authentication (#174 by @dozer133 )
    • Added build_absolute_uri on test client (#168 by @jairhenrique )
    • Typing improvements (#167, #170 by @davidszotten )
    • Fix assertion message (#175 by @igoose1 )
    • Resolve #148, missing wraps(), with a better error message. (#184 by @stephenrauch)
    • Improved documentation on forward refs ( #161 by @stephenrauch )
    • Fixed add_router() to router already attached to API ( #188 by @stephenrauch )
    • Bumped Swagger UI to 3.51.2 ( #192 by @igoose1 )
    Source code(tar.gz)
    Source code(zip)
  • v0.13.2(Jun 5, 2021)

  • v0.13.1(Jun 3, 2021)

  • v0.13.0(May 18, 2021)

    • Fixed create_schema ValueError on pydantic 1.8.2 (#135)
    • Allow collection fields to be identified when an alias is used #133 (by @kierandarcy )
    • New argument custom_fields in create_schema to override or add fields
    • Fixed create_schema Json field (#127)
    • Include ninja TestClient into distributed package
    Source code(tar.gz)
    Source code(zip)
  • v0.12.3(Apr 28, 2021)

  • v0.12.2(Apr 6, 2021)

  • v0.12.1(Mar 26, 2021)

  • v0.12.0(Mar 26, 2021)

  • v0.11.0(Mar 3, 2021)

  • v0.10.2(Feb 2, 2021)

  • 0.10.1(Jan 15, 2021)

  • v0.10.0(Jan 13, 2021)

  • v0.9.7(Dec 25, 2020)

  • v0.9.6(Dec 21, 2020)

  • v0.9.4(Dec 14, 2020)

  • v0.9.3(Dec 14, 2020)

Async Python 3.6+ web server/framework | Build fast. Run fast.

Sanic | Build fast. Run fast. Build Docs Package Support Stats Sanic is a Python 3.6+ web server and web framework that's written to go fast. It allow

Sanic Community Organization 16.2k Jun 30, 2022
The no-nonsense, minimalist REST and app backend framework for Python developers, with a focus on reliability, correctness, and performance at scale.

The Falcon Web Framework Falcon is a reliable, high-performance Python web framework for building large-scale app backends and microservices. It encou

Falconry 8.8k Jun 25, 2022
REST API framework designed for human beings

Eve Eve is an open source Python REST API framework designed for human beings. It allows to effortlessly build and deploy highly customizable, fully f

eve 6.5k Jun 24, 2022
REST API framework designed for human beings

Eve Eve is an open source Python REST API framework designed for human beings. It allows to effortlessly build and deploy highly customizable, fully f

eve 6.3k Feb 17, 2021
Goblet is an easy-to-use framework that enables developers to quickly spin up fully featured REST APIs with python on GCP

GOBLET Goblet is a framework for writing serverless rest apis in python in google cloud. It allows you to quickly create and deploy python apis backed

Austen 54 Jun 26, 2022
Endpoints is a lightweight REST api framework written in python and used in multiple production systems that handle millions of requests daily.

Endpoints Quickest API builder in the West! Endpoints is a lightweight REST api framework written in python and used in multiple production systems th

Jay Marcyes 30 Mar 5, 2022
An alternative serializer implementation for REST framework written in cython built for speed.

drf-turbo An alternative serializer implementation for REST framework written in cython built for speed. Free software: MIT license Documentation: htt

Mng 73 Jun 13, 2022
Fast, asynchronous and elegant Python web framework.

Warning: This project is being completely re-written. If you're curious about the progress, reach me on Slack. Vibora is a fast, asynchronous and eleg

vibora.io 5.7k Jun 26, 2022
FastAPI framework, high performance, easy to learn, fast to code, ready for production

FastAPI framework, high performance, easy to learn, fast to code, ready for production Documentation: https://fastapi.tiangolo.com Source Code: https:

Sebastián Ramírez 46.6k Jun 27, 2022
bottle.py is a fast and simple micro-framework for python web-applications.

Bottle: Python Web Framework Bottle is a fast, simple and lightweight WSGI micro web-framework for Python. It is distributed as a single file module a

Bottle Micro Web Framework 7.6k Jun 30, 2022
Fully featured framework for fast, easy and documented API development with Flask

Flask RestPlus IMPORTANT NOTICE: This project has been forked to Flask-RESTX and will be maintained by by the python-restx organization. Flask-RESTPlu

Axel H. 2.6k Jun 30, 2022
Fully featured framework for fast, easy and documented API development with Flask

Flask RestPlus IMPORTANT NOTICE: This project has been forked to Flask-RESTX and will be maintained by by the python-restx organization. Flask-RESTPlu

Axel H. 2.5k Feb 17, 2021
FPS, fast pluggable server, is a framework designed to compose and run a web-server based on plugins.

FPS, fast pluggable server, is a framework designed to compose and run a web-server based on plugins. It is based on top of fastAPI, uvicorn, typer, and pluggy.

Adrien Delsalle 1 Nov 16, 2021
Fast⚡, simple and light💡weight ASGI micro🔬 web🌏-framework for Python🐍.

NanoASGI Asynchronous Python Web Framework NanoASGI is a fast ⚡ , simple and light ?? weight ASGI micro ?? web ?? -framework for Python ?? . It is dis

Kavindu Santhusa 8 Jun 16, 2022
A minimal, extensible, fast and productive API framework for Python 3.

molten A minimal, extensible, fast and productive API framework for Python 3. Changelog: https://moltenframework.com/changelog.html Community: https:/

Bogdan Popa 982 Jun 29, 2022
Appier is an object-oriented Python web framework built for super fast app development.

Joyful Python Web App development Appier is an object-oriented Python web framework built for super fast app development. It's as lightweight as possi

Hive Solutions 120 May 19, 2022
Bionic is Python Framework for crafting beautiful, fast user experiences for web and is free and open source

Bionic is fast. It's powered core python without any extra dependencies. Bionic offers stateful hot reload, allowing you to make changes to your code and see the results instantly without restarting your app or losing its state.

 ⚓ 0 Mar 5, 2022
TinyAPI - 🔹 A fast & easy and lightweight WSGI Framework for Python

TinyAPI - ?? A fast & easy and lightweight WSGI Framework for Python

xArty 3 Apr 8, 2022
A Flask API REST to access words' definition

A Flask API to access words' definitions

Pablo Emídio S.S 9 Jan 27, 2022