-
-
Notifications
You must be signed in to change notification settings - Fork 2
Replace DRF wirth Ninja #129
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 47 commits
fc6b89c
c005f47
01bb81a
eb764cf
b4b5e15
9f5dbd4
e07cb1f
0d4720d
2e07845
e2685f9
309c102
edc16c4
65118b0
66b399c
3154855
82666a1
cb72d8a
9568842
ad30d5b
c2456e1
258ced5
d86ef81
6c9c083
017af4f
0283365
9b3593c
7499ace
5edcdda
4a79f81
82e79e4
c14be1c
d19704c
d2c236f
c916e91
ee8171c
d1ab8fd
e9d25ec
7c8a14d
4081b30
e74c4fd
d724a37
56b9af2
16163e9
677e566
b7a1c10
dd7d705
7ed9edc
6db122e
d86851d
3ddbec9
be23c26
289ef48
c3e9041
ff7603a
5115f39
6f4bf77
9a49359
e3d9739
f9700c6
afc663f
751ee86
344a5f5
85d637c
84031e7
20928a7
ee1b449
c8bf807
9e37865
e66a55e
3325a08
94cbc5a
785da0c
8a9af07
b92d583
4d33c10
e86b126
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -76,4 +76,4 @@ jobs: | |
|
||
- name: Failure logs | ||
if: failure() | ||
run: docker-compose logs | ||
run: docker compose logs |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -105,4 +105,4 @@ jobs: | |
|
||
- name: Failure logs | ||
if: failure() | ||
run: docker-compose logs | ||
run: docker compose logs |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -45,4 +45,4 @@ jobs: | |
|
||
- name: Failure logs | ||
if: failure() | ||
run: docker-compose logs | ||
run: docker compose logs |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
# Django-OAPIF | ||
|
||
*Django-OAPIF* allows to easily expose your Django models through an OGC API Features endpoint. | ||
It is based on Django REST Framework. | ||
It is based on Django Ninja. | ||
|
||
https://opengisch.github.io/django-oapif |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
# Django-OAPIF | ||
|
||
*Django-OAPIF* allows to easily expose your Django models through an OGC API Features endpoint. | ||
It is based on Django REST Framework. | ||
It is based on Django Ninja. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,15 @@ | ||
from . import permissions | ||
from .api import OAPIF | ||
|
||
try: | ||
from .__version__ import __version__, __version_tuple__ | ||
except ImportError: | ||
__version__ = "0.0.0.dev" | ||
__version_tuple__ = (0, 0, 0, "dev") | ||
|
||
__all__ = [ | ||
"permissions", | ||
"OAPIF", | ||
"__version__", | ||
"__version_tuple__", | ||
] |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
from typing import Any, Optional | ||
|
||
from django.conf import settings | ||
from django.contrib.auth import authenticate | ||
from django.db import models | ||
from django.http import HttpRequest | ||
from ninja import NinjaAPI | ||
from ninja.security import APIKeyCookie, HttpBasicAuth | ||
|
||
from django_oapif.collections import ( | ||
OAPIFCollectionEntry, | ||
create_collection_router, | ||
create_collections_router, | ||
) | ||
from django_oapif.conformance import create_conformance_router | ||
from django_oapif.permissions import ( | ||
BasePermission, | ||
DjangoModelPermissionsOrAnonReadOnly, | ||
) | ||
from django_oapif.root import create_root_router | ||
|
||
|
||
class BasicAuth(HttpBasicAuth): | ||
def authenticate(self, request, username, password): | ||
if user := authenticate(request, username=username, password=password): | ||
request.user = user | ||
return request.user | ||
|
||
|
||
class DjangoAuth(APIKeyCookie): | ||
param_name: str = settings.SESSION_COOKIE_NAME | ||
|
||
def authenticate(self, request: HttpRequest, key: Optional[str]) -> Optional[Any]: | ||
return request.user | ||
|
||
|
||
class OAPIF: | ||
"""Ninja API.""" | ||
|
||
def __init__(self): | ||
self.api = NinjaAPI(auth=[BasicAuth(), DjangoAuth()]) | ||
self.collections: dict[str, OAPIFCollectionEntry] = {} | ||
self.api.add_router("/", create_root_router()) | ||
self.api.add_router("/conformance", create_conformance_router()) | ||
self.api.add_router("/collections", create_collections_router(self.collections)) | ||
|
||
def register( | ||
self, | ||
/, | ||
id: str | None = None, | ||
title: str | None = None, | ||
description: str | None = None, | ||
geometry_field: str | None = "geom", | ||
properties_fields: list[str] | None = None, | ||
auth: type[BasePermission] = DjangoModelPermissionsOrAnonReadOnly, | ||
): | ||
"""Register a Django model in the API.""" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. could you document the arguments? that would answet these basic questions There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
||
def decorator(model_class: models.Model): | ||
collection_id = id or model_class._meta.label_lower | ||
collection_title = id or model_class._meta.label | ||
self.collections[collection_id] = OAPIFCollectionEntry( | ||
model_class=model_class, | ||
id=collection_id, | ||
title=collection_title, | ||
description=description, | ||
geometry_field=geometry_field, | ||
properties_fields=properties_fields, | ||
auth=auth, | ||
) | ||
|
||
return model_class | ||
|
||
return decorator | ||
|
||
def _add_collections_routers(self): | ||
for collection_id, collection_entry in self.collections.items(): | ||
self.api.add_router(f"/collections/{collection_id}", create_collection_router(collection_entry)) | ||
|
||
@property | ||
def urls(self): | ||
self._add_collections_routers() | ||
return self.api.urls |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shall we stick only to one type of imports? I see almost everywhere else we use absolute imports, which are slightly more preferrable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, I think we can even remove the re-export of permissions from here.