jazzmin as a more beauty admin panel

This commit is contained in:
gw3000 2023-07-11 18:04:19 +02:00
parent 8ea5c87c9c
commit aca1c3c3fa
117 changed files with 4 additions and 0 deletions

0
app/bird/__init__.py Normal file
View file

24
app/bird/admin.py Normal file
View file

@ -0,0 +1,24 @@
from django.contrib import admin
from .models import Bird, FallenBird, BirdStatus, Circumstance
@admin.register(FallenBird)
class FallenBirdAdmin(admin.ModelAdmin):
list_display = ["bird", "date_found", "place", "created", "updated", "user"]
list_filter = ("bird", "created", "user")
@admin.register(Bird)
class BirdAdmin(admin.ModelAdmin):
list_display = ["name", "description"]
@admin.register(BirdStatus)
class BirdStatusAdmin(admin.ModelAdmin):
list_display = ["id", "description"]
@admin.register(Circumstance)
class CircumstanceAdmin(admin.ModelAdmin):
list_display = ["id", "description"]

8
app/bird/apps.py Normal file
View file

@ -0,0 +1,8 @@
from django.apps import AppConfig
from django.utils.translation import gettext_lazy as _
class BirdConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "bird"
verbose_name = _("Vögel")

63
app/bird/forms.py Normal file
View file

@ -0,0 +1,63 @@
from datetime import date
from django import forms
from django.utils.translation import gettext_lazy as _
from .models import FallenBird
class DateInput(forms.DateInput):
input_type = "date"
class BirdAddForm(forms.ModelForm):
# find_circumstances_new = forms.CharField(
# widget=forms.HiddenInput(attrs={"class": "textinput form-control mb-3"})
# )
class Meta:
widgets = {
"date_found": DateInput(format="%Y-%m-%d", attrs={"value": date.today})
}
model = FallenBird
fields = [
"bird_identifier",
"bird",
"date_found",
"place",
"find_circumstances",
# "find_circumstances_new",
# "status",
]
labels = {
"bird_identifier": _("Kennung"),
"bird": _("Vogel"),
"date_found": _("Datum des Fundes"),
"place": _("Fundort"),
"find_circumstances": _("Fundumstände"),
# "find_circumstances_new": _("neuer Fundumstand"),
# "status": _("Status"),
}
class BirdEditForm(forms.ModelForm):
class Meta:
widgets = {"date_found": DateInput(format="%Y-%m-%d")}
model = FallenBird
fields = [
"bird_identifier",
"bird",
"date_found",
"place",
"status",
"aviary",
"find_circumstances",
]
labels = {
"bird": _("Vogel"),
"date_found": _("Datum des Fundes"),
"place": _("Fundort"),
"status": _("Status"),
"aviary": _("Voliere"),
"find_circumstances": _("Fundumstände"),
}

View file

@ -0,0 +1,156 @@
# Generated by Django 4.2.2 on 2023-07-10 19:16
import bird.models
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import uuid
class Migration(migrations.Migration):
initial = True
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
("aviary", "0003_alter_aviary_condition"),
("rescuer", "0001_initial"),
]
operations = [
migrations.CreateModel(
name="Bird",
fields=[
(
"id",
models.UUIDField(
default=uuid.uuid4,
editable=False,
primary_key=True,
serialize=False,
),
),
("name", models.CharField(max_length=256, unique=True)),
(
"description",
models.CharField(max_length=4096, verbose_name="Hilfetext"),
),
],
options={
"verbose_name": "Vogel",
"verbose_name_plural": "Vögel",
},
),
migrations.CreateModel(
name="BirdStatus",
fields=[
("id", models.BigAutoField(primary_key=True, serialize=False)),
("description", models.CharField(max_length=256, unique=True)),
],
options={
"verbose_name": "Patientenstatus",
"verbose_name_plural": "Patientenstatus",
},
),
migrations.CreateModel(
name="Circumstance",
fields=[
("id", models.BigAutoField(primary_key=True, serialize=False)),
("description", models.CharField(max_length=256)),
],
options={
"verbose_name": "Fundumstand",
"verbose_name_plural": "Fundumstände",
},
),
migrations.CreateModel(
name="FallenBird",
fields=[
(
"id",
models.UUIDField(
default=uuid.uuid4,
editable=False,
primary_key=True,
serialize=False,
),
),
(
"bird_identifier",
models.CharField(max_length=256, verbose_name="Kennung"),
),
("date_found", models.DateField(verbose_name="Datum des Fundes")),
(
"place",
models.CharField(max_length=256, verbose_name="Ort des Fundes"),
),
(
"created",
models.DateTimeField(auto_now_add=True, verbose_name="angelegt am"),
),
(
"updated",
models.DateTimeField(auto_now=True, verbose_name="geändert am"),
),
("diagnostic_finding", models.CharField(max_length=256)),
(
"costs",
models.JSONField(
default=bird.models.costs_default, verbose_name="Costs"
),
),
(
"aviary",
models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.SET_NULL,
to="aviary.aviary",
),
),
(
"bird",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to="bird.bird",
verbose_name="Patient",
),
),
(
"find_circumstances",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to="bird.circumstance",
),
),
(
"rescuer",
models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.SET_NULL,
to="rescuer.rescuer",
),
),
(
"status",
models.ForeignKey(
default=1,
on_delete=django.db.models.deletion.CASCADE,
to="bird.birdstatus",
),
),
(
"user",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to=settings.AUTH_USER_MODEL,
),
),
],
options={
"verbose_name": "Patient",
"verbose_name_plural": "Patienten",
},
),
]

