Initial commit

This commit is contained in:
Stephan Porada
2019-02-28 14:09:53 +01:00
commit 96e84d083d
97 changed files with 66293 additions and 0 deletions

0
app/speeches/__init__.py Executable file
View File

3
app/speeches/admin.py Executable file
View File

@ -0,0 +1,3 @@
from django.contrib import admin
# Register your models here.

22
app/speeches/apps.py Executable file
View File

@ -0,0 +1,22 @@
from django.apps import AppConfig
from watson import search as watson
class SpeechesConfig(AppConfig):
name = 'speeches'
def ready(self):
Protocol = self.get_model("Protocol")
watson.register(Protocol, fields=["protocol_id",
"protocol_period",
"session_date_str"])
Speech = self.get_model("Speech")
watson.register(Speech,
fields=["speech_id",
"foreign_protocol__protocol_id",
"foreign_protocol__session_date_str",
"foreign_speaker__id",
"foreign_speaker__first_name",
"foreign_speaker__last_name"],
exclude=["speech_content"])

21
app/speeches/forms.py Executable file
View File

@ -0,0 +1,21 @@
from django import forms
class SearchForm(forms.Form):
"""
Configures the html input form for the protocol search.
"""
query = forms.CharField(label="Suche Protokoll", max_length="200")
query.widget.attrs.update({"class": "autocomplete materialize-textarea",
"id": "icon_prefix2"})
class SearchFormSpeech(forms.Form):
"""
Configures the html input form for the speech search.
"""
query = forms.CharField(label="Suche Rede", max_length="200")
query.widget.attrs.update({"class": "autocomplete materialize-textarea",
"id": "icon_prefix2"})

View File

@ -0,0 +1,120 @@
from django.core.management.base import BaseCommand
from speeches.models import Protocol, Speech
from speakers.models import Speaker
from lxml import etree
import os
import fnmatch
import datetime
from tqdm import tqdm
class Command(BaseCommand):
help = ("Adds protocols to the database using the django models"
" syntax. Protocols will be added from the xml protocol files."
" Input is a path pointing to all/multiple protocols in one"
" directory with one level of subdirectories. First imports"
" toc, attachments and metadata with model Protocol. Speeches will be put into realtion with the model Speech."
" to the protocols later on.")
def add_arguments(self, parser):
parser.add_argument("input_path",
type=str)
def handle(self, *args, **options):
path = options["input_path"]
list_of_files = []
for path, subdirs, files in os.walk(path):
for name in files:
if fnmatch.fnmatch(name, "*.xml"):
list_of_files.append(os.path.join(path, name))
for file_path in tqdm(sorted(list_of_files), desc="Importing protocol data"):
# self.stdout.write("Reading data from file: " + file_path)
tree = etree.parse(file_path)
protocol = Protocol()
protocol.protocol_id = os.path.basename(file_path)[:-4]
# self.stdout.write("\tProtocol ID is: " + protocol.protocol_id)
# self.stdout.write("\tReading toc and attachment.")
session_nr = tree.xpath("//sitzungsnr")[0]
protocol.session_nr = session_nr
protocol_period = tree.xpath("@wahlperiode")[0]
protocol.protocol_period = protocol_period
session_date = tree.xpath("//@date")[0]
protocol.session_date_str = session_date
session_date = datetime.datetime.strptime(session_date, "%d.%m.%Y")
session_date = datetime.datetime.strftime(session_date, "%Y-%m-%d")
protocol.session_date = session_date
correct_start_time = None
start_of_session = tree.xpath("//@sitzung-start-uhrzeit")[0]
try:
start_of_session = datetime.datetime.strptime(start_of_session,
"%H:%M")
correct_start_time = True
except ValueError as e:
correct_start_time = False
if(correct_start_time is True):
protocol.start_of_session = start_of_session
else:
protocol.start_of_session = None
end_of_session = tree.xpath("//@sitzung-ende-uhrzeit")[0]
correct_end_time = None
try:
end_of_session = datetime.datetime.strptime(end_of_session,
"%H:%M")
correct_end_time = True
except ValueError as e:
correct_end_time = False
if(correct_end_time is True):
protocol.end_of_session = end_of_session
else:
protocol.end_of_session = None
session_nr = tree.xpath("//sitzungsnr")[0]
protocol.session_nr = session_nr.text
election_period = tree.xpath("//wahlperiode")[0]
protocol.election_period = election_period.text
toc = tree.xpath("//inhaltsverzeichnis")[0]
protocol.toc = toc.text
attachment = tree.xpath("//anlagen")[0]
protocol.attachment = attachment.text
protocol.save()
speeches = tree.xpath("//sitzungsbeginn | //rede")
for previous_e, current_e, next_e in zip([None]+speeches[:-1], speeches, speeches[1:]+[None]):
# self.stdout.write("\tReading speech from " + protocol.protocol_id)
speech = Speech()
speech.foreign_protocol = protocol
if(previous_e is not None):
previous_speech_id = previous_e.xpath("@id")[0]
speech.previous_speech_id = previous_speech_id
speech_id = current_e.xpath("@id")[0]
speech.speech_id = speech_id
if(next_e is not None):
next_speech_id = next_e.xpath("@id")[0]
speech.next_speech_id = next_speech_id
# self.stdout.write("\tSpeech ID is:" + str(speech.speech_id))
# self.stdout.write("\tPrevious Speech ID is:" + str(speech.previous_speech_id))
# self.stdout.write("\tNext Speech ID is:" + str(speech.next_speech_id))
speaker_type = current_e.xpath("//@typ")[0]
speech.speaker_type = speaker_type
speaker_id = current_e.xpath(".//redner/@id")[0]
# self.stdout.write("\tCurrent speaker ID is:" + str(speaker_id))
if(speaker_id != "None"):
speech.foreign_speaker = Speaker.objects.filter(pk=speaker_id)[0]
# self.stdout.write("\tSpeaker ID (Foreign key) is:" + str(speech.foreign_speaker))
speech_content = current_e.xpath(".//p")
speech_content = [str(etree.tostring(p)) for p in speech_content]
speech_content = "".join(speech_content)
speech.speech_content = speech_content
original_string = current_e.xpath(".//redner/name")[0]
speech.original_string = original_string.tail
# self.stdout.write("\t-------------------------------------------")
speech.save()

