prepared transition to new table "Ausgabe": modified DB schema; added ORM model, Flask views, HTML templates, nav link
This commit is contained in:
parent
fe054b3460
commit
56520fc72d
@ -2,7 +2,7 @@ from flask import Flask
|
||||
import dotenv # this import is not strictly necessary but it forces pipreqs-to include dotenv when generating `requirements.txt`
|
||||
from the_works.database import init_db
|
||||
from the_works.models import SIMPLE_MODELS
|
||||
from the_works.views import home, text, werk, reihe, veroeffentlichung, titelbild
|
||||
from the_works.views import home, reihe, titelbild, text, veroeffentlichung, werk, ausgabe
|
||||
from the_works.views.simple_view import VIEWS, ViewAll, ViewCreate, ViewUpdate, ViewDelete
|
||||
|
||||
|
||||
@ -49,10 +49,11 @@ def create_app(config=None):
|
||||
# register blueprints for remaining views
|
||||
app.register_blueprint(home.bp)
|
||||
app.register_blueprint(reihe.bp)
|
||||
app.register_blueprint(text.bp)
|
||||
app.register_blueprint(werk.bp)
|
||||
app.register_blueprint(veroeffentlichung.bp)
|
||||
app.register_blueprint(titelbild.bp)
|
||||
app.register_blueprint(text.bp)
|
||||
app.register_blueprint(veroeffentlichung.bp)
|
||||
app.register_blueprint(werk.bp)
|
||||
app.register_blueprint(ausgabe.bp)
|
||||
|
||||
# register helper function
|
||||
app.jinja_env.globals.update(sizeof_fmt=sizeof_fmt)
|
||||
|
||||
@ -61,7 +61,8 @@ class Pseudonym(Base):
|
||||
ID: Mapped[int] = mapped_column(primary_key=True)
|
||||
Pseudonym: Mapped[str] = mapped_column(CheckConstraint('Pseudonym <> ""', name='PseudonymNotEmptyConstraint'), nullable=False, unique=True)
|
||||
|
||||
veroeffentlichung: Mapped[List['Veroeffentlichung']] = relationship(back_populates='pseudonym')
|
||||
veroeffentlichung: Mapped[List['Veroeffentlichung']] = relationship(back_populates='pseudonym') #TODO DELETE
|
||||
werk: Mapped[List['Werk']] = relationship(back_populates='pseudonym')
|
||||
|
||||
|
||||
class Sprache(Base):
|
||||
@ -88,8 +89,9 @@ class Verlag(Base):
|
||||
ID: Mapped[int] = mapped_column(primary_key=True)
|
||||
Verlag: Mapped[str] = mapped_column(CheckConstraint('Verlag <> ""', name='VerlagNotEmptyConstraint'), nullable=False, unique=True)
|
||||
|
||||
ausgabe: Mapped[List['Ausgabe']] = relationship(back_populates='verlag')
|
||||
reihe: Mapped[List['Reihe']] = relationship(back_populates='verlag')
|
||||
werk: Mapped[List['Werk']] = relationship(back_populates='verlag')
|
||||
werk: Mapped[List['Werk']] = relationship(back_populates='verlag') #TODO DELETE
|
||||
|
||||
|
||||
class Werksform(Base):
|
||||
@ -98,10 +100,11 @@ class Werksform(Base):
|
||||
ID: Mapped[int] = mapped_column(primary_key=True)
|
||||
Werksform: Mapped[str] = mapped_column(CheckConstraint('Werksform <> ""', name='WerksformNotEmptyConstraint'), nullable=False, unique=True)
|
||||
|
||||
werk: Mapped[List['Werk']] = relationship(back_populates='werksform')
|
||||
ausgabe: Mapped[List['Ausgabe']] = relationship(back_populates='werksform')
|
||||
werk: Mapped[List['Werk']] = relationship(back_populates='werksform') #TODO DELETE
|
||||
|
||||
|
||||
# Classes that have more than one column and need dedicated view functions
|
||||
# Classes that have more than one column and need their own view functions
|
||||
|
||||
class Reihe(Base):
|
||||
__tablename__ = 'Reihe'
|
||||
@ -129,7 +132,9 @@ class Titelbild(Base):
|
||||
Thumbnail: Mapped[bytes] = mapped_column(nullable=False)
|
||||
sha256: Mapped[str] = mapped_column(CheckConstraint('sha256 <> ""', name='sha256NotEmptyConstraint'), nullable=False, unique=True)
|
||||
|
||||
werk: Mapped[List['Werk']] = relationship(back_populates='titelbild')
|
||||
# one-to-many
|
||||
ausgabe: Mapped[List['Ausgabe']] = relationship(back_populates='titelbild')
|
||||
werk: Mapped[List['Werk']] = relationship(back_populates='titelbild') #DELETE
|
||||
|
||||
def asdict_with_urls(self):
|
||||
tb = self.asdict()
|
||||
@ -162,42 +167,6 @@ class Text(Base):
|
||||
genre_ids: AssociationProxy[List["Genre"]] = association_proxy("genres", "Genre", creator=lambda genre_id: Text_Genre(Genre=genre_id))
|
||||
|
||||
|
||||
class Werk(Base):
|
||||
__tablename__ = 'Werk'
|
||||
|
||||
# regular columns
|
||||
ID: Mapped[int] = mapped_column(primary_key=True)
|
||||
Titel: Mapped[str] = mapped_column(CheckConstraint('Titel <> ""', name='WerkstitelNotEmptyConstraint'), nullable=False)
|
||||
Untertitel: Mapped[Optional[str]]
|
||||
Reihennummer: Mapped[Optional[str]]
|
||||
Erscheinungsdatum: Mapped[Optional[str]]
|
||||
ISBN_13: Mapped[Optional[str]]
|
||||
ISBN_10: Mapped[Optional[str]]
|
||||
ISSN: Mapped[Optional[str]]
|
||||
Preis: Mapped[Optional[str]]
|
||||
Klappentext: Mapped[Optional[str]]
|
||||
Anmerkungen: Mapped[Optional[str]]
|
||||
|
||||
# many-to-one
|
||||
Reihe: Mapped[Optional[int]] = mapped_column(ForeignKey('Reihe.ID'))
|
||||
reihe: Mapped[Optional['Reihe']] = relationship(back_populates='werk')
|
||||
Titelbild: Mapped[Optional[int]] = mapped_column(ForeignKey('Titelbild.ID'))
|
||||
titelbild: Mapped[Optional['Titelbild']] = relationship(back_populates='werk')
|
||||
Verlag: Mapped[Optional[int]] = mapped_column(ForeignKey('Verlag.ID'))
|
||||
verlag: Mapped[Optional['Verlag']] = relationship(back_populates='werk')
|
||||
Werksform: Mapped[int] = mapped_column(ForeignKey('Werksform.ID'), nullable=False)
|
||||
werksform: Mapped['Werksform'] = relationship(back_populates='werk')
|
||||
|
||||
# one-to-many
|
||||
veroeffentlichung: Mapped[List['Veroeffentlichung']] = relationship(back_populates='werk')
|
||||
|
||||
# many-to-many
|
||||
genres: Mapped[List['Werk_Genre']] = relationship(back_populates='werk', cascade='all, delete-orphan')
|
||||
genre_ids: AssociationProxy[List["Genre"]] = association_proxy("genres", "Genre", creator=lambda genre_id: Werk_Genre(Genre=genre_id))
|
||||
herausgeber: Mapped[List['Werk_Herausgeber']] = relationship(back_populates='werk', cascade="all, delete-orphan")
|
||||
herausgeber_ids: AssociationProxy[List['Herausgeber']] = association_proxy("herausgeber", "Herausgeber", creator=lambda hrsg_id: Werk_Herausgeber(Herausgeber=hrsg_id))
|
||||
|
||||
|
||||
class Veroeffentlichung(Base):
|
||||
__tablename__ = 'Veroeffentlichung'
|
||||
|
||||
@ -207,14 +176,77 @@ class Veroeffentlichung(Base):
|
||||
AltUntertitel: Mapped[Optional[str]]
|
||||
|
||||
# many-to-one
|
||||
Pseudonym: Mapped[int] = mapped_column(ForeignKey('Pseudonym.ID'), nullable=False)
|
||||
pseudonym: Mapped['Pseudonym'] = relationship(back_populates='veroeffentlichung')
|
||||
Pseudonym: Mapped[int] = mapped_column(ForeignKey('Pseudonym.ID'), nullable=False) #TODO DELETE
|
||||
pseudonym: Mapped['Pseudonym'] = relationship(back_populates='veroeffentlichung') #TODO DELETE
|
||||
Text: Mapped[int] = mapped_column(ForeignKey('Text.ID'), nullable=False)
|
||||
text: Mapped['Text'] = relationship(back_populates='veroeffentlichung')
|
||||
Werk: Mapped[int] = mapped_column(ForeignKey('Werk.ID'), nullable=False)
|
||||
werk: Mapped['Werk'] = relationship(back_populates='veroeffentlichung')
|
||||
|
||||
|
||||
class Werk(Base):
|
||||
__tablename__ = 'Werk'
|
||||
|
||||
# regular columns
|
||||
ID: Mapped[int] = mapped_column(primary_key=True)
|
||||
Titel: Mapped[str] = mapped_column(CheckConstraint('Titel <> ""', name='WerkstitelNotEmptyConstraint'), nullable=False)
|
||||
Untertitel: Mapped[Optional[str]]
|
||||
Reihennummer: Mapped[Optional[str]]
|
||||
Erscheinungsdatum: Mapped[Optional[str]] #TODO DELETE
|
||||
ISBN_13: Mapped[Optional[str]] #TODO DELETE
|
||||
ISBN_10: Mapped[Optional[str]] #TODO DELETE
|
||||
ISSN: Mapped[Optional[str]] #TODO DELETE
|
||||
Preis: Mapped[Optional[str]] #TODO DELETE
|
||||
Klappentext: Mapped[Optional[str]] #TODO DELETE
|
||||
Anmerkungen: Mapped[Optional[str]] #TODO DELETE
|
||||
|
||||
# many-to-one
|
||||
Pseudonym: Mapped[int] = mapped_column(ForeignKey('Pseudonym.ID'))
|
||||
pseudonym: Mapped['Pseudonym'] = relationship(back_populates='werk')
|
||||
Reihe: Mapped[Optional[int]] = mapped_column(ForeignKey('Reihe.ID'))
|
||||
reihe: Mapped[Optional['Reihe']] = relationship(back_populates='werk')
|
||||
Titelbild: Mapped[Optional[int]] = mapped_column(ForeignKey('Titelbild.ID')) #TODO DELETE
|
||||
titelbild: Mapped[Optional['Titelbild']] = relationship(back_populates='werk') #TODO DELETE
|
||||
Verlag: Mapped[Optional[int]] = mapped_column(ForeignKey('Verlag.ID')) #TODO DELETE
|
||||
verlag: Mapped[Optional['Verlag']] = relationship(back_populates='werk') #TODO DELETE
|
||||
Werksform: Mapped[int] = mapped_column(ForeignKey('Werksform.ID'), nullable=False) #TODO DELETE
|
||||
werksform: Mapped['Werksform'] = relationship(back_populates='werk') #TODO DELETE
|
||||
|
||||
# one-to-many
|
||||
ausgabe: Mapped[List['Ausgabe']] = relationship(back_populates='werk')
|
||||
veroeffentlichung: Mapped[List['Veroeffentlichung']] = relationship(back_populates='werk')
|
||||
|
||||
# many-to-many
|
||||
genres: Mapped[List['Werk_Genre']] = relationship(back_populates='werk', cascade='all, delete-orphan')
|
||||
genre_ids: AssociationProxy[List["Genre"]] = association_proxy("genres", "Genre", creator=lambda genre_id: Werk_Genre(Genre=genre_id))
|
||||
herausgeber: Mapped[List['Werk_Herausgeber']] = relationship(back_populates='werk', cascade="all, delete-orphan")
|
||||
herausgeber_ids: AssociationProxy[List['Herausgeber']] = association_proxy("herausgeber", "Herausgeber", creator=lambda hrsg_id: Werk_Herausgeber(Herausgeber=hrsg_id))
|
||||
|
||||
|
||||
class Ausgabe(Base):
|
||||
__tablename__ = 'Ausgabe'
|
||||
|
||||
# regular columns
|
||||
ID: Mapped[int] = mapped_column(primary_key=True)
|
||||
Erscheinungsdatum: Mapped[Optional[str]]
|
||||
ISBN_13: Mapped[Optional[str]]
|
||||
ISBN_10: Mapped[Optional[str]]
|
||||
ISSN: Mapped[Optional[str]]
|
||||
Preis: Mapped[Optional[str]]
|
||||
Klappentext: Mapped[Optional[str]]
|
||||
Anmerkungen: Mapped[Optional[str]]
|
||||
|
||||
# many-to-one
|
||||
Titelbild: Mapped[Optional[int]] = mapped_column(ForeignKey('Titelbild.ID'))
|
||||
titelbild: Mapped[Optional['Titelbild']] = relationship(back_populates='ausgabe')
|
||||
Verlag: Mapped[Optional[int]] = mapped_column(ForeignKey('Verlag.ID'))
|
||||
verlag: Mapped[Optional['Verlag']] = relationship(back_populates='ausgabe')
|
||||
Werk: Mapped[int] = mapped_column(ForeignKey('Werk.ID'), nullable=False)
|
||||
werk: Mapped["Werk"] = relationship(back_populates='ausgabe')
|
||||
Werksform: Mapped[int] = mapped_column(ForeignKey('Werksform.ID'), nullable=False)
|
||||
werksform: Mapped['Werksform'] = relationship(back_populates='ausgabe')
|
||||
|
||||
|
||||
# Additional tables for many-to-many-relationships within the DB
|
||||
|
||||
class Text_Genre(Base):
|
||||
@ -245,4 +277,3 @@ class Werk_Herausgeber(Base):
|
||||
|
||||
werk: Mapped['Werk'] = relationship(back_populates="herausgeber")
|
||||
herausgeber: Mapped['Herausgeber'] = relationship(back_populates="werke")
|
||||
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
{% set menu = (
|
||||
("Texte", url_for("text.all")),
|
||||
("Werke", url_for("werk.all")),
|
||||
("Veröffentlichungen", url_for("veroeffentlichung.all")),
|
||||
("Werke", url_for("werk.all")),
|
||||
("Ausgaben", url_for("ausgabe.all")),
|
||||
("Basisdaten", (
|
||||
("Genres", url_for("genre.all")),
|
||||
("Herausgeber:innen", url_for("herausgeber.all")),
|
||||
|
||||
94
the_works/templates/views/ausgabe.html
Normal file
94
the_works/templates/views/ausgabe.html
Normal file
@ -0,0 +1,94 @@
|
||||
{% extends 'base.html' %}
|
||||
|
||||
{% block title %}Ausgaben{% endblock title %}
|
||||
|
||||
{% block head %}
|
||||
<link type="text/css" rel="stylesheet" href="{{ url_for('static', filename='datatables.css') }}">
|
||||
{% endblock head %}
|
||||
|
||||
{% block heading %}Ausgaben{% endblock heading %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
{% include "_icons.svg" %}
|
||||
|
||||
<div class="overflow-auto">
|
||||
<table id="ausgabe-table" class="striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Werk</th>
|
||||
<th>Werksform</th>
|
||||
<th>Verlag</th>
|
||||
<th>Preis</th>
|
||||
<th>Erscheinungsdatum</th>
|
||||
<th>ISBN_13</th>
|
||||
<th>ISBN_10</th>
|
||||
<th>ISSN</th>
|
||||
<th>Titelbild</th>
|
||||
<th>Klappentext</th>
|
||||
<th>Anmerkungen</th>
|
||||
<th colspan="2">Aktionen</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for ausgabe in ausgaben %}
|
||||
<tr id="ausgabe-{{ ausgabe['id'] }}">
|
||||
<td title="Werk">{{ ausgabe["Werk"] }}</td>
|
||||
<td title="Werksform">{{ ausgabe["Werksform"] }}</td>
|
||||
<td title="Verlag">{{ ausgabe["Verlag"] }}</td>
|
||||
<td title="Preis">{{ ausgabe["Preis"] }}</td>
|
||||
<td title="Erscheinungsdatum">{{ ausgabe["Erscheinungsdatum"] }}</td>
|
||||
<td title="ISBN_13">{{ ausgabe["ISBN_13"] }}</td>
|
||||
<td title="ISBN_10">{{ ausgabe["ISBN_10"] }}</td>
|
||||
<td title="ISSN">{{ ausgabe["ISSN"] }}</td>
|
||||
<td title="Titelbild">
|
||||
{% if ausgabe["Titelbild"] %}
|
||||
<div class="imageselect-entry" data-bild="{{ ausgabe['Titelbild']['Bild'] }}">
|
||||
<div class="imageselect-div">
|
||||
<img src="{{ ausgabe['Titelbild']['Thumbnail'] }}" width="128" height="128" alt="Titelbild (Thumbnail)" />
|
||||
<span class="imageselect-label display-none">
|
||||
{{ ausgabe['Titelbild']['Dateiname'] }} ({{ ausgabe['Titelbild']['Breite'] }} x {{ ausgabe['Titelbild']['Hoehe'] }}, {{ ausgabe['Titelbild']['Dateigroesse'] }} Bytes)
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
✘
|
||||
{% endif %}
|
||||
</td>
|
||||
<td title="Klappentext"{% if ausgabe["Klappentext"] %} data-tooltip="{{ ausgabe['Klappentext'] | replace('\n', ' ') | safe }}" data-placement="bottom">✔{% else %}>✘{% endif %}</td>
|
||||
<td title="Anmerkungen">{{ ausgabe["Anmerkungen"] }}</td>
|
||||
<td class="action action-update" data-id="{{ ausgabe['id'] }}"><a href="{{ url_for('ausgabe.read', id=ausgabe['id']) }}" title="Ausgabe ansehen/bearbeiten"><svg viewbox="0 0 24 24"><use href="#update" /></svg></a></td>
|
||||
<td id="delete-{{ ausgabe['id'] }}" class="action"><a onclick="return confirm('Eintrag wirklich löschen?');" href="{{ url_for('ausgabe.delete', id=ausgabe['id']) }}" title="Ausgabe löschen"><svg viewbox="0 0 24 24"><use href="#delete" /></svg></a></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<dialog id="imagepreview-modal" closedby="any">
|
||||
<article>
|
||||
<header>
|
||||
<button class="modal-close" aria-label="close" rel="prev"></button>
|
||||
<div class="imagepreview-details"></div>
|
||||
</header>
|
||||
<div class="imagepreview-div">
|
||||
<img src="" />
|
||||
</div>
|
||||
</article>
|
||||
</dialog>
|
||||
|
||||
{% endblock content %}
|
||||
|
||||
{% block script %}
|
||||
<script src="{{ url_for('static', filename='js/datatables.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/init_dt.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/imagepreview.js') }}"></script>
|
||||
<script>
|
||||
window.onload = () => {
|
||||
initDataTable("ausgabe-table");
|
||||
initCreateButton("ausgabe-table", "Ausgabe hinzufügen", "{{ url_for('ausgabe.read', id=0) }}");
|
||||
initImagepreview("imagepreview-modal");
|
||||
}
|
||||
</script>
|
||||
{% endblock script %}
|
||||
|
||||
163
the_works/templates/views/ausgabe_detail.html
Normal file
163
the_works/templates/views/ausgabe_detail.html
Normal file
@ -0,0 +1,163 @@
|
||||
{% extends 'base.html' %}
|
||||
{% set create_mode = (ausgabe['ID'] == 0) %}
|
||||
|
||||
{% block title %}
|
||||
{% if create_mode %}
|
||||
Neue Ausgabe erstellen
|
||||
{% else %}
|
||||
Ausgabe bearbeiten
|
||||
{% endif %}
|
||||
{% endblock title %}
|
||||
|
||||
{% block head %}
|
||||
{% endblock head %}
|
||||
|
||||
{% block heading %}
|
||||
{% if create_mode %}
|
||||
Neue Ausgabe erstellen
|
||||
{% else %}
|
||||
Ausgabe bearbeiten
|
||||
{% endif %}
|
||||
{% endblock heading %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
{% include "_icons.svg" %}
|
||||
|
||||
<form id="ausgabe_detail_form" method="post" enctype="multipart/form-data" action="#">
|
||||
<section>
|
||||
<label>
|
||||
<span class="required">Werk</span>
|
||||
<select id="form_Werk" name="form_Werk" aria-label="Werk" required>
|
||||
<option value="">bitte wählen …</option>
|
||||
{% for w in werke %}<option value="{{ w.ID }}"{% if w.ID == ausgabe['Werk'] %} selected{% endif %}>{{ w.Titel }}</option>{% endfor %}
|
||||
</select>
|
||||
</label>
|
||||
</section>
|
||||
<hr />
|
||||
<section class="grid">
|
||||
<div>
|
||||
<label>
|
||||
<span class="required">Werksform</span>
|
||||
<select id="form_Werksform" name="form_Werksform" aria-label="Werksform" required>
|
||||
<option value="">bitte wählen …</option>
|
||||
{% for wf in werksformen %}<option value="{{ wf.ID }}"{% if wf.ID == ausgabe['Werksform'] %} selected{% endif %}>{{ wf.Werksform }}</option>{% endfor %}
|
||||
</select>
|
||||
</label>
|
||||
<label>
|
||||
Verlag
|
||||
<select id="form_Verlag" name="form_Verlag" aria-label="Verlag">
|
||||
<option selected value="">kein Verlag</option>
|
||||
{% for v in verlage %}<option value="{{ v.ID }}"{% if v.ID == ausgabe['Verlag'] %} selected{% endif %}>{{ v.Verlag }}</option>{% endfor %}
|
||||
</select>
|
||||
</label>
|
||||
<label>
|
||||
Preis
|
||||
<input id="form_Preis" name="form_Preis" aria-label="Preis" placeholder="kein Preis" value="{{ ausgabe['Preis'] or '' }}" />
|
||||
</label>
|
||||
<label>
|
||||
Titelbild
|
||||
<details id="form_Titelbild_dropdown" class="dropdown imageselect">
|
||||
<summary id="form_Titelbild_summary" class="imageselect-summary">
|
||||
</summary>
|
||||
<ul>
|
||||
<li class="imageselect-entry" data-bild='<svg width="900" height="1280" viewbox="0 0 90 128"><use class="imageselect-svg" href="#placeholder" /></svg>'>
|
||||
<div class="imageselect-input">
|
||||
<input id="imageselect-radio-0" type="radio" name="form_Titelbild" value="" {% if not ausgabe['Titelbild'] %}checked{% endif %}/>
|
||||
</div>
|
||||
<div class="imageselect-div">
|
||||
<svg viewbox="0 0 90 128">
|
||||
<use class="imageselect-svg" href="#placeholder" />
|
||||
</svg>
|
||||
</div>
|
||||
<div class="imageselect-title">
|
||||
<label class="imageselect-label" for="imageselect-radio-0">kein Titelbild</label>
|
||||
</div>
|
||||
</li>
|
||||
{% for t in titelbilder %}
|
||||
<li class="imageselect-entry" data-bild="{{ t.Bild }}">
|
||||
<div class="imageselect-input">
|
||||
<input id="imageselect-radio-{{ t.ID }}" type="radio" name="form_Titelbild" value="{{ t.ID }}" {% if ausgabe['Titelbild'] == t.ID %}checked{% endif %}/>
|
||||
</div>
|
||||
<div class="imageselect-div">
|
||||
<img class="imageselect-img" src="{{ t.Thumbnail }}" />
|
||||
</div>
|
||||
<div class="imageselect-title">
|
||||
<label class="imageselect-label" for="imageselect-radio-{{ t.ID }}">{{ t.Dateiname }} ({{ t.Breite }} x {{ t.Hoehe }}, {{ t.Dateigroesse }} Bytes)</label>
|
||||
</div>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</details>
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<label>
|
||||
Erscheinungsdatum (TT-MM-JJJJ, MM-JJJJ, JJJJ oder leer)
|
||||
<div class="grid">
|
||||
<input type="number" min="1" max="31" id="form_Erscheinungstag" name="form_Erscheinungstag" aria-label="Erscheinungstag" placeholder="Tag" value="{{ ausgabe['Erscheinungsdatum'][8:] if ausgabe['Erscheinungsdatum'] }}" />
|
||||
<input type="number" min="1" max="12" id="form_Erscheinungsmonat" name="form_Erscheinungsmonat" aria-label="Erscheinungsmonat" placeholder="Monat" value="{{ ausgabe['Erscheinungsdatum'][5:7] if ausgabe['Erscheinungsdatum'] }}" />
|
||||
<input type="number" min="1980" max="2100" id="form_Erscheinungsjahr" name="form_Erscheinungsjahr" aria-label="Erscheinungsjahr" placeholder="Jahr" value="{{ ausgabe['Erscheinungsdatum'][:4] if ausgabe['Erscheinungsdatum'] }}" />
|
||||
</div>
|
||||
</label>
|
||||
<label>
|
||||
ISBN-13
|
||||
<input id="form_ISBN_13" name="form_ISBN_13" aria-label="ISBN-13" placeholder="keine ISBN-13" value="{{ ausgabe['ISBN_13'] or '' }}" />
|
||||
</label>
|
||||
<label>
|
||||
ISBN-10
|
||||
<input id="form_ISBN_10" name="form_ISBN_10" aria-label="ISBN-10" placeholder="keine ISBN-10" value="{{ ausgabe['ISBN_10'] or '' }}" />
|
||||
</label>
|
||||
<label>
|
||||
ISSN
|
||||
<input id="form_ISSN" name="form_ISSN" aria-label="ISSN" placeholder="keine ISSN" value="{{ ausgabe['ISSN'] or '' }}" />
|
||||
</label>
|
||||
</div>
|
||||
</section>
|
||||
<hr />
|
||||
<section class="grid">
|
||||
<label>
|
||||
Klappentext
|
||||
<textarea id="form_Klappentext" name="form_Klappentext" aria-label="Klappentext" placeholder="kein Klappentext" rows="10">{{ ausgabe['Klappentext'] or '' }}</textarea>
|
||||
</label>
|
||||
<label>
|
||||
Anmerkungen
|
||||
<textarea id="form_Anmerkungen" name="form_Anmerkungen" aria-label="Anmerkungen" placeholder="keine Anmerkungen" rows="10">
|
||||
{{ ausgabe['Anmerkungen'] or '' }}</textarea>
|
||||
</label>
|
||||
</section>
|
||||
|
||||
<footer class="grid">
|
||||
<button id="form_submit" type="submit" onclick="return validate_date()" formmethod="post" formaction="{% if create_mode %}{{ url_for('ausgabe.create') }}{% else %}{{ url_for('ausgabe.update', id=ausgabe['ID']) }}{% endif %}">
|
||||
{% if create_mode %}Eintrag speichern{% else %}Änderungen speichern{% endif %}
|
||||
</button>
|
||||
<button type="reset" onclick="return confirm('Wirklich zurücksetzen? Alle geänderten Daten gehen dabei verloren.');" title="Alle Felder auf den vorherigen Zustand zurücksetzen">Alles zurücksetzen</button>
|
||||
<a role="button" class="contrast" href="{{ url_for('ausgabe.all') }}">Abbrechen (nicht speichern)</a>
|
||||
</footer>
|
||||
</form>
|
||||
|
||||
<dialog id="imagepreview-modal" closedby="any">
|
||||
<article>
|
||||
<header>
|
||||
<button class="modal-close" aria-label="close" rel="prev"></button>
|
||||
<div class="imagepreview-details"></div>
|
||||
</header>
|
||||
<div class="imagepreview-div" />
|
||||
</article>
|
||||
</dialog>
|
||||
|
||||
{% endblock content %}
|
||||
|
||||
{% block script %}
|
||||
<script src="{{ url_for('static', filename='js/imageselect.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/imagepreview.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/validate_date.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/datalosswarning.js') }}"></script>
|
||||
<script>
|
||||
window.onload = () => {
|
||||
initImageselect("form_Titelbild_dropdown");
|
||||
initImagepreview("imagepreview-modal");
|
||||
initDatalosswarning();
|
||||
}
|
||||
</script>
|
||||
{% endblock script %}
|
||||
116
the_works/views/ausgabe.py
Normal file
116
the_works/views/ausgabe.py
Normal file
@ -0,0 +1,116 @@
|
||||
from flask import Blueprint, render_template, request, redirect, flash, url_for
|
||||
from sqlalchemy import select
|
||||
from the_works.database import db
|
||||
from the_works.models import Ausgabe, Werk, Verlag, Werksform, Titelbild
|
||||
|
||||
bp = Blueprint("ausgabe", __name__)
|
||||
|
||||
|
||||
@bp.route("/ausgabe/")
|
||||
@bp.route("/ausgabe/all/")
|
||||
def all():
|
||||
# select all rows from table "Ausgabe", ORM style
|
||||
rows = db.session.execute(select(Ausgabe, Titelbild, Verlag, Werk, Werksform).join(Ausgabe.titelbild, isouter=True).join(Ausgabe.verlag, isouter=True).join(Ausgabe.werk, isouter=True).join(Ausgabe.werksform, isouter=True))
|
||||
# condense result into list of dicts
|
||||
ausgaben = []
|
||||
for row in rows:
|
||||
ausgaben.append({
|
||||
"id": row.Ausgabe.ID,
|
||||
"Werk": row.Werk.Titel if row.Werk else "",
|
||||
"Werksform": row.Werksform.Werksform if row.Werksform else "",
|
||||
"Verlag": row.Verlag.Verlag if row.Verlag else "",
|
||||
"Erscheinungsdatum": row.Ausgabe.Erscheinungsdatum or "",
|
||||
"ISBN_13": row.Ausgabe.ISBN_13 or "",
|
||||
"ISBN_10": row.Ausgabe.ISBN_10 or "",
|
||||
"ISSN": row.Ausgabe.ISSN or "",
|
||||
"Preis": row.Ausgabe.Preis or "",
|
||||
"Titelbild": db.session.get(Titelbild, row.Ausgabe.Titelbild).asdict_with_urls() if row.Titelbild else "",
|
||||
"Klappentext": row.Ausgabe.Klappentext or "",
|
||||
"Anmerkungen": row.Ausgabe.Anmerkungen or "",
|
||||
})
|
||||
return render_template("views/ausgabe.html", ausgaben=ausgaben)
|
||||
|
||||
|
||||
@bp.route("/ausgabe/read/<int:id>")
|
||||
def read(id):
|
||||
# prepare Titelbilder as dict including URLs for thumbnail and full pic
|
||||
titelbilder = map(lambda t: t.asdict_with_urls(), db.session.scalars(select(Titelbild)))
|
||||
|
||||
# id of zero -> return empty data
|
||||
if id == 0:
|
||||
return render_template("views/ausgabe_detail.html", ausgabe={"ID": 0, "Erscheinungsdatum": ""}, werke=db.session.scalars(select(Werk)), verlage=db.session.scalars(select(Verlag)), werksformen=db.session.scalars(select(Werksform)), titelbilder=titelbilder)
|
||||
|
||||
# all other ids -> read existing entry from DB and return as dict
|
||||
a = db.session.get(Ausgabe, id)
|
||||
if not a:
|
||||
raise ValueError(f"Ausgabe with ID {id} not found")
|
||||
ausgabe = a.asdict()
|
||||
|
||||
return render_template("views/ausgabe_detail.html", ausgabe=ausgabe, werke=db.session.scalars(select(Werk)), verlage=db.session.scalars(select(Verlag)), werksformen=db.session.scalars(select(Werksform)), titelbilder=titelbilder)
|
||||
|
||||
|
||||
|
||||
@bp.route("/ausgabe/create/", methods=["POST"])
|
||||
def create():
|
||||
ausgabe = Ausgabe(
|
||||
Werk = request.form["form_Werk"],
|
||||
Werksform = request.form["form_Werksform"],
|
||||
Verlag = request.form["form_Verlag"] or None,
|
||||
Erscheinungsdatum = _get_datum(request.form["form_Erscheinungsjahr"], request.form["form_Erscheinungsmonat"], request.form["form_Erscheinungstag"]),
|
||||
ISBN_13 = request.form["form_ISBN_13"] or None,
|
||||
ISBN_10 = request.form["form_ISBN_10"] or None,
|
||||
ISSN = request.form["form_ISSN"] or None,
|
||||
Preis = request.form["form_Preis"] or None,
|
||||
Titelbild = request.form["form_Titelbild"] or None,
|
||||
Klappentext = request.form["form_Klappentext"] or None,
|
||||
Anmerkungen = request.form["form_Anmerkungen"] or None
|
||||
)
|
||||
db.session.add(ausgabe)
|
||||
db.session.commit()
|
||||
flash("Eintrag erfolgreich hinzugefügt")
|
||||
return redirect(url_for("ausgabe.all"))
|
||||
|
||||
|
||||
@bp.route("/ausgabe/update/<int:id>", methods=["POST"])
|
||||
def update(id):
|
||||
# get record
|
||||
ausgabe = db.session.get(Ausgabe, id)
|
||||
|
||||
# update values
|
||||
ausgabe.Werk = request.form["form_Werkl"]
|
||||
ausgabe.Werksform = request.form["form_Werksform"]
|
||||
ausgabe.Verlag = request.form["form_Verlag"] or None
|
||||
ausgabe.Erscheinungsdatum = _get_datum(request.form["form_Erscheinungsjahr"], request.form["form_Erscheinungsmonat"], request.form["form_Erscheinungstag"])
|
||||
ausgabe.ISBN_13 = request.form["form_ISBN_13"] or None
|
||||
ausgabe.ISBN_10 = request.form["form_ISBN_10"] or None
|
||||
ausgabe.ISSN = request.form["form_ISSN"] or None
|
||||
ausgabe.Preis = request.form["form_Preis"] or None
|
||||
ausgabe.Titelbild = request.form["form_Titelbild"] or None
|
||||
ausgabe.Klappentext = request.form["form_Klappentext"] or None
|
||||
ausgabe.Anmerkungen = request.form["form_Anmerkungen"] or None
|
||||
|
||||
# commit changes
|
||||
db.session.commit()
|
||||
flash("Eintrag erfolgreich geändert")
|
||||
return redirect(url_for("ausgabe.all"))
|
||||
|
||||
|
||||
@bp.route("/ausgabe/delete/<int:id>")
|
||||
def delete(id):
|
||||
ausgabe = db.session.get(Werk, id)
|
||||
db.session.delete(ausgabe)
|
||||
db.session.commit()
|
||||
flash("Eintrag erfolgreich gelöscht")
|
||||
return redirect(url_for("ausgabe.all"))
|
||||
|
||||
|
||||
def _get_datum(jahr, monat, tag):
|
||||
if tag != "":
|
||||
return "-".join([jahr, monat.zfill(2), tag.zfill(2)])
|
||||
elif monat != "":
|
||||
return "-".join([jahr, monat.zfill(2)])
|
||||
elif jahr != "":
|
||||
return jahr
|
||||
else:
|
||||
return None
|
||||
|
||||
155
utils/schema.sql
155
utils/schema.sql
@ -1,65 +1,19 @@
|
||||
BEGIN TRANSACTION;
|
||||
DROP TABLE IF EXISTS "Genre";
|
||||
CREATE TABLE "Genre" (
|
||||
"ID" INTEGER,
|
||||
"Genre" TEXT NOT NULL,
|
||||
PRIMARY KEY("ID" AUTOINCREMENT)
|
||||
);
|
||||
DROP TABLE IF EXISTS "Herausgeber";
|
||||
CREATE TABLE "Herausgeber" (
|
||||
"ID" INTEGER,
|
||||
"Name" TEXT NOT NULL,
|
||||
PRIMARY KEY("ID" AUTOINCREMENT)
|
||||
);
|
||||
DROP TABLE IF EXISTS "Pseudonym";
|
||||
CREATE TABLE "Pseudonym" (
|
||||
"ID" INTEGER,
|
||||
"Pseudonym" TEXT NOT NULL,
|
||||
PRIMARY KEY("ID" AUTOINCREMENT)
|
||||
);
|
||||
DROP TABLE IF EXISTS "Reihe";
|
||||
CREATE TABLE "Reihe" (
|
||||
CREATE TABLE sqlite_sequence(name,seq);
|
||||
CREATE TABLE IF NOT EXISTS "Reihe" (
|
||||
"ID" INTEGER,
|
||||
"Titel" TEXT NOT NULL,
|
||||
"Verlag" TEXT,
|
||||
PRIMARY KEY("ID" AUTOINCREMENT),
|
||||
FOREIGN KEY("Verlag") REFERENCES "Verlag"("ID")
|
||||
);
|
||||
DROP TABLE IF EXISTS "Sprache";
|
||||
CREATE TABLE "Sprache" (
|
||||
"ID" INTEGER,
|
||||
"Sprache" TEXT NOT NULL,
|
||||
PRIMARY KEY("ID" AUTOINCREMENT)
|
||||
);
|
||||
DROP TABLE IF EXISTS "Text";
|
||||
CREATE TABLE "Text" (
|
||||
"ID" INTEGER,
|
||||
"Titel" TEXT NOT NULL,
|
||||
"Untertitel" TEXT,
|
||||
"Reihe" INTEGER,
|
||||
"Textform" INTEGER,
|
||||
"Sprache" INTEGER,
|
||||
PRIMARY KEY("ID" AUTOINCREMENT),
|
||||
FOREIGN KEY("Reihe") REFERENCES "Reihe"("ID"),
|
||||
FOREIGN KEY("Sprache") REFERENCES "Sprache"("ID"),
|
||||
FOREIGN KEY("Textform") REFERENCES "Textform"("ID")
|
||||
);
|
||||
DROP TABLE IF EXISTS "Text_Genre";
|
||||
CREATE TABLE "Text_Genre" (
|
||||
CREATE TABLE IF NOT EXISTS "Text_Genre" (
|
||||
"Text" INTEGER,
|
||||
"Genre" INTEGER,
|
||||
PRIMARY KEY("Text","Genre"),
|
||||
FOREIGN KEY("Genre") REFERENCES "Genre"("ID"),
|
||||
FOREIGN KEY("Text") REFERENCES "Text"("ID")
|
||||
);
|
||||
DROP TABLE IF EXISTS "Textform";
|
||||
CREATE TABLE "Textform" (
|
||||
"ID" INTEGER,
|
||||
"Textform" TEXT NOT NULL,
|
||||
PRIMARY KEY("ID" AUTOINCREMENT)
|
||||
);
|
||||
DROP TABLE IF EXISTS "Titelbild";
|
||||
CREATE TABLE "Titelbild" (
|
||||
CREATE TABLE IF NOT EXISTS "Titelbild" (
|
||||
"ID" INTEGER,
|
||||
"Mimetype" TEXT NOT NULL,
|
||||
"Dateiname" TEXT NOT NULL,
|
||||
@ -71,31 +25,58 @@ CREATE TABLE "Titelbild" (
|
||||
"sha256" TEXT NOT NULL UNIQUE,
|
||||
PRIMARY KEY("ID" AUTOINCREMENT)
|
||||
);
|
||||
DROP TABLE IF EXISTS "Verlag";
|
||||
CREATE TABLE "Verlag" (
|
||||
CREATE TABLE IF NOT EXISTS "Genre" (
|
||||
"ID" INTEGER,
|
||||
"Verlag" TEXT NOT NULL,
|
||||
"Genre" TEXT NOT NULL UNIQUE,
|
||||
PRIMARY KEY("ID" AUTOINCREMENT)
|
||||
);
|
||||
DROP TABLE IF EXISTS "Veroeffentlichung";
|
||||
CREATE TABLE "Veroeffentlichung" (
|
||||
CREATE TABLE IF NOT EXISTS "Herausgeber" (
|
||||
"ID" INTEGER,
|
||||
"Text" INTEGER NOT NULL,
|
||||
"Werk" INTEGER NOT NULL,
|
||||
"AltTitel" TEXT,
|
||||
"AltUntertitel" TEXT,
|
||||
"Pseudonym" INTEGER NOT NULL,
|
||||
PRIMARY KEY("ID" AUTOINCREMENT),
|
||||
FOREIGN KEY("Pseudonym") REFERENCES "Pseudonym"("ID"),
|
||||
FOREIGN KEY("Text") REFERENCES "Text"("ID"),
|
||||
FOREIGN KEY("Werk") REFERENCES "Werk"("ID")
|
||||
"Name" TEXT NOT NULL UNIQUE,
|
||||
PRIMARY KEY("ID" AUTOINCREMENT)
|
||||
);
|
||||
DROP TABLE IF EXISTS "Werk";
|
||||
CREATE TABLE "Werk" (
|
||||
CREATE TABLE IF NOT EXISTS "Pseudonym" (
|
||||
"ID" INTEGER,
|
||||
"Pseudonym" TEXT NOT NULL UNIQUE,
|
||||
PRIMARY KEY("ID" AUTOINCREMENT)
|
||||
);
|
||||
CREATE TABLE IF NOT EXISTS "Sprache" (
|
||||
"ID" INTEGER,
|
||||
"Sprache" TEXT NOT NULL UNIQUE,
|
||||
PRIMARY KEY("ID" AUTOINCREMENT)
|
||||
);
|
||||
CREATE TABLE IF NOT EXISTS "Textform" (
|
||||
"ID" INTEGER,
|
||||
"Textform" TEXT NOT NULL UNIQUE,
|
||||
PRIMARY KEY("ID" AUTOINCREMENT)
|
||||
);
|
||||
CREATE TABLE IF NOT EXISTS "Verlag" (
|
||||
"ID" INTEGER,
|
||||
"Verlag" TEXT NOT NULL UNIQUE,
|
||||
PRIMARY KEY("ID" AUTOINCREMENT)
|
||||
);
|
||||
CREATE TABLE IF NOT EXISTS "Werksform" (
|
||||
"ID" INTEGER,
|
||||
"Werksform" TEXT NOT NULL UNIQUE,
|
||||
PRIMARY KEY("ID" AUTOINCREMENT)
|
||||
);
|
||||
CREATE TABLE IF NOT EXISTS "Text" (
|
||||
"ID" INTEGER,
|
||||
"Titel" TEXT NOT NULL,
|
||||
"Untertitel" TEXT,
|
||||
"Werksform" INTEGER,
|
||||
"Reihe" INTEGER,
|
||||
"Textform" INTEGER NOT NULL,
|
||||
"Sprache" INTEGER NOT NULL,
|
||||
PRIMARY KEY("ID" AUTOINCREMENT),
|
||||
FOREIGN KEY("Reihe") REFERENCES "Reihe"("ID"),
|
||||
FOREIGN KEY("Sprache") REFERENCES "Sprache"("ID"),
|
||||
FOREIGN KEY("Textform") REFERENCES "Textform"("ID")
|
||||
);
|
||||
CREATE TABLE IF NOT EXISTS "Werk" (
|
||||
"ID" INTEGER,
|
||||
"Titel" TEXT NOT NULL,
|
||||
"Untertitel" TEXT,
|
||||
"Werksform" INTEGER NOT NULL,
|
||||
"Verlag" INTEGER,
|
||||
"Reihe" INTEGER,
|
||||
"Reihennummer" TEXT,
|
||||
@ -113,26 +94,48 @@ CREATE TABLE "Werk" (
|
||||
FOREIGN KEY("Verlag") REFERENCES "Verlag"("ID"),
|
||||
FOREIGN KEY("Werksform") REFERENCES "Werksform"("ID")
|
||||
);
|
||||
DROP TABLE IF EXISTS "Werk_Genre";
|
||||
CREATE TABLE "Werk_Genre" (
|
||||
CREATE TABLE IF NOT EXISTS "Werk_Genre" (
|
||||
"Werk" INTEGER,
|
||||
"Genre" INTEGER,
|
||||
PRIMARY KEY("Werk","Genre"),
|
||||
FOREIGN KEY("Genre") REFERENCES "Genre"("ID"),
|
||||
FOREIGN KEY("Werk") REFERENCES "Werk"("ID")
|
||||
);
|
||||
DROP TABLE IF EXISTS "Werk_Herausgeber";
|
||||
CREATE TABLE "Werk_Herausgeber" (
|
||||
CREATE TABLE IF NOT EXISTS "Werk_Herausgeber" (
|
||||
"Herausgeber" INTEGER,
|
||||
"Werk" INTEGER,
|
||||
PRIMARY KEY("Herausgeber","Werk"),
|
||||
FOREIGN KEY("Herausgeber") REFERENCES "Herausgeber"("ID"),
|
||||
FOREIGN KEY("Werk") REFERENCES "Werk"("ID")
|
||||
);
|
||||
DROP TABLE IF EXISTS "Werksform";
|
||||
CREATE TABLE "Werksform" (
|
||||
CREATE TABLE IF NOT EXISTS "Veroeffentlichung" (
|
||||
"ID" INTEGER,
|
||||
"Werksform" TEXT NOT NULL,
|
||||
PRIMARY KEY("ID" AUTOINCREMENT)
|
||||
"Text" INTEGER NOT NULL,
|
||||
"Werk" INTEGER NOT NULL,
|
||||
"AltTitel" TEXT,
|
||||
"AltUntertitel" TEXT,
|
||||
"Pseudonym" INTEGER NOT NULL,
|
||||
PRIMARY KEY("ID" AUTOINCREMENT),
|
||||
FOREIGN KEY("Pseudonym") REFERENCES "Pseudonym"("ID"),
|
||||
FOREIGN KEY("Text") REFERENCES "Text"("ID"),
|
||||
FOREIGN KEY("Werk") REFERENCES "Werk"("ID")
|
||||
);
|
||||
CREATE TABLE IF NOT EXISTS "Ausgabe" (
|
||||
"ID" INTEGER,
|
||||
"Werk" INTEGER NOT NULL,
|
||||
"Werksform" INTEGER NOT NULL,
|
||||
"Verlag" INTEGER,
|
||||
"Erscheinungsdatum" TEXT,
|
||||
"ISBN_13" TEXT,
|
||||
"ISBN_10" TEXT,
|
||||
"ISSN" TEXT,
|
||||
"Preis" TEXT,
|
||||
"Titelbild" INTEGER,
|
||||
"Klappentext" TEXT,
|
||||
"Anmerkungen" TEXT,
|
||||
PRIMARY KEY("ID"),
|
||||
FOREIGN KEY("Titelbild") REFERENCES "Titelbild"("ID"),
|
||||
FOREIGN KEY("Verlag") REFERENCES "Verlag"("ID"),
|
||||
FOREIGN KEY("Werk") REFERENCES "Werk"("ID"),
|
||||
FOREIGN KEY("Werksform") REFERENCES "Werksform"("ID")
|
||||
);
|
||||
COMMIT;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user