bookwyrm/fedireads/models/book.py

88 lines
3.6 KiB
Python

''' database schema for books and shelves '''
from datetime import datetime
from django.db import models
from uuid import uuid4
from fedireads.settings import DOMAIN
from fedireads.utils.fields import JSONField, ArrayField
from fedireads.utils.models import FedireadsModel
class Book(FedireadsModel):
''' a generic book, which can mean either an edition or a work '''
# these identifiers apply to both works and editions
openlibrary_key = models.CharField(max_length=255, unique=True, null=True)
librarything_key = models.CharField(max_length=255, unique=True, null=True)
local_key = models.CharField(max_length=255, unique=True, default=uuid4)
misc_identifiers = JSONField(null=True)
# info about where the data comes from and where/if to sync
origin = models.CharField(max_length=255, unique=True, null=True)
local_edits = models.BooleanField(default=False)
sync = models.BooleanField(default=True)
last_sync_date = models.DateTimeField(default=datetime.now)
# TODO: edit history
# book/work metadata
title = models.CharField(max_length=255)
sort_title = models.CharField(max_length=255, null=True)
subtitle = models.TextField(blank=True, null=True)
description = models.TextField(blank=True, null=True)
language = models.CharField(max_length=255, null=True)
series = models.CharField(max_length=255, blank=True, null=True)
series_number = models.CharField(max_length=255, blank=True, null=True)
# TODO: include an annotation about the type of authorship (ie, translator)
authors = models.ManyToManyField('Author')
# TODO: also store cover thumbnail
cover = models.ImageField(upload_to='covers/', blank=True, null=True)
first_published_date = models.DateTimeField(null=True)
published_date = models.DateTimeField(null=True)
shelves = models.ManyToManyField(
'Shelf',
symmetrical=False,
through='ShelfBook',
through_fields=('book', 'shelf')
)
# TODO: why can't I just call this work????
parent_work = models.ForeignKey('Work', on_delete=models.PROTECT, null=True)
@property
def absolute_id(self):
''' constructs the absolute reference to any db object '''
base_path = 'https://%s' % DOMAIN
model_name = type(self).__name__.lower()
return '%s/%s/%s' % (base_path, model_name, self.openlibrary_key)
def __repr__(self):
return "<{} key={!r} title={!r} author={!r}>".format(self.__class__, self.openlibrary_key, self.title, self.author)
class Work(Book):
''' a work (an abstract concept of a book that manifests in an edition) '''
# library of congress catalog control number
lccn = models.CharField(max_length=255, unique=True, null=True)
class Edition(Book):
''' an edition of a book '''
# these identifiers only apply to work
isbn = models.CharField(max_length=255, unique=True, null=True)
oclc_number = models.CharField(max_length=255, unique=True, null=True)
pages = models.IntegerField(null=True)
class Author(FedireadsModel):
''' copy of an author from OL '''
openlibrary_key = models.CharField(max_length=255, null=True, unique=True)
wikipedia_link = models.CharField(max_length=255, blank=True, null=True)
# idk probably other keys would be useful here?
born = models.DateTimeField(null=True)
died = models.DateTimeField(null=True)
name = models.CharField(max_length=255)
last_name = models.CharField(max_length=255, null=True)
first_name = models.CharField(max_length=255, null=True)
aliases = ArrayField(models.CharField(max_length=255), blank=True, default=list)
bio = models.TextField(null=True, blank=True)