View File

44
app/speeches/models.py Executable file
View File

@ -0,0 +1,44 @@
from django.db import models
class Protocol(models.Model):
"""
This models contains the data about one protocol. Data will be imported from
the XML protocols via the custom django-admin command import_protocols.py.
Does not contain speeches. Speeches will be related to this model though.
Only contains table of contents, metadata etc.
"""
protocol_id = models.IntegerField(primary_key=True, verbose_name="Protokoll ID")
protocol_period = models.IntegerField(verbose_name="Wahlperiode", null=True, blank=True)
session_nr = models.IntegerField(verbose_name="Sitzungsnummer", null=True, blank=True)
session_date = models.DateField(verbose_name="Datum")
session_date_str = models.CharField(verbose_name="Datums String", max_length=12, blank=True, default=None, null=True)
start_of_session = models.TimeField(null=True, verbose_name="Startuhrzeit")
end_of_session = models.TimeField(null=True, verbose_name="Enduhrzeit")
toc = models.TextField(verbose_name="Inhaltsverzeichnis")
attachment = models.TextField(verbose_name="Anlagen")
def __str__(self):
return str(self.protocol_id) + " " + str(self.session_date)
class Speech(models.Model):
"""
This models contains the data about one speech. Data will be imported from
the XML protocols via the custom django-admin command import_speeches.py.
"""
foreign_protocol = models.ForeignKey("Protocol", on_delete=models.CASCADE,
verbose_name="Foreign Protokoll",
default=None)
speech_id = models.CharField(verbose_name="Rede ID", primary_key=True, max_length=14)
previous_speech_id = models.CharField(verbose_name="Vorherige Rede ID", max_length=14, blank=True, default=None, null=True)
next_speech_id = models.CharField(verbose_name="Nächste Rede ID", max_length=14, blank=True, default=None, null=True)
speaker_type = models.CharField(verbose_name="Rolle des MdBs", max_length=50)
foreign_speaker = models.ForeignKey("speakers.Speaker", on_delete=models.CASCADE,
null=True, blank=True, verbose_name="MdB ID", )
speech_content = models.TextField(verbose_name="Redeinhalt") # import as XML element to string
original_string = models.TextField(verbose_name="Original String")
def __str__(self):
return (str(self.foreign_protocol) + " " + str(self.speech_id) + " "
+ self.speech_content[:20])