View file

88
app/bird/models.py Normal file
View file

@ -0,0 +1,88 @@
from datetime import date
from uuid import uuid4
from django.conf import settings
from django.db import models
from django.utils.translation import gettext_lazy as _
from aviary.models import Aviary
from rescuer.models import Rescuer
def costs_default():
return [{"date": date.today().strftime("%Y-%m-%d"), "cost_entry": "0.00"}]
class FallenBird(models.Model):
id = models.UUIDField(primary_key=True, default=uuid4, editable=False)
bird_identifier = models.CharField(max_length=256, verbose_name=_("Kennung"))
bird = models.ForeignKey(
"Bird", on_delete=models.CASCADE, verbose_name=_("Patient")
)
date_found = models.DateField(verbose_name=_("Datum des Fundes"))
place = models.CharField(max_length=256, verbose_name=_("Ort des Fundes"))
created = models.DateTimeField(auto_now_add=True, verbose_name=_("angelegt am"))
updated = models.DateTimeField(auto_now=True, verbose_name=_("geändert am"))
find_circumstances = models.ForeignKey("Circumstance", on_delete=models.CASCADE)
diagnostic_finding = models.CharField(max_length=256)
costs = models.JSONField("Costs", default=costs_default)
rescuer = models.ForeignKey(
Rescuer, on_delete=models.SET_NULL, blank=True, null=True
)
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
status = models.ForeignKey("BirdStatus", on_delete=models.CASCADE, default=1)
aviary = models.ForeignKey(Aviary, on_delete=models.SET_NULL, blank=True, null=True)
class Meta:
verbose_name = _("Patient")
verbose_name_plural = _("Patienten")
def __str__(self):
return self.place
class Bird(models.Model):
id = models.UUIDField(primary_key=True, default=uuid4, editable=False)
name = models.CharField(max_length=256, unique=True)
description = models.CharField(max_length=4096, verbose_name=_("Hilfetext"))
class Meta:
verbose_name = _("Vogel")
verbose_name_plural = _("Vögel")
def __str__(self):
return self.name
class BirdStatus(models.Model):
id = models.BigAutoField(primary_key=True)
description = models.CharField(max_length=256, unique=True)
class Meta:
verbose_name = _("Patientenstatus")
verbose_name_plural = _("Patientenstatus")
def __str__(self):
return self.description
# CHOICE_FIND_CIRCUMSTANCES = [
# ("Neu", "Neu"),
# ("Scheibenschlag", "Scheibenschlag"),
# ("Angriff Hund/Katze", "Angriff Hund/Katze"),
# ("Entkräftet", "Entkräftet"),
# ("Verkehrsunfall", "Verkehrsunfall"),
# ("unbekannt", "unbekannt"),
# ]
class Circumstance(models.Model):
id = models.BigAutoField(primary_key=True)
description = models.CharField(max_length=256)
class Meta:
verbose_name = _("Fundumstand")
verbose_name_plural = _("Fundumstände")
def __str__(self) -> str:
return self.description

View file

