new data model: add OpenAPI prototype

This commit is contained in:
Your Name 2022-12-17 23:03:19 -05:00
parent 3e85c620c5
commit 356695f594
6 changed files with 115 additions and 16 deletions

View file

@ -1,11 +1,104 @@
from ninja import NinjaAPI
from .models import Podcast
from .models import *
from .common import *
from .sites import *
from django.conf import settings
from datetime import date
from ninja import Schema
from typing import List, Optional
from django.utils.baseconv import base62
from django.shortcuts import render, get_object_or_404, redirect, reverse
from django.http import Http404
api = NinjaAPI(title=settings.SITE_INFO['site_name'], version="1.0.0", description=f"{settings.SITE_INFO['site_name']} API <hr/><a href='{settings.APP_WEBSITE}'>Learn more</a>")
api = NinjaAPI(title=settings.SITE_INFO['site_name'], version="1.0.0", description=settings.SITE_INFO['site_name'])
class ItemIn(Schema):
title: str
brief: str
@api.get("/podcasts/{item_id}")
def get_item(request, item_id: int):
return Podcast.objects.filter(pk=item_id).first()
class ItemOut(Schema):
uuid: str
title: str
brief: str
url: str
api_url: str
category: str
class EditionIn(ItemIn):
subtitle: str = None
orig_title: str = None
author: list[str]
translator: list[str]
language: str = None
pub_house: str = None
pub_year: int = None
pub_month: int = None
binding: str = None
price: str = None
pages: str = None
series: str = None
imprint: str = None
class EditionOut(ItemOut):
subtitle: str = None
orig_title: str = None
author: list[str]
translator: list[str]
language: str = None
pub_house: str = None
pub_year: int = None
pub_month: int = None
binding: str = None
price: str = None
pages: str = None
series: str = None
imprint: str = None
@api.post("/catalog/fetch", response=ItemOut)
def fetch_edition(request, url: str):
site = SiteManager.get_site_by_url(url)
if not site:
return Http404()
resource = site.get_resource_ready()
if not resource:
return Http404()
return site.get_item()
@api.post("/book/")
def create_edition(request, payload: EditionIn):
edition = Edition.objects.create(**payload.dict())
return {"id": edition.uuid}
@api.get("/book/{uuid}/", response=EditionOut)
def get_edition(request, uuid: str):
edition = get_object_or_404(Edition, uid=base62.decode(uuid))
return edition
# @api.get("/book", response=List[EditionOut])
# def list_editions(request):
# qs = Edition.objects.all()
# return qs
@api.put("/book/{uuid}/")
def update_edition(request, uuid: str, payload: EditionIn):
edition = get_object_or_404(Item, uid=base62.decode(uuid))
for attr, value in payload.dict().items():
setattr(edition, attr, value)
edition.save()
return {"success": True}
@api.delete("/book/{uuid}/")
def delete_edition(request, uuid: str):
edition = get_object_or_404(Edition, uid=base62.decode(uuid))
edition.delete()
return {"success": True}

View file

@ -57,16 +57,16 @@ class Edition(Item):
orig_title = jsondata.CharField(null=True, blank=True, default=None)
author = jsondata.ArrayField(_('作者'), null=False, blank=False, default=list)
translator = jsondata.ArrayField(_('译者'), null=True, blank=True, default=list)
language = jsondata.ArrayField(_("语言"), null=True, blank=True, default=list)
pub_house = jsondata.ArrayField(_('出版方'), null=True, blank=True, default=list)
language = jsondata.CharField(_("语言"), null=True, blank=True, default=None)
pub_house = jsondata.CharField(_('出版方'), null=True, blank=True, default=None)
pub_year = jsondata.IntegerField(_("发表年份"), null=True, blank=True)
pub_month = jsondata.IntegerField(_("发表月份"), null=True, blank=True)
binding = jsondata.CharField(null=True, blank=True, default=None)
pages = jsondata.IntegerField(blank=True, default=None)
series = jsondata.CharField(null=True, blank=True, default=None)
contents = jsondata.CharField(null=True, blank=True, default=None)
price = jsondata.FloatField(_("发表月份"), null=True, blank=True)
imprint = jsondata.FloatField(_("发表月份"), null=True, blank=True)
price = jsondata.CharField(_("价格"), null=True, blank=True)
imprint = jsondata.CharField(_("发表月份"), null=True, blank=True)
@property
def isbn10(self):

View file

@ -123,6 +123,8 @@ class BooleanField(JSONFieldMixin, fields.BooleanField):
class CharField(JSONFieldMixin, fields.CharField):
def from_json(self, value): # TODO workaound some bad data in migration, should be removed after clean up
return value if isinstance(value, str) else None
pass

View file

@ -195,7 +195,7 @@ class Item(SoftDeleteMixin, PolymorphicModel):
self.primary_lookup_id_type = None
def __str__(self):
return f"{self.id}|{self.url_id}{' ' + self.primary_lookup_id_type + ':' + self.primary_lookup_id_value if self.primary_lookup_id_value else ''} ({self.title})"
return f"{self.id}|{self.uuid}{' ' + self.primary_lookup_id_type + ':' + self.primary_lookup_id_value if self.primary_lookup_id_value else ''} ({self.title})"
@classmethod
def get_best_lookup_id(cls, lookup_ids):
@ -222,12 +222,16 @@ class Item(SoftDeleteMixin, PolymorphicModel):
self.merged_to_item = to_item
@property
def url_id(self):
def uuid(self):
return base62.encode(self.uid.int)
@property
def url(self):
return f'/{self.url_path}/{self.url_id}/'
return f'/{self.url_path}/{self.uuid}/'
@property
def api_url(self):
return '/api' + self.url
@property
def class_name(self):

View file

@ -75,7 +75,7 @@
<span> {% trans '评分:评分人数不足' %}</span>
{% endif %}
</div>
<div>uid: {{item.url_id}}</div>
<div>uuid: {{item.uuid}}</div>
<div>class: {{item.class_name}}</div>
<div>category: {{item.category}}</div>
<div>id type: {{item.primary_id_type}}</div>

View file

@ -15,7 +15,7 @@ def _get_all_url_paths():
urlpatterns = [
re_path(r'item/(?P<item_uuid>[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12})/', retrieve_by_uuid, name='retrieve_by_uuid'),
re_path(r'(?P<item_path>' + _get_all_url_paths() + ')/(?P<item_uid>[A-Za-z0-9]{21,22})/', retrieve, name='retrieve'),
re_path(r'^item/(?P<item_uuid>[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12})/', retrieve_by_uuid, name='retrieve_by_uuid'),
re_path(r'^(?P<item_path>' + _get_all_url_paths() + ')/(?P<item_uid>[A-Za-z0-9]{21,22})/', retrieve, name='retrieve'),
path("api/", api.urls),
]