53
app/speeches/tables.py Executable file
View File

@ -0,0 +1,53 @@
import django_tables2 as tables
from .models import Speech, Protocol
from django_tables2.utils import A # alias for Accessor
class SpeechTable(tables.Table):
"""
Configures the table showing all speeches. Inserts a column with links to
the speeches. Also defines all shown columns.
"""
link = tables.LinkColumn("Rede", text="Rede", args=[A("speech_id")],
orderable=False,
attrs={"a": {"class": "waves-effect waves-light btn light-green darken-3"}}) # Adds colum with Link to Rede
class Meta:
model = Speech
fields = ("speech_id", "foreign_protocol.protocol_id",
"foreign_protocol.session_date", "foreign_speaker.id",
"foreign_speaker.first_name", "foreign_speaker.last_name")
template_name = "speeches/table.html"
empty_text = ("Für den eingegebenen Suchbegriff gibt es leider keine Ergebnisse.")
class SpeakerSpeechTable(tables.Table):
"""
Configures the table showing all speeches of one speaker in his profile.
Inserts a column with links to the speeches. Also defines all shown columns.
"""
link = tables.LinkColumn("Rede", text="Rede", args=[A("speech_id")],
orderable=False,
attrs={"a": {"class": "waves-effect waves-light btn light-green darken-3"}}) # Adds colum with Link to Speaker
class Meta:
model = Speech
fields = ("speech_id", "foreign_protocol.protocol_id", "foreign_protocol.session_date")
template_name = "speeches/table.html"
empty_text = ("Für den eingegebenen Suchbegriff gibt es leider keine Ergebnisse.")
class ProtocolTable(tables.Table):
"""
Configures the table showing all protocols.
Inserts a column with links to the protocols. Also defines all shown columns.
"""
link = tables.LinkColumn("Protokoll", text="Protokoll", args=[A("protocol_id")],
orderable=False,
attrs={"a": {"class": "waves-effect waves-light btn light-green darken-3"}}) # Adds colum with Link to protocol
class Meta:
model = Protocol
fields = ("protocol_id", "session_date", "protocol_period")
template_name = "speeches/table.html"
empty_text = ("Für den eingegebenen Suchbegriff gibt es leider keine Ergebnisse.")

View File

@ -0,0 +1,84 @@
{% extends "blog/base.html" %}
{% load render_table from django_tables2 %}
{% block content %}
<div class="container">
<div class="row">
<div class="col s12 m4">
<div class="card">
<div class="card-content">
<span class="card-title center-align">
Protokoll:<br />{{current_protocol.protocol_id}}</span>
<p class="center-align"><i class="large material-icons blue-grey-text darken-4">insert_drive_file</i></p>
<span class="card-title">Metadaten</span>
<ul>
<li><i class="material-icons blue-grey-text darken-4" style="margin-right: 10px;">date_range</i>Wahlperiode: {{current_protocol.protocol_period}}</li>
<br />
<li><i class="material-icons blue-grey-text darken-4" style="margin-right: 10px;">date_range</i>Sitzungsnummer: {{current_protocol.session_nr}}</li>
<br />
<li><i class="material-icons blue-grey-text darken-4" style="margin-right: 10px;">date_range</i>Datum: {{current_protocol.session_date}}</li>
<br />
<li><i class="material-icons blue-grey-text darken-4" style="margin-right: 10px;">access_time</i>Startuhrzeit der Sitzung: {{current_protocol.start_of_session}} Uhr</li>
<br />
<li><i class="material-icons blue-grey-text darken-4" style="margin-right: 10px;">av_timer</i>Enduhrzeit der Sitzung: {{current_protocol.end_of_session}} Uhr</li>
<br />
</div>
</div>
<ul class="collapsible hoverable white">
<li>
<div class="collapsible-header"><i class="material-icons left blue-grey-text darken-4">account_circle</i>MdBs dieser Rede</div>
<div class="collapsible-body">
<ul>
{% for speaker in speakers %}
<li>
<a href="/mdbs/mdb/{{speaker.id}}">{{speaker.id}}: {{speaker.last_name}}, {{speaker.first_name}}</a>
</li>
<br />
{% endfor %}
</ul>
</div>
</li>
<li>
<div class="collapsible-header"><i class="material-icons left blue-grey-text darken-4">toc</i>Inhaltsverzeichnis</div>
<div class="collapsible-body"><span>{{current_protocol.toc}}</span></div>
</li>
{% if current_protocol.attachment %}
<li>
<div class="collapsible-header"><i class="material-icons left blue-grey-text darken-4">folder</i>Anlagen</div>
<div class="collapsible-body"><span>{{current_protocol.attachment}}</span></div>
</li>
{% endif %}
</ul>
</div>
<div class="col s12 m8">
<div class="card">
<div class="card-content">
<span class="card-title">Gesamtes Protokol</span>
{% for speaker, speech, related_speech in speaker_speech_html %}
{% autoescape off%}
{% if speaker.id %}
<h5><a href="/mdbs/mdb/{{speaker.id}}">{% if speaker.title %}
{{speaker.title}}
{% endif %}
{% if speaker.nobility %}
{{speaker.nobility}}
{% endif %}
{{speaker.first_name}}
{% if speaker.name_prefix %}
{{speaker.name_prefix}}
{% endif %}
{{speaker.last_name}}:</a></h5>
{% else %}
<span class="card-title">Rede von: Unbekannt<a class="tooltipped" data-position="bottom" data-tooltip="Dieses Mitglied des Bundestags konnte leider nicht automatisch erkannt werden. Grundlegende Infos zu Namen etc. können beim zugehörigen Redeeintrag unter dem Punkt Original String gefunden werden."><i
class="material-icons blue-grey-text darken-4" style="margin-right: 10px;">info_outline</i></a></span>
{% endif %}
<h6><a href="/protokolle/rede/{{related_speech.speech_id}}">Rede ID: {{related_speech.speech_id}}</a></h6>
{{speech}}
{% endautoescape %}
{% endfor%}
</div>
</div>
</div>
</div>
</div>
{% endblock content %}

