depicts/depicts/model.py

135 lines
4.5 KiB
Python

from sqlalchemy.ext.declarative import declarative_base
from .database import session, now_utc
from sqlalchemy.schema import Column, ForeignKey
from sqlalchemy.types import Integer, String, DateTime, Boolean
from sqlalchemy.orm import column_property, relationship, synonym
from sqlalchemy.ext.associationproxy import association_proxy
from sqlalchemy.ext.hybrid import hybrid_property
from sqlalchemy.sql.expression import cast
from sqlalchemy.dialects import postgresql
from urllib.parse import quote
Base = declarative_base()
Base.query = session.query_property()
class User(Base):
__tablename__ = 'user'
id = Column(Integer, primary_key=True, autoincrement=False)
username = Column(String, unique=True)
options = Column(postgresql.JSON)
first_seen = Column(DateTime, default=now_utc())
is_admin = Column(Boolean, default=False)
class DepictsItem(Base):
__tablename__ = 'depicts'
item_id = Column(Integer, primary_key=True, autoincrement=False)
label = Column(String)
description = Column(String)
commons = Column(String)
count = Column(Integer)
entity = Column(postgresql.JSON)
qid = column_property('Q' + cast(item_id, String))
db_alt_labels = relationship('DepictsItemAltLabel',
collection_class=set,
cascade='save-update, merge, delete, delete-orphan',
backref='item')
alt_labels = association_proxy('db_alt_labels', 'alt_label')
class DepictsItemAltLabel(Base):
__tablename__ = 'depicts_alt_label'
item_id = Column(Integer,
ForeignKey('depicts.item_id'),
primary_key=True,
autoincrement=False)
alt_label = Column(String, primary_key=True)
def __init__(self, alt_label):
self.alt_label = alt_label
class ArtworkItem(Base):
__tablename__ = 'artwork'
item_id = Column(Integer, primary_key=True, autoincrement=False)
label = Column(String)
entity = Column(postgresql.JSON)
qid = column_property('Q' + cast(item_id, String))
class HumanItem(Base):
__tablename__ = 'human'
item_id = Column(Integer, primary_key=True, autoincrement=False)
year_of_birth = Column(Integer, nullable=False)
year_of_death = Column(Integer, nullable=False)
age_at_death = column_property(year_of_death - year_of_birth)
qid = column_property('Q' + cast(item_id, String))
yob = synonym('year_of_birth')
yod = synonym('year_of_death')
class Language(Base):
__tablename__ = 'language'
item_id = Column(Integer, primary_key=True, autoincrement=False)
wikimedia_language_code = Column(String, index=True, unique=True)
en_label = Column(String, nullable=False)
code = synonym('wikimedia_language_code')
label = synonym('en_label')
@classmethod
def get_by_code(cls, code):
return cls.query.filter_by(wikimedia_language_code=code).one()
class Edit(Base):
__tablename__ = 'edit'
username = Column(String, primary_key=True)
artwork_id = Column(Integer, ForeignKey('artwork.item_id'), primary_key=True)
depicts_id = Column(Integer, ForeignKey('depicts.item_id'), primary_key=True)
timestamp = Column(DateTime, default=now_utc())
lastrevid = Column(Integer, nullable=True)
artwork_qid = column_property('Q' + cast(artwork_id, String))
depicts_qid = column_property('Q' + cast(depicts_id, String))
artwork = relationship('ArtworkItem')
depicts = relationship('DepictsItem')
@property
def url_norm_username(self):
return quote(self.username.replace(' ', '_'))
@property
def user_wikidata_url(self):
return 'https://www.wikidata.org/wiki/User:' + self.url_norm_username
class WikidataQuery(Base):
__tablename__ = 'wikidata_query'
id = Column(Integer, primary_key=True)
start_time = Column(DateTime)
end_time = Column(DateTime)
sparql_query = Column(String)
path = Column(String)
status_code = Column(Integer)
error_text = Column(String)
query_template = Column(String)
@property
def duration(self):
if self.end_time:
return self.end_time - self.start_time
@property
def display_seconds(self):
return f'{self.duration.total_seconds():.1f}'
@property
def template(self):
if not self.query_template:
return
t = self.query_template
if t.startswith('query/'):
t = t[6:]
if t.endswith('.sparql'):
t = t[:-7]
return t