init project
This commit is contained in:
parent
a26fa2c64a
commit
dc0440fcef
291 changed files with 124865 additions and 485 deletions
1
council/__init__.py
Normal file
1
council/__init__.py
Normal file
|
|
@ -0,0 +1 @@
|
|||
|
||||
BIN
council/__pycache__/__init__.cpython-312.pyc
Normal file
BIN
council/__pycache__/__init__.cpython-312.pyc
Normal file
Binary file not shown.
BIN
council/__pycache__/admin.cpython-312.pyc
Normal file
BIN
council/__pycache__/admin.cpython-312.pyc
Normal file
Binary file not shown.
BIN
council/__pycache__/apps.cpython-312.pyc
Normal file
BIN
council/__pycache__/apps.cpython-312.pyc
Normal file
Binary file not shown.
BIN
council/__pycache__/models.cpython-312.pyc
Normal file
BIN
council/__pycache__/models.cpython-312.pyc
Normal file
Binary file not shown.
BIN
council/__pycache__/urls.cpython-312.pyc
Normal file
BIN
council/__pycache__/urls.cpython-312.pyc
Normal file
Binary file not shown.
BIN
council/__pycache__/views.cpython-312.pyc
Normal file
BIN
council/__pycache__/views.cpython-312.pyc
Normal file
Binary file not shown.
36
council/admin.py
Normal file
36
council/admin.py
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
from django.contrib import admin
|
||||
from .models import PublicBody, Party, Member, Question, Answer
|
||||
|
||||
|
||||
@admin.register(PublicBody)
|
||||
class PublicBodyAdmin(admin.ModelAdmin):
|
||||
list_display = ("name", "website")
|
||||
prepopulated_fields = {"slug": ("name",)}
|
||||
search_fields = ("name",)
|
||||
|
||||
|
||||
@admin.register(Party)
|
||||
class PartyAdmin(admin.ModelAdmin):
|
||||
list_display = ("name", "abbreviation")
|
||||
search_fields = ("name", "abbreviation")
|
||||
|
||||
|
||||
@admin.register(Member)
|
||||
class MemberAdmin(admin.ModelAdmin):
|
||||
list_display = ("first_name", "last_name", "public_body", "party")
|
||||
list_filter = ("public_body", "party")
|
||||
search_fields = ("first_name", "last_name")
|
||||
|
||||
|
||||
@admin.register(Question)
|
||||
class QuestionAdmin(admin.ModelAdmin):
|
||||
list_display = ("title", "member", "created_at")
|
||||
list_filter = ("member",)
|
||||
search_fields = ("title", "body")
|
||||
|
||||
|
||||
@admin.register(Answer)
|
||||
class AnswerAdmin(admin.ModelAdmin):
|
||||
list_display = ("question", "answered_by", "created_at")
|
||||
list_filter = ("answered_by",)
|
||||
search_fields = ("body",)
|
||||
7
council/apps.py
Normal file
7
council/apps.py
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class CouncilConfig(AppConfig):
|
||||
default_auto_field = "django.db.models.BigAutoField"
|
||||
name = "council"
|
||||
verbose_name = "Gemeinderat"
|
||||
105
council/migrations/0001_initial.py
Normal file
105
council/migrations/0001_initial.py
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
# Generated by Django on initial setup
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = []
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name="PublicBody",
|
||||
fields=[
|
||||
("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
|
||||
("name", models.CharField(max_length=255, unique=True)),
|
||||
("slug", models.SlugField(max_length=255, unique=True)),
|
||||
("website", models.URLField(blank=True)),
|
||||
("description", models.TextField(blank=True)),
|
||||
("created_at", models.DateTimeField(auto_now_add=True)),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Gemeinde",
|
||||
"verbose_name_plural": "Gemeinden",
|
||||
"ordering": ["name"],
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="Party",
|
||||
fields=[
|
||||
("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
|
||||
("name", models.CharField(max_length=255, unique=True)),
|
||||
("abbreviation", models.CharField(blank=True, max_length=50)),
|
||||
("color", models.CharField(blank=True, help_text="Hex-Farbe, z. B. #00AAFF", max_length=7)),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Partei",
|
||||
"verbose_name_plural": "Parteien",
|
||||
"ordering": ["name"],
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="Member",
|
||||
fields=[
|
||||
("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
|
||||
("first_name", models.CharField(max_length=150)),
|
||||
("last_name", models.CharField(max_length=150)),
|
||||
("email", models.EmailField(blank=True, max_length=254)),
|
||||
(
|
||||
"party",
|
||||
models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name="members", to="council.party"),
|
||||
),
|
||||
(
|
||||
"public_body",
|
||||
models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name="members", to="council.publicbody"),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Stadträt:in",
|
||||
"verbose_name_plural": "Stadträt:innen",
|
||||
"ordering": ["last_name", "first_name"],
|
||||
"unique_together": {("first_name", "last_name", "public_body")},
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="Question",
|
||||
fields=[
|
||||
("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
|
||||
("title", models.CharField(max_length=255)),
|
||||
("body", models.TextField()),
|
||||
("created_at", models.DateTimeField(auto_now_add=True)),
|
||||
(
|
||||
"member",
|
||||
models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name="questions", to="council.member"),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Frage",
|
||||
"verbose_name_plural": "Fragen",
|
||||
"ordering": ["-created_at"],
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="Answer",
|
||||
fields=[
|
||||
("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
|
||||
("body", models.TextField()),
|
||||
("created_at", models.DateTimeField(auto_now_add=True)),
|
||||
(
|
||||
"answered_by",
|
||||
models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name="answers", to="council.member"),
|
||||
),
|
||||
(
|
||||
"question",
|
||||
models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name="answers", to="council.question"),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Antwort",
|
||||
"verbose_name_plural": "Antworten",
|
||||
"ordering": ["created_at"],
|
||||
},
|
||||
),
|
||||
]
|
||||
1
council/migrations/__init__.py
Normal file
1
council/migrations/__init__.py
Normal file
|
|
@ -0,0 +1 @@
|
|||
|
||||
BIN
council/migrations/__pycache__/0001_initial.cpython-312.pyc
Normal file
BIN
council/migrations/__pycache__/0001_initial.cpython-312.pyc
Normal file
Binary file not shown.
BIN
council/migrations/__pycache__/__init__.cpython-312.pyc
Normal file
BIN
council/migrations/__pycache__/__init__.cpython-312.pyc
Normal file
Binary file not shown.
97
council/models.py
Normal file
97
council/models.py
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
from django.db import models
|
||||
|
||||
|
||||
class PublicBody(models.Model):
|
||||
name = models.CharField(max_length=255, unique=True)
|
||||
slug = models.SlugField(max_length=255, unique=True)
|
||||
website = models.URLField(blank=True)
|
||||
description = models.TextField(blank=True)
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
class Meta:
|
||||
verbose_name = "Gemeinde"
|
||||
verbose_name_plural = "Gemeinden"
|
||||
ordering = ["name"]
|
||||
|
||||
def __str__(self) -> str: # pragma: no cover - trivial
|
||||
return self.name
|
||||
|
||||
|
||||
class Party(models.Model):
|
||||
name = models.CharField(max_length=255, unique=True)
|
||||
abbreviation = models.CharField(max_length=50, blank=True)
|
||||
color = models.CharField(max_length=7, blank=True, help_text="Hex-Farbe, z. B. #00AAFF")
|
||||
|
||||
class Meta:
|
||||
verbose_name = "Partei"
|
||||
verbose_name_plural = "Parteien"
|
||||
ordering = ["name"]
|
||||
|
||||
def __str__(self) -> str: # pragma: no cover
|
||||
return self.abbreviation or self.name
|
||||
|
||||
|
||||
class Member(models.Model):
|
||||
first_name = models.CharField(max_length=150)
|
||||
last_name = models.CharField(max_length=150)
|
||||
email = models.EmailField(blank=True)
|
||||
public_body = models.ForeignKey(
|
||||
PublicBody, related_name="members", on_delete=models.SET_NULL, null=True, blank=True
|
||||
)
|
||||
party = models.ForeignKey(Party, related_name="members", on_delete=models.SET_NULL, null=True, blank=True)
|
||||
|
||||
class Meta:
|
||||
verbose_name = "Stadträt:in"
|
||||
verbose_name_plural = "Stadträt:innen"
|
||||
ordering = ["last_name", "first_name"]
|
||||
unique_together = ("first_name", "last_name", "public_body")
|
||||
|
||||
def __str__(self) -> str: # pragma: no cover
|
||||
return f"{self.first_name} {self.last_name}"
|
||||
|
||||
|
||||
class Question(models.Model):
|
||||
title = models.CharField(max_length=255)
|
||||
body = models.TextField()
|
||||
member = models.ForeignKey(Member, related_name="questions", on_delete=models.CASCADE)
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
class Meta:
|
||||
verbose_name = "Frage"
|
||||
verbose_name_plural = "Fragen"
|
||||
ordering = ["-created_at"]
|
||||
|
||||
def __str__(self) -> str: # pragma: no cover
|
||||
return self.title
|
||||
|
||||
|
||||
class Answer(models.Model):
|
||||
question = models.ForeignKey(Question, related_name="answers", on_delete=models.CASCADE)
|
||||
answered_by = models.ForeignKey(Member, related_name="answers", on_delete=models.SET_NULL, null=True, blank=True)
|
||||
body = models.TextField()
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
class Meta:
|
||||
verbose_name = "Antwort"
|
||||
verbose_name_plural = "Antworten"
|
||||
ordering = ["created_at"]
|
||||
|
||||
def __str__(self) -> str: # pragma: no cover
|
||||
return f"Antwort zu: {self.question.title}"
|
||||
|
||||
|
||||
class Vote(models.Model):
|
||||
title = models.CharField(max_length=255)
|
||||
description = models.TextField(blank=True)
|
||||
public_body = models.ForeignKey(PublicBody, related_name="votes", on_delete=models.CASCADE)
|
||||
date = models.DateField(null=True, blank=True)
|
||||
members = models.ManyToManyField(Member, related_name="votes", blank=True)
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
class Meta:
|
||||
verbose_name = "Abstimmung"
|
||||
verbose_name_plural = "Abstimmungen"
|
||||
ordering = ["-date", "-created_at"]
|
||||
|
||||
def __str__(self) -> str: # pragma: no cover
|
||||
return self.title
|
||||
13
council/urls.py
Normal file
13
council/urls.py
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
from django.urls import path
|
||||
from . import views
|
||||
|
||||
urlpatterns = [
|
||||
path("", views.home, name="home"),
|
||||
path("gemeinden/", views.public_bodies, name="public_bodies"),
|
||||
path("gemeinden/<slug:slug>/", views.public_body_detail, name="public_body_detail"),
|
||||
path("mitglieder/", views.members, name="members"),
|
||||
path("mitglieder/<int:pk>/", views.member_detail, name="member_detail"),
|
||||
path("parteien/", views.parties, name="parties"),
|
||||
path("parteien/<int:pk>/", views.party_detail, name="party_detail"),
|
||||
path("fragen/", views.questions, name="questions"),
|
||||
]
|
||||
61
council/views.py
Normal file
61
council/views.py
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
from django.shortcuts import render, get_object_or_404
|
||||
from .models import PublicBody, Party, Member, Question, Vote
|
||||
|
||||
|
||||
def home(request):
|
||||
return render(request, "index.html", {})
|
||||
|
||||
|
||||
def public_bodies(request):
|
||||
items = PublicBody.objects.all()
|
||||
return render(request, "council/public_bodies.html", {"items": items})
|
||||
|
||||
|
||||
def public_body_detail(request, slug: str):
|
||||
body = get_object_or_404(PublicBody, slug=slug)
|
||||
members = body.members.select_related("party").all()
|
||||
parties = Party.objects.filter(members__public_body=body).distinct()
|
||||
votes = body.votes.all()
|
||||
return render(
|
||||
request,
|
||||
"council/public_body_detail.html",
|
||||
{"body": body, "members": members, "parties": parties, "votes": votes},
|
||||
)
|
||||
|
||||
|
||||
def members(request):
|
||||
items = Member.objects.select_related("public_body", "party").all()
|
||||
return render(request, "council/members.html", {"items": items})
|
||||
|
||||
|
||||
def member_detail(request, pk: int):
|
||||
member = get_object_or_404(Member.objects.select_related("public_body", "party"), pk=pk)
|
||||
questions = member.questions.all()
|
||||
votes = member.votes.select_related("public_body").all()
|
||||
return render(
|
||||
request,
|
||||
"council/member_detail.html",
|
||||
{"member": member, "questions": questions, "votes": votes},
|
||||
)
|
||||
|
||||
|
||||
def parties(request):
|
||||
items = Party.objects.all()
|
||||
return render(request, "council/parties.html", {"items": items})
|
||||
|
||||
|
||||
def party_detail(request, pk: int):
|
||||
party = get_object_or_404(Party, pk=pk)
|
||||
members = party.members.select_related("public_body").all()
|
||||
public_bodies = PublicBody.objects.filter(members__party=party).distinct()
|
||||
questions = Question.objects.filter(member__party=party).select_related("member").all()
|
||||
return render(
|
||||
request,
|
||||
"council/party_detail.html",
|
||||
{"party": party, "members": members, "public_bodies": public_bodies, "questions": questions},
|
||||
)
|
||||
|
||||
|
||||
def questions(request):
|
||||
items = Question.objects.select_related("member").all()
|
||||
return render(request, "council/questions.html", {"items": items})
|
||||
Loading…
Add table
Add a link
Reference in a new issue