View File

@ -0,0 +1,31 @@
{% extends "blog/base.html" %}
{% load render_table from django_tables2 %}
{% block content %}
<div class="container">
<div class="row">
<div class="col s12">
<div class="card">
<div class="card-content">
<span class="card-title">Alle Protokolle des Bundestag</span>
<p>Liste aller Bundestagsplenarprotokolle von der ersten bis zur 18. Wahlperiode. Eine Volltextsuche ist zurzeit noch nicht implementiert.</p>
<div class="row">
<form method="GET" class="col l4 offset-l8 m6 offset-m6 s12">
{% csrf_token %}
<div class="row">
<div class="input-field">
<i class="material-icons prefix">search</i>
{{form}}
</div>
</div>
</form>
</div>
<div style="overflow-x:auto;">
{% render_table table %}
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock content %}

View File

@ -0,0 +1,144 @@
{% extends "blog/base.html" %}
{% load render_table from django_tables2 %}
{% block content %}
<div class="container">
<div class="row">
<div class="col s12 m4">
<div class="card">
<div class="card-content">
<span class="card-title center-align">
Rede:<br />{{current_speech.speech_id}}</span>
<p class="center-align"><i class="large material-icons blue-grey-text darken-4">insert_comment</i></p>
<span class="card-title">Metadaten</span>
<ul>
<li><i class="material-icons blue-grey-text darken-4" style="margin-right: 10px;">insert_drive_file</i><a href="/protokolle/protokoll/{{current_speech.foreign_protocol.protocol_id}}">Aus Protokoll:
{{current_speech.foreign_protocol.protocol_id}}</a></li>
<br />
<li><i class="material-icons blue-grey-text darken-4" style="margin-right: 10px;">date_range</i>Datum: {{current_speech.foreign_protocol.session_date}}</li>
<br />
<li><i class="material-icons blue-grey-text darken-4" style="margin-right: 10px;">access_time</i>Startuhrzeit der Sitzung: {{current_speech.foreign_protocol.start_of_session}} Uhr</li>
<br />
<li><i class="material-icons blue-grey-text darken-4" style="margin-right: 10px;">av_timer</i>Enduhrzeit der Sitzung: {{current_speech.foreign_protocol.end_of_session}} Uhr</li>
<br />
{% if current_speech.foreign_speaker.id %}
<a href="/mdbs/mdb/{{current_speech.foreign_speaker.id}}">
<li><i class="material-icons blue-grey-text darken-4" style="margin-right: 10px;">fingerprint</i>Redner ID: {{current_speech.foreign_speaker.id}}</li>
</a>
{%else%}
<li><i class="material-icons blue-grey-text darken-4" style="margin-right: 10px;">fingerprint</i>Redner ID: Nicht erkannt {{current_speech.foreign_speaker.id}}</li>
{% endif %}
<br />
<li><i class="material-icons blue-grey-text darken-4" style="margin-right: 10px;">perm_identity</i>Rednertyp: {{current_speech.speaker_type}}</li>
<br />
<li><i class="material-icons blue-grey-text darken-4" style="margin-right: 10px;">short_text</i>Original String: {{current_speech.original_string}}<a class="tooltipped" data-position="bottom" data-tooltip="Dies ist die Zeichenfolge, mit der der aktuelle Redner oder die aktuelle Rednerin im original Protokoll vor ihrem Redebeitrag genannt wurde. Passt dieser nicht zum Namen, der über der Rede steht, ist leider etwas bei der automatischen Erkennung schiefgegangen. Steht kein Name über der Rede, wurde der Redner nicht automatisch erkannt."><i
class="material-icons blue-grey-text darken-4">info_outline</i></a></li>
<br />
<li><i class="material-icons blue-grey-text darken-4" style="margin-right: 10px;">record_voice_over</i>Unterbrechungen/Zurufe: {{interruptions}}</li>
<br />
<li><i class="material-icons blue-grey-text darken-4" style="margin-right: 10px;">subject</i>Länge: {{words}} Wörter</li>
</div>
</div>
<ul class="collapsible hoverable">
<li>
<div class="collapsible-header"><i class="material-icons left blue-grey-text darken-4">sort_by_alpha</i>Vokabular</div>
<div class="collapsible-body white"><span><b>Vokabeln: {{unique_words}}</b><br /><ol>{{ vocabulary|safe }}</ol></span></div>
</li>
<li>
<div class="collapsible-header"><i class="material-icons left blue-grey-text darken-4">toc</i>Inhaltsverzeichnis</div>
<div class="collapsible-body white"><span>{{current_speech.foreign_protocol.toc}}</span></div>
</li>
{% if current_speech.foreign_protocol.attachment %}
<li>
<div class="collapsible-header"><i class="material-icons left blue-grey-text darken-4">folder</i>Anlagen</div>
<div class="collapsible-body white"><span>{{current_speech.foreign_protocol.attachment}}</span></div>
</li>
{% endif %}
</ul>
</div>
<div class="col s12 m8">
{% if previous_speech.speech_content %}
<ul class="collapsible hoverable white">
<li>
<div class="collapsible-header"><i class="large material-icons blue-grey-text darken-4">insert_comment</i>Vorherige Rede als Kontext</div>
<div class="collapsible-body">
<h6>{% if previous_speech.foreign_speaker.id %}
Rede von {% if previous_speech.foreign_speaker.title %}
{{previous_speech.foreign_speaker.title}}
{% endif %}
{% if previous_speech.foreign_speaker.nobility %}
{{previous_speech.foreign_speaker.nobility}}
{% endif %}
{{previous_speech.foreign_speaker.first_name}}
{% if previous_speech.foreign_speaker.name_prefix %}
{{previous_speech.foreign_speaker.name_prefix}}
{% endif %}
{{previous_speech.foreign_speaker.last_name}}
({{previous_speech.foreign_speaker.party}})
{% else %}
<span class="card-title">Rede von: Unbekannt<a class="tooltipped" data-position="bottom" data-tooltip="Dieses Mitglied des Bundestags konnte leider nicht automatisch erkannt werden. Grundlegende Infos zu Namen etc. können beim zugehörigen Redeeintrag unter dem Punkt Original String gefunden werden."><i
class="material-icons blue-grey-text darken-4" style="margin-right: 10px;">info_outline</i></a></span>
{% endif %}
</h6>
<span>{% autoescape off %}{{previous_speech_html}}{% endautoescape %}</span>
</div>
</li>
</ul>
{% endif %}
<div class="card">
<div class="card-content">
{% if previous_speech %}
<div class="center-align"><a href="/protokolle/rede/{{previous_speech.speech_id}}" class="waves-effect waves-light light-green darken-3 btn"><i class="material-icons left">arrow_upward</i>Zur Rede davor</a></div>
<br />
{% endif %}
{% if current_speech.foreign_speaker.id%}
<span class="card-title">Rede von {% if current_speech.foreign_speaker.title %}
{{current_speech.foreign_speaker.title}}
{% endif %}
{% if current_speech.foreign_speaker.nobility %}
{{current_speech.foreign_speaker.nobility}}
{% endif %}
{{current_speech.foreign_speaker.first_name}}
{% if current_speech.foreign_speaker.name_prefix %}
{{current_speech.foreign_speaker.name_prefix}}
{% endif %}
{{current_speech.foreign_speaker.last_name}}
({{current_speech.foreign_speaker.party}})</span>
{% else %}
<span class="card-title">Rede von: Unbekannt<a class="tooltipped" data-position="bottom" data-tooltip="Dieses Mitglied des Bundestags konnte leider nicht automatisch erkannt werden. Grundlegende Infos zu Namen etc. können links unter 'Original String' gelesen werden."><i
class="material-icons blue-grey-text darken-4" style="margin-right: 10px;">info_outline</i></a></span>
{% endif %}
{% autoescape off %}
{{current_speech_html}}
{% endautoescape %}
{% if next_speech %}
<div class="center-align"><br /><a href="/protokolle/rede/{{next_speech.speech_id}}" class="waves-effect waves-light light-green darken-3 btn"><i class="material-icons left">arrow_downward</i>Zur Rede danach</a></div>
{% endif %}
</div>
</div>
{% if next_speech.speech_content %}
<ul class="collapsible hoverable white">
<li>
<div class="collapsible-header"><i class="large material-icons blue-grey-text darken-4">insert_comment</i>Nächste Rede als Kontext</div>
<div class="collapsible-body">
<h6>Rede von {% if next_speech.foreign_speaker.title %}
{{next_speech.foreign_speaker.title}}
{% endif %}
{% if next_speech.foreign_speaker.nobility %}
{{next_speech.foreign_speaker.nobility}}
{% endif %}
{{next_speech.foreign_speaker.first_name}}
{% if next_speech.foreign_speaker.name_prefix %}
{{next_speech.foreign_speaker.name_prefix}}
{% endif %}
{{next_speech.foreign_speaker.last_name}}
({{next_speech.foreign_speaker.party}})</h6>
<span><span>{% autoescape off %}{{next_speech_html}}{% endautoescape %}</span>
</div>
</li>
</ul>
{% endif %}
</div>
</div>
</div>
{% endblock content %}

