new data model: add OpenAPI prototype
This commit is contained in:
parent
3e85c620c5
commit
356695f594
6 changed files with 115 additions and 16 deletions
105
catalog/api.py
105
catalog/api.py
|
@ -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}
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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),
|
||||
]
|
||||
|
|
Loading…
Add table
Reference in a new issue