@ -0,0 +1,107 @@
{% extends "base.html" %}
{% load static %}
{% block header %}
<!-- Datatable CSS -->
<link rel="stylesheet" href="https://cdn.datatables.net/1.13.4/css/dataTables.bootstrap5.min.css" />
<link rel="stylesheet" href="https://cdn.datatables.net/responsive/2.2.9/css/responsive.bootstrap5.min.css">
<!-- jQuery -->
<script src="https://code.jquery.com/jquery-3.5.1.js"></script>
<!-- Datatable jQuery -->
<script src="https://cdn.datatables.net/1.11.3/js/jquery.dataTables.min.js"></script>
<script src="https://cdn.datatables.net/1.11.3/js/dataTables.bootstrap5.min.js"></script>
<script src="https://cdn.datatables.net/responsive/2.2.9/js/dataTables.responsive.min.js"></script>
<script src="https://cdn.datatables.net/responsive/2.2.9/js/responsive.bootstrap5.min.js"></script>
<script>
$(document).ready(function () {
$('#t__bird_all').DataTable({
language: {
url: 'https://cdn.datatables.net/plug-ins/1.11.3/i18n/de_de.json',
},
paging: false,
info: false,
responsive: true,
columnDefs: [
{ responsivePriority: 1, targets: 0 },
]
})
})
</script>
{% endblock header %}
{% block content %}
<h3>Übersicht aller Patienten in Behandlung</h3>
<p>
Übersicht aller in Behandlung befindlichen oder behandelten Vögel.
</p>
<p>
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#addPatientModal">einen Patienten
anlegen
</button>
</p>
<table class="table table-striped table-hover display responsive nowrap" id="t__bird_all">
<thead>
<tr>
<th>Patienten Alias</th>
<th>Vogel</th>
<th>Finder</th>
<th>Fundort</th>
<th>gefunden am</th>
<th>Status</th>
<th>Voliere</th>
<th>Kosten</th>
</tr>
</thead>
<tbody>
{% for bird in birds %}
<tr>
<td><a href="{% url 'bird_single' bird.id %}">{{ bird.bird_identifier }}</a></td>
<td>{{ bird.bird }}</td>
<td>
<a href="{% url 'rescuer_single' bird.rescuer_id %}">{{ bird.rescuer }}</a>
</td>
<td>{{ bird.place }}</td>
<td>{{ bird.date_found }}</td>
<td>{{ bird.status }}</td>
<td>{{ bird.aviary|default_if_none:"" }}</td>
<td>{{ bird.costs }}</td>
</tr>
{% endfor %}
</tbody>
</table>
<div class="modal fade" id="addPatientModal" tabindex="-1" data-bs-backdrop="static"
aria-labelledby="addRescuerModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header bg-primary">
<h5 class="modal-title text-white" id="addRescuerModalLabel">(neuen) Finder zuweisen</h5>
</div>
<form method="post">
{% csrf_token %}
<div class="modal-body">
<label for="rescuer" class="form-label mt-3">Wählen Sie einen <strong>bereits angelegten</strong>
Finder aus oder legen Sie einen <strong>neuen</strong> Finder an:</label>
<select id="rescuer" class="form-select" name="rescuer_id">
<option value="new_rescuer"><strong>neuen
Finder anlegen</strong></option>
{% for rescuer in rescuer_modal %}
<option value={{rescuer.id}}>
{{rescuer.first_name}} {{rescuer.last_name}},
{{rescuer.street}} {{rescuer.street_number}},
{{rescuer.city}}
</option>
{% endfor %}
</select>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-danger" data-bs-dismiss="modal">Abbruch</button>
<button class="btn btn-primary" type="submit">Übernehmen und weiter</button>
</div>
</div>
</div>
</div>
</form>
{% endblock content %}

View file

@ -0,0 +1,48 @@
{% extends "base.html" %}
{% load static %}
{% load crispy_forms_tags %}
{% block content %}
<h3>Patient anlegen</h3>
<p>(Retter: {{rescuer.first_name}} {{rescuer.last_name}})</p>
<div class="row">
<div class="col-lg-8 mb-3">
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form|crispy }}
<a href="{% url 'bird_all' %}" class="btn btn-danger">Abbruch</a>
<button class="btn btn-primary" type="submit">Patient anlegen</button>
<div class="mt-3"><small>* Pflichtfeld</small></div>
</form>
</div>
<div class="col-lg-4">
<h4>eins</h4>
<p>
Lorem ipsum, dolor sit amet consectetur adipisicing elit. Facilis illum
quos eveniet obcaecati, adipisci voluptate alias iste ipsa blanditiis
earum veritatis provident modi repellendus ut maxime iusto enim distinctio
voluptatum.
</p>
<h4>zwei</h4>
<p>
Lorem ipsum, dolor sit amet consectetur adipisicing elit. Facilis illum
quos eveniet obcaecati, adipisci voluptate alias iste ipsa blanditiis
earum veritatis provident modi repellendus ut maxime iusto enim distinctio
voluptatum.
</p>
<h4>drei</h4>
<p>
Lorem ipsum, dolor sit amet consectetur adipisicing elit. Facilis illum
quos eveniet obcaecati, adipisci voluptate alias iste ipsa blanditiis
earum veritatis provident modi repellendus ut maxime iusto enim distinctio
voluptatum.
</p>
</div>
</div>
<script src="{% static 'js/find_circumstances.js' %}"></script>
{% endblock content %}