View File

@ -0,0 +1,31 @@
{% extends "blog/base.html" %}
{% load render_table from django_tables2 %}
{% block content %}
<div class="container">
<div class="row">
<div class="col s12">
<div class="card">
<div class="card-content">
<span class="card-title">Reden und Redebeiträge aller Mitglieder des Bundestags seit 1949 bis 2017</span>
<p>Hier ist eine liste aller Reden, die Mitglieder des Bundestags gehalten haben. Eine Volltextsuche ist zurzeit noch nicht implementiert.</p>
<div class="row">
<form method="GET" class="col l4 offset-l8 m6 offset-m6 s12">
{% csrf_token %}
<div class="row">
<div class="input-field">
<i class="material-icons prefix">search</i>
{{form}}
</div>
</div>
</form>
</div>
<div style="overflow-x:auto;">
{% render_table table %}
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock content %}

View File

@ -0,0 +1,95 @@
{% load django_tables2 %}
{% load i18n %}
{% block table-wrapper %}
{% block table %}
<table {% render_attrs table.attrs %} class="highlight">
{% block table.thead %}
{% if table.show_header %}
<thead {{ table.attrs.thead.as_html }}>
<tr>
{% for column in table.columns %}
<th {{ column.attrs.th.as_html }}>
{% if column.orderable %}
<a href="{% querystring table.prefixed_order_by_field=column.order_by_alias.next %}"><i class="material-icons ">sort</i> {{ column.header }}</a>
{% else %}
{{ column.header }}
{% endif %}
</th>
{% endfor %}
</tr>
</thead>
{% endif %}
{% endblock table.thead %}
{% block table.tbody %}
<tbody {{ table.attrs.tbody.as_html }}>
{% for row in table.paginated_rows %}
{% block table.tbody.row %}
<tr {{ row.attrs.as_html }}>
{% for column, cell in row.items %}
<td {{ column.attrs.td.as_html }}>{% if column.localize == None %}{{ cell }}{% else %}{% if column.localize %}{{ cell|localize }}{% else %}{{ cell|unlocalize }}{% endif %}{% endif %}</td>
{% endfor %}
</tr>
{% endblock table.tbody.row %}
{% empty %}
{% if table.empty_text %}
{% block table.tbody.empty_text %}
<tr><td colspan="{{ table.columns|length }}">{{ table.empty_text }}</td></tr>
{% endblock table.tbody.empty_text %}
{% endif %}
{% endfor %}
</tbody>
{% endblock table.tbody %}
{% block table.tfoot %}
{% if table.has_footer %}
<tfoot {{ table.attrs.tfoot.as_html }}>
<tr>
{% for column in table.columns %}
<td {{ column.attrs.tf.as_html }}>{{ column.footer }}</td>
{% endfor %}
</tr>
</tfoot>
{% endif %}
{% endblock table.tfoot %}
</table>
{% endblock table %}
{% block pagination %}
{% if table.page and table.paginator.num_pages > 1 %}
<ul class="pagination">
{% if table.page.has_previous %}
{% block pagination.previous %}
<li class="previous waves-effect">
<a href="{% querystring table.prefixed_page_field=table.page.previous_page_number %}">
{% trans '<i class="material-icons">chevron_left</i>' %}
</a>
</li>
{% endblock pagination.previous %}
{% endif %}
{% if table.page.has_previous or table.page.has_next %}
{% block pagination.range %}
{% for p in table.page|table_page_range:table.paginator %}
<li {% if p == table.page.number %}class="active light-green darken-3"{% endif %} class="waves-effect">
{% if p == '...' %}
<a href="#">{{ p }}</a>
{% else %}
<a href="{% querystring table.prefixed_page_field=p %}">
{{ p }}
</a>
{% endif %}
</li>
{% endfor %}
{% endblock pagination.range %}
{% endif %}
{% if table.page.has_next %}
{% block pagination.next %}
<li class="next waves-effect">
<a href="{% querystring table.prefixed_page_field=table.page.next_page_number %}">
{% trans '<i class="material-icons">chevron_right</i>' %}
</a>
</li>
{% endblock pagination.next %}
{% endif %}
</ul>
{% endif %}
{% endblock pagination %}
{% endblock table-wrapper %}

