WIP Quellen/Admin
This commit is contained in:
@@ -16,3 +16,4 @@ und für die öffentliche Rechercheplattform.
|
|||||||
- Python 3.14 (funktioniert wahrscheinlich auch mit anderen Versionen)
|
- Python 3.14 (funktioniert wahrscheinlich auch mit anderen Versionen)
|
||||||
- Django 6.0
|
- Django 6.0
|
||||||
- django-taggit
|
- django-taggit
|
||||||
|
- django-taggit-helpers (uralt, funktioniert aber)
|
||||||
|
|||||||
22
docs/README.md
Normal file
22
docs/README.md
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
# Installation zum Testen & Entwickeln
|
||||||
|
|
||||||
|
Wir entwickeln auf Python 3.14. Python 3.12+ funktioniert, ältere haben zumindest Probleme mit Frescobaldi, was hiermit nichts zu tun hat…
|
||||||
|
|
||||||
|
- `git clone ssh://git@git.zahlenlabyrinth.de:9922/Notenbund/liederquelle.git`
|
||||||
|
- `cd liederquelle`
|
||||||
|
- Python virtual environment (Venv) anlegen: `python3.14 -m venv .venv`
|
||||||
|
- Venv aktivieren: `. .venv/bin/activate`
|
||||||
|
- Abhängigkeiten installieren: `pip install -Ur requirements.txt`
|
||||||
|
- `cd liederquelle`
|
||||||
|
- `.env` anlegen:
|
||||||
|
|
||||||
|
$ python manage.py shell
|
||||||
|
>> from django.core.management.utils import get_random_secret_key
|
||||||
|
>> with open('.env', 'w') as dotenv:
|
||||||
|
dotenv.write('SECRET_KEY=%s' % get_random_secret_key())
|
||||||
|
>> ^D
|
||||||
|
|
||||||
|
- Datenbank (SQLite) anlegen: `python3 manage.py makemigrations quellen; python3 manage.py migrate`
|
||||||
|
- Admin anlegen: `python3 manage.py createsuperuser`
|
||||||
|
- Server starten: `python3 manage.py runserver`
|
||||||
|
- Öffne [http://localhost:8080/admin] im Browser
|
||||||
@@ -5,6 +5,7 @@ see https://docs.djangoproject.com/en/6.0/ref/settings/
|
|||||||
"""
|
"""
|
||||||
import os
|
import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from django.core.exceptions import ImproperlyConfigured
|
||||||
|
|
||||||
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
||||||
BASE_DIR = Path(__file__).resolve().parent.parent
|
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||||
@@ -36,6 +37,7 @@ ALLOWED_HOSTS = []
|
|||||||
INSTALLED_APPS = [
|
INSTALLED_APPS = [
|
||||||
'quellen.apps.QuellenConfig',
|
'quellen.apps.QuellenConfig',
|
||||||
'taggit',
|
'taggit',
|
||||||
|
'taggit_helpers',
|
||||||
'django.contrib.admin',
|
'django.contrib.admin',
|
||||||
'django.contrib.auth',
|
'django.contrib.auth',
|
||||||
'django.contrib.contenttypes',
|
'django.contrib.contenttypes',
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ def main():
|
|||||||
if not os.path.isfile(env):
|
if not os.path.isfile(env):
|
||||||
print("Configuration environment file (.env) not found!")
|
print("Configuration environment file (.env) not found!")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
dotenv.load_dotenv(env)
|
dotenv.read_dotenv(env)
|
||||||
|
|
||||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'liederquelle.settings')
|
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'liederquelle.settings')
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -1,31 +1,62 @@
|
|||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from .models import Person, Identity, AuthorID, Contact, Medium
|
from .models import Person, Identity, AuthorID, AuthorURL, Contact, Medium
|
||||||
from taggit_helpers.admin import TaggitListFilter, TaggitTabularInline
|
from taggit_helpers.admin import TaggitListFilter, TaggitTabularInline
|
||||||
|
from django.contrib.contenttypes.admin import GenericTabularInline, GenericStackedInline
|
||||||
|
|
||||||
# TODO: Links zu Suchseiten mit Vorbelegungen
|
# TODO: Links zu Suchseiten mit Vorbelegungen
|
||||||
|
|
||||||
|
|
||||||
class IdentityTabularInline(admin.TabularInline):
|
class IdentityInline(admin.TabularInline):
|
||||||
model = Identity
|
model = Identity
|
||||||
#ordering_field = ['slideshow', 'weight']
|
ordering_field = ['alias',]
|
||||||
ordering_field_hide_input = False
|
min_num = 1
|
||||||
#fields = ['weight', 'display_title', 'target', 'image', 'overlay_image']
|
extra = 1
|
||||||
# exclude = ['display_content', 'overlay_tilt', 'overlay_class', 'activated']
|
show_change_link = True
|
||||||
|
#fields = ['author_id', 'alias', 'organization', 'tags']
|
||||||
|
|
||||||
|
|
||||||
|
class AuthorIDInline(admin.TabularInline):
|
||||||
|
model = AuthorID
|
||||||
|
ordering_field = ['key',]
|
||||||
|
extra = 1
|
||||||
|
|
||||||
|
|
||||||
|
class AuthorURLInline(admin.TabularInline):
|
||||||
|
model = AuthorURL
|
||||||
|
ordering_field = ['name',]
|
||||||
|
extra = 1
|
||||||
|
|
||||||
|
|
||||||
|
class ContactInline(GenericStackedInline):
|
||||||
|
model = Contact
|
||||||
|
ordering_field = ['last_try',]
|
||||||
|
min_num = 1
|
||||||
|
extra = 0
|
||||||
|
show_change_link = True
|
||||||
|
|
||||||
|
|
||||||
|
class MediumInline(admin.TabularInline):
|
||||||
|
model = Medium
|
||||||
|
ordering_field = ['key',]
|
||||||
|
#min_num = 1
|
||||||
|
#show_change_link = True
|
||||||
|
|
||||||
|
|
||||||
@admin.register(Person)
|
@admin.register(Person)
|
||||||
class PersonAdmin(admin.ModelAdmin):
|
class PersonAdmin(admin.ModelAdmin):
|
||||||
list_display = ['name', 'full_name', 'birth_year']
|
list_display = Person.list_display
|
||||||
search_fields = ('name', 'full_name', 'name_native', 'birth_name')
|
search_fields = ('name', 'full_name', 'name_native', 'birth_name')
|
||||||
inlines = [
|
inlines = [
|
||||||
IdentityTabularInline
|
IdentityInline,
|
||||||
|
AuthorIDInline,
|
||||||
|
AuthorURLInline,
|
||||||
|
ContactInline
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@admin.register(Identity)
|
@admin.register(Identity)
|
||||||
class IdentityAdmin(admin.ModelAdmin):
|
class IdentityAdmin(admin.ModelAdmin):
|
||||||
list_display = ['person', 'author_id', 'alias', 'organization']
|
list_display = Identity.list_display
|
||||||
search_fields = ('alias', 'organization')
|
search_fields = ('alias', 'organization')
|
||||||
list_filter = ['person', 'organization', TaggitListFilter]
|
list_filter = ['person', 'organization', TaggitListFilter]
|
||||||
exclude = ('tags',)
|
exclude = ('tags',)
|
||||||
@@ -36,19 +67,28 @@ class IdentityAdmin(admin.ModelAdmin):
|
|||||||
|
|
||||||
@admin.register(AuthorID)
|
@admin.register(AuthorID)
|
||||||
class AuthorIDAdmin(admin.ModelAdmin):
|
class AuthorIDAdmin(admin.ModelAdmin):
|
||||||
list_display = ['person','key','value']
|
list_display = AuthorID.list_display
|
||||||
search_fields = ('value',)
|
search_fields = ('value',)
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(AuthorURL)
|
||||||
|
class AuthorURLAdmin(admin.ModelAdmin):
|
||||||
|
list_display = AuthorURL.list_display
|
||||||
|
search_fields = ('url',)
|
||||||
|
|
||||||
|
|
||||||
@admin.register(Contact)
|
@admin.register(Contact)
|
||||||
class ContactAdmin(admin.ModelAdmin):
|
class ContactAdmin(admin.ModelAdmin):
|
||||||
date_hierarchy = 'last_try'
|
date_hierarchy = 'last_try'
|
||||||
list_display = ['reference', 'name',]
|
list_display = Contact.list_display
|
||||||
search_fields = ('name', 'address', 'remarks')
|
search_fields = ('name', 'address', 'remarks')
|
||||||
#prepopulated_fields = {'user': ('',)}
|
#prepopulated_fields = {'user': ('',)}
|
||||||
|
inlines = [
|
||||||
|
MediumInline,
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
@admin.register(Medium)
|
@admin.register(Medium)
|
||||||
class MediumAdmin(admin.ModelAdmin):
|
class MediumAdmin(admin.ModelAdmin):
|
||||||
list_display = ['contact','key','value']
|
list_display = Medium.list_display
|
||||||
search_fields = ('value',)
|
search_fields = ('value',)
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
# Generated by Django 6.0.1 on 2026-01-24 23:09
|
# Generated by Django 6.0.1 on 2026-01-25 20:38
|
||||||
|
|
||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
|
import quellen.models
|
||||||
import taggit.managers
|
import taggit.managers
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
@@ -23,33 +24,50 @@ class Migration(migrations.Migration):
|
|||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
('name', models.CharField(help_text='Klarname, wie er beim Lied angezeigt werden soll. Normalerweise "Vorname Nachname".', max_length=127, verbose_name='Name')),
|
('name', models.CharField(help_text='Klarname, wie er beim Lied angezeigt werden soll. Normalerweise "Vorname Nachname".', max_length=127, verbose_name='Name')),
|
||||||
('full_name', models.CharField(blank=True, help_text='Name mit zusätzlichen Vornamen, Titeln usw.', max_length=255, verbose_name='Vollständiger Name')),
|
('full_name', models.CharField(blank=True, help_text='Name mit zusätzlichen Vornamen, Titeln usw.', max_length=255, verbose_name='Vollständiger Name')),
|
||||||
|
('name_native', models.CharField(blank=True, help_text='Name in nichtlateinischer Schrift', max_length=255, verbose_name='Name in Originalschreibweise')),
|
||||||
('birth_name', models.CharField(blank=True, help_text='Name vor einer Namensänderung, z.B. durch Ehe.', max_length=127, verbose_name='Geburtsname')),
|
('birth_name', models.CharField(blank=True, help_text='Name vor einer Namensänderung, z.B. durch Ehe.', max_length=127, verbose_name='Geburtsname')),
|
||||||
('details_secret', models.BooleanField(default=False, help_text='Beim Lied soll nur der Alias angezeigt werden, kein Klarname und keine Lebensdaten.', verbose_name='Details geheim')),
|
('details_secret', models.BooleanField(default=False, help_text='Beim Lied soll nur der Alias angezeigt werden, kein Klarname und keine Lebensdaten.', verbose_name='Details geheim')),
|
||||||
('birth_year', models.CharField(blank=True, help_text='Auch ungefähre Angaben sind erlaubt.', max_length=15, verbose_name='Geburtsjahr')),
|
('birth_year', models.CharField(blank=True, help_text='Auch ungefähre Angaben sind erlaubt.', max_length=15, verbose_name='Geburtsjahr')),
|
||||||
('death_year', models.CharField(blank=True, help_text='Auch ungefähre Angaben sind erlaubt.', max_length=15, verbose_name='Todesjahr')),
|
('death_year', models.CharField(blank=True, help_text='Auch ungefähre Angaben sind erlaubt.', max_length=15, verbose_name='Todesjahr')),
|
||||||
('remarks', models.TextField(blank=True, verbose_name='Anmerkungen')),
|
('remarks', models.TextField(blank=True, verbose_name='Anmerkungen')),
|
||||||
],
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Person',
|
||||||
|
'verbose_name_plural': 'Personen',
|
||||||
|
'ordering': ['name', 'birth_year'],
|
||||||
|
},
|
||||||
),
|
),
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='Contact',
|
name='Contact',
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('object_id', models.PositiveBigIntegerField(default=1)),
|
||||||
|
('name', models.CharField(blank=True, help_text='Name der Kontaktperson, falls nicht mit der Person identisch', max_length=127, verbose_name='Kontaktperson')),
|
||||||
('address', models.TextField(blank=True, help_text='Postadresse', verbose_name='Adresse')),
|
('address', models.TextField(blank=True, help_text='Postadresse', verbose_name='Adresse')),
|
||||||
('last_try', models.DateField(blank=True, null=True, verbose_name='letzter Kontaktversuch')),
|
('last_try', models.DateField(blank=True, null=True, verbose_name='letzter Kontaktversuch')),
|
||||||
('success', models.BooleanField(blank=True, default=None, help_text='War der Kontaktversuch erfolgreich?', null=True, verbose_name='Kontakt erfolgreich?')),
|
('success', models.BooleanField(blank=True, default=None, help_text='War der Kontaktversuch erfolgreich?', null=True, verbose_name='Kontakt erfolgreich?')),
|
||||||
('remarks', models.TextField(blank=True, verbose_name='Anmerkungen')),
|
('remarks', models.TextField(blank=True, verbose_name='Anmerkungen')),
|
||||||
('reference', models.ForeignKey(help_text='Person oder Verlag', on_delete=django.db.models.deletion.CASCADE, to='contenttypes.contenttype')),
|
('content_type', models.ForeignKey(default=quellen.models.Person, help_text='Person oder Verlag', on_delete=django.db.models.deletion.CASCADE, to='contenttypes.contenttype')),
|
||||||
('user', models.ForeignKey(blank=True, help_text='Kontakt durch Projektmitarbeiter*in', null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL, verbose_name='User')),
|
('user', models.ForeignKey(blank=True, help_text='Kontakt durch bzw. persönlich bekannt mit Projektmitarbeiter*in', null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL, verbose_name='User')),
|
||||||
],
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Kontakt',
|
||||||
|
'verbose_name_plural': 'Kontakte',
|
||||||
|
},
|
||||||
),
|
),
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='Medium',
|
name='Medium',
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
('key', models.CharField(choices=[('Email', 'E-Mail'), ('Phone', 'Telefon'), ('Signal', 'Signal-ID')], default='Email', max_length=15, verbose_name='Art')),
|
('key', models.CharField(choices=[('Email', 'E-Mail'), ('Phone', 'Telefon'), ('Web', 'Homepage'), ('Signal', 'Signal-ID'), ('Fedi', 'Fediverse-Handle'), ('Matrix', 'Matrix-ID'), ('XMPP', 'XMPP-ID')], default='Email', max_length=15, verbose_name='Art')),
|
||||||
('value', models.CharField(help_text='Adresse bzw. Handle', max_length=127, verbose_name='Wert')),
|
('value', models.CharField(help_text='Adresse bzw. Handle', max_length=127, verbose_name='Wert')),
|
||||||
('contact', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='quellen.contact')),
|
('contact', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='quellen.contact')),
|
||||||
],
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Kontaktmedium',
|
||||||
|
'verbose_name_plural': 'Kontaktmedien',
|
||||||
|
'ordering': ['contact', 'key'],
|
||||||
|
},
|
||||||
),
|
),
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='Identity',
|
name='Identity',
|
||||||
@@ -57,9 +75,29 @@ class Migration(migrations.Migration):
|
|||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
('author_id', models.CharField(help_text='Wie in der LilyPond-Datei und der `authors.yml` verwendet.', max_length=127, verbose_name='Autoren-ID')),
|
('author_id', models.CharField(help_text='Wie in der LilyPond-Datei und der `authors.yml` verwendet.', max_length=127, verbose_name='Autoren-ID')),
|
||||||
('alias', models.CharField(blank=True, help_text='Fahrtenname, Künstlername o.ä.; Spitznamen nur, wenn sie mehr sind als eine Vornamensvariante.', max_length=127, verbose_name='Alias')),
|
('alias', models.CharField(blank=True, help_text='Fahrtenname, Künstlername o.ä.; Spitznamen nur, wenn sie mehr sind als eine Vornamensvariante.', max_length=127, verbose_name='Alias')),
|
||||||
('tags', taggit.managers.TaggableManager(help_text='A comma-separated list of tags.', through='taggit.TaggedItem', to='taggit.Tag', verbose_name='Tags')),
|
('organization', models.CharField(blank=True, help_text='Bund (mit Stamm/Orden), Band o.ä. wie am Lied anzuzeigen – bitte zusätzlich taggen!', max_length=127, verbose_name='Organisation')),
|
||||||
|
('tags', taggit.managers.TaggableManager(blank=True, help_text='Kommaseparierte Stichwörter zu dieser Identität, z.B. "Bund:DPB,Band:Schlagsaite"', through='taggit.TaggedItem', to='taggit.Tag', verbose_name='Stichwörter')),
|
||||||
('person', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='quellen.person')),
|
('person', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='quellen.person')),
|
||||||
],
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Identität',
|
||||||
|
'verbose_name_plural': 'Identitäten',
|
||||||
|
'ordering': ['author_id'],
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='AuthorURL',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('name', models.CharField(default='Homepage', help_text='z.B. Wikipedia-Eintrag', max_length=15, verbose_name='Art')),
|
||||||
|
('url', models.URLField(help_text='Web-Adresse', verbose_name='URL')),
|
||||||
|
('person', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='quellen.person')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Autor-Website',
|
||||||
|
'verbose_name_plural': 'Autor-Webseiten',
|
||||||
|
'ordering': ['person', 'name'],
|
||||||
|
},
|
||||||
),
|
),
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='AuthorID',
|
name='AuthorID',
|
||||||
@@ -69,5 +107,14 @@ class Migration(migrations.Migration):
|
|||||||
('value', models.CharField(help_text='ID in der Schreibweise der jeweiligen Datenbank', max_length=127, verbose_name='Wert')),
|
('value', models.CharField(help_text='ID in der Schreibweise der jeweiligen Datenbank', max_length=127, verbose_name='Wert')),
|
||||||
('person', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='quellen.person')),
|
('person', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='quellen.person')),
|
||||||
],
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Autor-ID',
|
||||||
|
'verbose_name_plural': 'Autor-IDs',
|
||||||
|
'ordering': ['person', 'key', 'value'],
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.AddIndex(
|
||||||
|
model_name='contact',
|
||||||
|
index=models.Index(fields=['content_type', 'object_id'], name='quellen_con_content_7ef419_idx'),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
from django.db import models
|
from django.db import models
|
||||||
from taggit.managers import TaggableManager
|
from taggit.managers import TaggableManager
|
||||||
from django.contrib.contenttypes.fields import GenericForeignKey
|
from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
|
|
||||||
@@ -46,14 +46,14 @@ class Person(models.Model):
|
|||||||
blank=True,
|
blank=True,
|
||||||
#help_text='',
|
#help_text='',
|
||||||
)
|
)
|
||||||
# TODO: URLs wie Tags?
|
contacts = GenericRelation('Contact')
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = 'Person'
|
verbose_name = 'Person'
|
||||||
verbose_name_plural = 'Personen'
|
verbose_name_plural = 'Personen'
|
||||||
ordering = ['name','birth_year']
|
ordering = ['name','birth_year']
|
||||||
|
|
||||||
list_display = ['name']
|
list_display = ['name', 'full_name', 'birth_year']
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
@@ -92,7 +92,7 @@ class Identity(models.Model):
|
|||||||
verbose_name_plural = 'Identitäten'
|
verbose_name_plural = 'Identitäten'
|
||||||
ordering = ['author_id']
|
ordering = ['author_id']
|
||||||
|
|
||||||
list_display = ['author_id', 'alias']
|
list_display = ['person', 'author_id', 'alias', 'organization']
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "{} ({})".format(self.author_id, self.alias)
|
return "{} ({})".format(self.author_id, self.alias)
|
||||||
@@ -103,7 +103,6 @@ class AuthorID(models.Model):
|
|||||||
blank=False,
|
blank=False,
|
||||||
on_delete=models.CASCADE,
|
on_delete=models.CASCADE,
|
||||||
)
|
)
|
||||||
# TODO: Medien in eigene Tabelle ausgliedern
|
|
||||||
class IDs(models.TextChoices):
|
class IDs(models.TextChoices):
|
||||||
DISCOGS = "DISCOGS", 'Discogs'
|
DISCOGS = "DISCOGS", 'Discogs'
|
||||||
GND = "GND", 'DNB GND'
|
GND = "GND", 'DNB GND'
|
||||||
@@ -134,12 +133,44 @@ class AuthorID(models.Model):
|
|||||||
list_display = ['person', 'key', 'value']
|
list_display = ['person', 'key', 'value']
|
||||||
|
|
||||||
|
|
||||||
class Contact(models.Model):
|
class AuthorURL(models.Model):
|
||||||
reference = models.ForeignKey(ContentType,
|
person = models.ForeignKey(Person,
|
||||||
on_delete = models.CASCADE,
|
blank=False,
|
||||||
help_text = 'Person oder Verlag'
|
on_delete=models.CASCADE,
|
||||||
# TODO: Das stimmt so nicht, ID des Objekts fehlt
|
|
||||||
)
|
)
|
||||||
|
name = models.CharField(
|
||||||
|
verbose_name='Art',
|
||||||
|
max_length=15,
|
||||||
|
blank=False,
|
||||||
|
default='Homepage',
|
||||||
|
help_text='z.B. Wikipedia-Eintrag'
|
||||||
|
)
|
||||||
|
url = models.URLField(
|
||||||
|
verbose_name='URL',
|
||||||
|
blank=False,
|
||||||
|
help_text='Web-Adresse',
|
||||||
|
)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = 'Autor-Website'
|
||||||
|
verbose_name_plural = 'Autor-Webseiten'
|
||||||
|
ordering = ['person', 'name',]
|
||||||
|
|
||||||
|
list_display = ['person', 'name', 'url']
|
||||||
|
|
||||||
|
|
||||||
|
class Contact(models.Model):
|
||||||
|
content_type = models.ForeignKey(ContentType,
|
||||||
|
on_delete = models.CASCADE,
|
||||||
|
help_text = 'Person oder Verlag',
|
||||||
|
default = Person,
|
||||||
|
blank=False,null=False,
|
||||||
|
)
|
||||||
|
object_id = models.PositiveBigIntegerField(
|
||||||
|
default=1,
|
||||||
|
blank=False,null=False,
|
||||||
|
)
|
||||||
|
content_object = GenericForeignKey("content_type", "object_id")
|
||||||
name = models.CharField(
|
name = models.CharField(
|
||||||
verbose_name = 'Kontaktperson',
|
verbose_name = 'Kontaktperson',
|
||||||
blank=True,
|
blank=True,
|
||||||
@@ -175,9 +206,12 @@ class Contact(models.Model):
|
|||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = 'Kontakt'
|
verbose_name = 'Kontakt'
|
||||||
verbose_name_plural = 'Kontakte'
|
verbose_name_plural = 'Kontakte'
|
||||||
ordering = ['reference', 'last_try']
|
#ordering = ['content_object', 'last_try']
|
||||||
|
indexes = [
|
||||||
|
models.Index(fields=["content_type", "object_id"]),
|
||||||
|
]
|
||||||
|
|
||||||
list_display = ['reference', 'last_try', 'user', 'success']
|
list_display = ['content_object', 'name', 'last_try', 'user', 'success']
|
||||||
|
|
||||||
|
|
||||||
class Medium(models.Model):
|
class Medium(models.Model):
|
||||||
@@ -185,7 +219,6 @@ class Medium(models.Model):
|
|||||||
blank=False,
|
blank=False,
|
||||||
on_delete=models.CASCADE,
|
on_delete=models.CASCADE,
|
||||||
)
|
)
|
||||||
# TODO: Medien in eigene Tabelle ausgliedern
|
|
||||||
class IDs(models.TextChoices):
|
class IDs(models.TextChoices):
|
||||||
Email = "Email", 'E-Mail'
|
Email = "Email", 'E-Mail'
|
||||||
Phone = "Phone", 'Telefon'
|
Phone = "Phone", 'Telefon'
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
django>6,<7
|
django>6,<7
|
||||||
Pillow
|
|
||||||
|
|
||||||
django-dotenv
|
django-dotenv
|
||||||
django-taggit
|
django-taggit
|
||||||
django-taggit-helpers
|
django-taggit-helpers
|
||||||
|
|||||||
Reference in New Issue
Block a user