lib.itmens/catalog/book/models.py

192 lines
5.7 KiB
Python
Raw Normal View History

"""
Models for Book
Series -> Work -> Edition
Series is not fully implemented at the moment
Goodreads
Famous works have many editions
Google Books:
only has Edition level ("volume") data
Douban:
old editions has only CUBN(Chinese Unified Book Number)
2022-12-08 16:08:59 +00:00
work data seems asymmetric (a book links to a work, but may not listed in that work as one of its editions)
"""
2023-01-05 03:06:13 -05:00
from django.core.validators import MaxValueValidator, MinValueValidator
from django.db import models
from django.utils.translation import gettext_lazy as _
2023-02-15 15:45:57 -05:00
from catalog.common.models import *
from .utils import *
2023-02-15 15:45:57 -05:00
class EditionInSchema(ItemInSchema):
subtitle: str | None = None
orig_title: str | None = None
author: list[str]
translator: list[str]
language: str | None = None
pub_house: str | None = None
pub_year: int | None = None
pub_month: int | None = None
binding: str | None = None
price: str | None = None
pages: str | None = None
series: str | None = None
imprint: str | None = None
class EditionSchema(EditionInSchema, BaseSchema):
2023-02-15 16:22:32 -05:00
isbn: str | None = None
2023-02-15 15:45:57 -05:00
pass
class Edition(Item):
2022-12-11 23:20:28 +00:00
category = ItemCategory.Book
2022-12-29 23:57:02 -05:00
url_path = "book"
demonstrative = _("这本书")
2022-12-15 17:29:35 -05:00
isbn = PrimaryLookupIdDescriptor(IdType.ISBN)
asin = PrimaryLookupIdDescriptor(IdType.ASIN)
cubn = PrimaryLookupIdDescriptor(IdType.CUBN)
# douban_book = LookupIdDescriptor(IdType.DoubanBook)
# goodreads = LookupIdDescriptor(IdType.Goodreads)
METADATA_COPY_LIST = [
2022-12-29 23:57:02 -05:00
"title",
"subtitle",
"author",
"pub_house",
"pub_year",
"pub_month",
"language",
"orig_title",
"translator",
"series",
2023-01-05 03:06:13 -05:00
"imprint",
2022-12-29 23:57:02 -05:00
"binding",
"pages",
2023-01-05 03:06:13 -05:00
"price",
"brief",
"contents",
]
2023-01-05 03:06:13 -05:00
subtitle = jsondata.CharField(
_("副标题"), null=True, blank=True, default=None, max_length=500
)
orig_title = jsondata.CharField(
_("原名"), null=True, blank=True, default=None, max_length=500
)
author = jsondata.ArrayField(
verbose_name=_("作者"),
base_field=models.CharField(max_length=500),
null=False,
blank=False,
default=list,
)
translator = jsondata.ArrayField(
verbose_name=_("译者"),
base_field=models.CharField(max_length=500),
null=True,
blank=True,
default=list,
)
2023-01-09 09:21:53 -05:00
language = jsondata.CharField(
_("语言"), null=True, blank=True, default=None, max_length=500
)
2023-01-05 03:06:13 -05:00
pub_house = jsondata.CharField(
_("出版社"), null=True, blank=False, default=None, max_length=500
)
pub_year = jsondata.IntegerField(
_("出版年份"),
null=True,
blank=False,
validators=[MinValueValidator(1), MaxValueValidator(2999)],
)
pub_month = jsondata.IntegerField(
_("出版月份"),
null=True,
blank=True,
2023-01-05 03:06:13 -05:00
validators=[MinValueValidator(1), MaxValueValidator(12)],
)
binding = jsondata.CharField(
_("装订"), null=True, blank=True, default=None, max_length=500
)
pages = jsondata.IntegerField(_("页数"), blank=True, default=None)
series = jsondata.CharField(
_("丛书"), null=True, blank=True, default=None, max_length=500
)
2023-01-09 10:21:18 -05:00
contents = jsondata.TextField(_("目录"), null=True, blank=True, default=None)
2023-01-05 03:06:13 -05:00
price = jsondata.CharField(_("价格"), null=True, blank=True, max_length=500)
imprint = jsondata.CharField(_("出品方"), null=True, blank=True, max_length=500)
@property
def isbn10(self):
return isbn_13_to_10(self.isbn)
@isbn10.setter
def isbn10(self, value):
self.isbn = isbn_10_to_13(value)
2023-01-05 03:06:13 -05:00
@classmethod
def lookup_id_type_choices(cls):
id_types = [
IdType.ISBN,
IdType.ASIN,
IdType.CUBN,
IdType.DoubanBook,
IdType.Goodreads,
IdType.GoogleBooks,
]
return [(i.value, i.label) for i in id_types]
@classmethod
def lookup_id_cleanup(cls, lookup_id_type, lookup_id_value):
if lookup_id_type in [IdType.ASIN.value, IdType.ISBN.value]:
return detect_isbn_asin(lookup_id_value)
return super().lookup_id_cleanup(lookup_id_type, lookup_id_value)
2022-12-08 16:08:59 +00:00
def update_linked_items_from_external_resource(self, resource):
"""add Work from resource.metadata['work'] if not yet"""
links = resource.required_resources + resource.related_resources
for w in links:
2022-12-29 23:57:02 -05:00
if w["model"] == "Work":
work = Work.objects.filter(
primary_lookup_id_type=w["id_type"],
primary_lookup_id_value=w["id_value"],
).first()
if work and work not in self.works.all():
self.works.add(work)
# if not work:
2022-12-08 16:59:03 +00:00
# _logger.info(f'Unable to find link for {w["url"]}')
def get_related_books(self):
2023-02-13 00:52:24 -05:00
works = list(self.works.all())
return (
Edition.objects.filter(works__in=works)
.exclude(pk=self.pk)
.exclude(is_deleted=True)
.exclude(merged_to_item__isnull=False)
)
class Work(Item):
2022-12-11 23:20:28 +00:00
category = ItemCategory.Book
2022-12-29 23:57:02 -05:00
url_path = "book/work"
2022-12-11 23:20:28 +00:00
douban_work = PrimaryLookupIdDescriptor(IdType.DoubanBook_Work)
goodreads_work = PrimaryLookupIdDescriptor(IdType.Goodreads_Work)
2022-12-29 23:57:02 -05:00
editions = models.ManyToManyField(Edition, related_name="works")
class Series(Item):
2022-12-11 23:20:28 +00:00
category = ItemCategory.Book
2022-12-29 23:57:02 -05:00
url_path = "book/series"
# douban_serie = LookupIdDescriptor(IdType.DoubanBook_Serie)
# goodreads_serie = LookupIdDescriptor(IdType.Goodreads_Serie)
class Meta:
proxy = True