3
app/speeches/tests.py Executable file
View File

@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

9
app/speeches/urls.py Executable file
View File

@ -0,0 +1,9 @@
from django.urls import path
from . import views
urlpatterns = [
path("reden/", views.speeches, name="Reden"),
path("liste-protokolle/", views.protocols, name="Protokoll-list"),
path("protokoll/<int:protocol_id>", views.protocol, name="Protokoll"),
path("rede/<str:speech_id>", views.speech, name="Rede")
]

37
app/speeches/utils.py Executable file
View File

@ -0,0 +1,37 @@
import re
from lxml import etree
def create_html_speech(speech_content_xml_string):
"""
COnverts the XML speech content into styled html. Also counts the words and
shows the vocabulary.
"""
speech_html = "<div>" + speech_content_xml_string + "</div>"
speech_html = etree.fromstring(speech_html)
raw_text = []
interruptions = 0
for element in speech_html.iter():
if(element.tag == "p"):
raw_text.append(element.text)
element.tag = "span"
element.attrib["class"]="line"
element.attrib.pop("klasse", None)
elif(element.tag == "kommentar"):
interruptions += 1
element.tag = "span"
element.attrib["class"]="comment"
element.attrib.pop("klasse", None)
elif(element.tag == "metadata"):
element.tag = "blockquote"
element.attrib["class"]="metadata"
element.attrib.pop("klasse", None)
element.text = "Metadaten/Kopzeile:" + "\\n" + element.text
raw_text = [element for element in raw_text if element != None]
raw_text = "".join(raw_text)
speech_html = etree.tostring(speech_html, pretty_print=True, encoding='unicode')
speech_html = re.sub(r"b'", "", speech_html)
speech_html = re.sub(r"\\n\s+\'", "<br/>", speech_html)
speech_html = re.sub(r"\\n", "<br/>", speech_html)
speech_html = re.sub(r"\\'", "'", speech_html)
return(speech_html, raw_text, interruptions)