View file

@ -0,0 +1,25 @@
{% extends 'base.html' %}
{% block content %}
<h3>Patient löschen</h3>
<div class="row mt-3">
<div class="col-lg-7">
<form method="post">
{% csrf_token %}
<div class="alert alert-dismissible alert-danger">
<h4 class="alert-heading">Warnung!</h4>
<p class="mb-0">Wollen Sie den Vogel <strong>{{bird.bird}}</strong>
Reg-Num.: <strong>{{bird.id}}</strong> löschen?</p>
</div>
</p>
<a href="{% url 'bird_all'%}" class="btn btn-secondary">Abbruch</a>
<button class="btn btn-danger" type="submit">Löschen</button>
</form>
</div>
<div class="col-lg-5">
<h5>Vogel löschen</h5>
<p>
Hinweis zum Löschen eines Vogels!
</p>
</div>
</div>
{% endblock content %}

View file

@ -0,0 +1,13 @@
{% extends "base.html" %}
{% load static %}
{% block content %}
<div class="row">
<div class="col-lg-8 mb-3">
<h3>Hilfesammlung</h3>
{% for bird in birds %}
<h4>{{ bird.name }}</h4>
<p>{{ bird.description }}</p>
{% endfor %}
</div>
</div>
{% endblock content %}

View file

@ -0,0 +1,72 @@
{% extends "base.html" %}
{% load static %}
{% load crispy_forms_tags %}
{% block content %}
<h3>Patient <strong>{{ bird.bird_identifier }}</strong> bearbeiten </h3>
<p>Finder des Patienten: <strong> <a href="{% url 'rescuer_single' bird.rescuer_id %}">{{ bird.rescuer }}</a></strong></p>
<div class="row">
<div class="col-lg-5 mb-3">
<form method="post" enctype="multipart/form-data">
<fieldset>
{% csrf_token %}
{{form|crispy}}
<button class="btn btn-success" type="abbort">Abbrechen</button>
<a href="{% url 'bird_delete' bird.id %}" class="btn btn-danger">Löschen</a>
<button class="btn btn-primary" type="submit">Speichern</button>
</fieldset>
</form>
</div>
<div class="col-lg-5">
<h4>
Kennung
</h4>
<p>
Lorem ipsum dolor sit, amet consectetur adipisicing elit.
Reiciendis, hic enim pariatur, exercitationem, repellat quasi sit
temporibus dicta voluptate in voluptates. Alias deserunt sint
suscipit explicabo et. Perferendis, dolor praesentium.
</p>
<h4>
Vogel
</h4>
<p>
Lorem ipsum dolor sit, amet consectetur adipisicing elit.
Reiciendis, hic enim pariatur, exercitationem, repellat quasi sit
temporibus dicta voluptate in voluptates. Alias deserunt sint
suscipit explicabo et. Perferendis, dolor praesentium.
</p>
<h4>
Fundort
</h4>
<p>
Lorem ipsum dolor sit, amet consectetur adipisicing elit.
Reiciendis, hic enim pariatur, exercitationem, repellat quasi sit
temporibus dicta voluptate in voluptates. Alias deserunt sint
suscipit explicabo et. Perferendis, dolor praesentium.
</p>
<h4>
Voliere
</h4>
<p>
Lorem ipsum dolor sit, amet consectetur adipisicing elit.
Reiciendis, hic enim pariatur, exercitationem, repellat quasi sit
temporibus dicta voluptate in voluptates. Alias deserunt sint
suscipit explicabo et. Perferendis, dolor praesentium.
</p>
<h4>
Kosten
</h4>
<p>
Lorem ipsum dolor sit, amet consectetur adipisicing elit.
Reiciendis, hic enim pariatur, exercitationem, repellat quasi sit
temporibus dicta voluptate in voluptates. Alias deserunt sint
suscipit explicabo et. Perferendis, dolor praesentium.
</p>
</div>
</div>
<script src="{% static 'js/bird.js' %}"></script>
{% endblock content %}