109
app/speeches/views.py Executable file
View File

@ -0,0 +1,109 @@
from django.shortcuts import render
from django_tables2 import RequestConfig
from .models import Speech, Protocol
from .tables import SpeechTable, ProtocolTable
from django.http import Http404
from .utils import create_html_speech
from .forms import SearchForm, SearchFormSpeech
from watson import search as watson
from collections import Counter
def speech(request, speech_id):
try:
current_speech = Speech.objects.get(pk=speech_id)
if(current_speech.previous_speech_id is not None):
previous_speech = Speech.objects.get(pk=current_speech.previous_speech_id)
previous_speech_html = create_html_speech(previous_speech.speech_content)[0]
else:
previous_speech = None
previous_speech_html = None
if(current_speech.next_speech_id is not None):
next_speech = Speech.objects.get(pk=current_speech.next_speech_id)
next_speech_html = create_html_speech(next_speech.speech_content)[0]
else:
next_speech = None
next_speech_html = None
current_speech_html, raw_text, interruptions = create_html_speech(current_speech.speech_content)
vocabulary = Counter(raw_text.split()).most_common()
unique_words = len(vocabulary)
tmp_str = []
for pair in vocabulary:
tmp_str.append("<li>{}: {}</li>".format(pair[0], pair[1]))
vocabulary = "".join(tmp_str)
except Speech.DoesNotExist:
raise Http404("Speech does not exist")
context = {"title": ("Rede "
+ " "
+ current_speech.speech_id),
"current_speech": current_speech,
"current_speech_html": current_speech_html,
"previous_speech_html": previous_speech_html,
"next_speech_html": next_speech_html,
"previous_speech": previous_speech,
"next_speech": next_speech,
"interruptions": interruptions,
"words": len(raw_text.split()),
"vocabulary": vocabulary,
"unique_words": unique_words}
return render(request, "speeches/speech.html", context)
def speeches(request):
if(request.method == "GET"):
form = SearchFormSpeech(request.GET)
if(form.is_valid()):
query = form.cleaned_data["query"]
search_results = watson.filter(Speech, query)
table = SpeechTable(search_results)
RequestConfig(request, paginate={'per_page': 20}).configure(table)
context = {"title": "Suchergebnisse für " + query,
"form": form, "table": table}
return render(request, "speeches/speeches.html", context)
else:
form = SearchFormSpeech()
table = SpeechTable(Speech.objects.all().order_by("speech_id"))
RequestConfig(request, paginate={'per_page': 20}).configure(table)
context = {"title": "Suche", "table": table, "form": form}
return render(request, "speeches/speeches.html", context)
def protocol(request, protocol_id):
try:
current_protocol = Protocol.objects.get(pk=protocol_id)
related_speeches = Speech.objects.filter(foreign_protocol=protocol_id).order_by("speech_id")
speakers = []
speeches_html = []
for speech in related_speeches:
speakers.append(speech.foreign_speaker)
speech_html = create_html_speech(speech.speech_content)[0]
speeches_html.append(speech_html)
speaker_speech_html = zip(speakers, speeches_html, related_speeches)
except Protocol.DoesNotExist:
raise Http404("Protocol does not exist")
context = {"title": ("Protokoll " + str(current_protocol.protocol_id)),
"current_protocol": current_protocol,
"related_speeches": related_speeches,
"speeches_html": speeches_html,
"speakers": set(speakers),
"speaker_speech_html": speaker_speech_html}
return render(request, "speeches/protocol.html", context)
def protocols(request):
if(request.method == "GET"):
form = SearchForm(request.GET)
if(form.is_valid()):
query = form.cleaned_data["query"]
search_results = watson.filter(Protocol, query)
table = ProtocolTable(search_results)
RequestConfig(request, paginate={'per_page': 20}).configure(table)
context = {"title": "Suchergebnisse für " + query,
"form": form, "table": table}
return render(request, "speeches/protocols.html", context)
else:
form = SearchForm()
table = ProtocolTable(Protocol.objects.all().order_by("session_date"))
RequestConfig(request, paginate={'per_page': 20}).configure(table)
context = {"title": "Suche", "table": table, "form": form}
return render(request, "speeches/protocols.html", context)