3
app/bird/tests.py Normal file
View file

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

21
app/bird/urls.py Normal file
View file

@ -0,0 +1,21 @@
from django.urls import path
from .views import (
bird_all,
bird_help,
bird_create,
bird_delete,
bird_recover,
bird_recover_all,
bird_single,
)
urlpatterns = [
path("all/", bird_all, name="bird_all"),
path("create/", bird_create, name="bird_create"),
path("delete/<id>", bird_delete, name="bird_delete"),
path("help/", bird_help, name="bird_help"),
path("recover/<id>", bird_recover, name="bird_recover"),
path("recover/all", bird_recover_all, name="bird_recover_all"),
path("<id>/", bird_single, name="bird_single"),
]

104
app/bird/views.py Normal file
View file

@ -0,0 +1,104 @@
import names
from django.contrib.auth.decorators import login_required
from django.shortcuts import HttpResponse, redirect, render
from rescuer.models import Rescuer
from .forms import BirdAddForm, BirdEditForm
from .models import FallenBird, Bird
@login_required(login_url="account_login")
def bird_create(request):
form = BirdAddForm(initial={"bird_identifier": names.get_first_name()})
# Rescuer for modal usage
rescuer_id = request.session.get("rescuer_id")
rescuer = Rescuer.objects.get(id=rescuer_id, user=request.user)
# Just show only related rescuers in select field of the form.
if request.method == "POST":
form = BirdAddForm(request.POST or None, request.FILES or None)
# circumstances = Circumstance.objects.all()
rescuer_id = request.session.get("rescuer_id")
rescuer = Rescuer.objects.get(id=rescuer_id, user=request.user)
if form.is_valid():
# if form.cleaned_data["find_circumstances_new"]:
# circumstance = form.cleaned_data["find_circumstances_new"]
# if Circumstance.objects.filter(description=circumstance).exists():
# print("is in circumstances")
fs = form.save(commit=False)
fs.user = request.user
fs.rescuer_id = rescuer_id
fs.save()
request.session["rescuer_id"] = None
return redirect("bird_all")
context = {"form": form, "rescuer": rescuer}
return render(request, "bird/bird_create.html", context)
@login_required(login_url="account_login")
def bird_help(request):
birds = Bird.objects.all()
context = {"birds": birds}
return render(request, "bird/bird_help.html", context)
@login_required(login_url="account_login")
def bird_all(request):
birds = FallenBird.objects.all()
# Sum all costs per bird from json
for bird in birds:
costs_per_bird = float()
for item in bird.costs:
costs_per_bird += float(item["cost_entry"])
if costs_per_bird == 0.0:
costs_per_bird = ""
bird.costs = costs_per_bird
rescuer_modal = Rescuer.objects.all()
context = {"birds": birds, "rescuer_modal": rescuer_modal}
# Post came from the modal form.
if request.method == "POST":
rescuer_id = request._post["rescuer_id"]
if rescuer_id != "new_rescuer":
request.session["rescuer_id"] = rescuer_id
return redirect("bird_create")
else:
return redirect("rescuer_create")
return render(request, "bird/bird_all.html", context)
@login_required(login_url="account_login")
def bird_recover_all(request):
return HttpResponse("Show all recovered Birds")
@login_required(login_url="account_login")
def bird_single(request, id):
bird = FallenBird.objects.get(id=id)
form = BirdEditForm(request.POST or None, request.FILES or None, instance=bird)
if request.method == "POST":
if form.is_valid():
fs = form.save(commit=False)
if fs.status.description != "In Auswilderung":
fs.aviary = None
fs.save()
return redirect("bird_all")
context = {"form": form, "bird": bird}
return render(request, "bird/bird_single.html", context)
@login_required(login_url="account_login")
def bird_delete(request, id):
bird = FallenBird.objects.get(id=id)
if request.method == "POST":
bird.delete()
return redirect("bird_all")
context = {"bird": bird}
return render(request, "bird/bird_delete.html", context)
@login_required(login_url="account_login")
def bird_recover(request, id):
return HttpResponse(f"Show recover with ID {id}")