change slug to UUID + title and url to slug

This commit is contained in:
2022-07-30 11:31:50 +00:00
parent adc0d33185
commit 9d8ea00463
11 changed files with 118 additions and 115 deletions

View File

@@ -5,8 +5,8 @@ from .models import Document, Task, TaskList
class DocumentInline(admin.TabularInline): class DocumentInline(admin.TabularInline):
model = Document
form = DocumentInlineForm form = DocumentInlineForm
model = Document
extra = 0 extra = 0
verbose_name = "Dokument" verbose_name = "Dokument"
verbose_name_plural = "Do­ku­men­ten­samm­lung" verbose_name_plural = "Do­ku­men­ten­samm­lung"
@@ -16,7 +16,6 @@ class TaskListAdmin(admin.ModelAdmin):
form = TaskListAdminForm form = TaskListAdminForm
model = TaskList model = TaskList
readonly_fields = ("slug",)
fieldsets = ( fieldsets = (
( (
None, None,
@@ -30,6 +29,7 @@ class TaskListAdmin(admin.ModelAdmin):
}, },
), ),
) )
readonly_fields = ("slug",)
def add_view(self, request, form_url="", extra_context=None): def add_view(self, request, form_url="", extra_context=None):
extra_context = extra_context or {} extra_context = extra_context or {}
@@ -56,23 +56,34 @@ class TaskAdmin(admin.ModelAdmin):
model = Task model = Task
inlines = (DocumentInline,) inlines = (DocumentInline,)
readonly_fields = ("slug",)
fieldsets = ( fieldsets = (
( (
None, None,
{ {
"fields": ( "fields": (
"title", "title",
"shortterm",
"slug",
"task_list", "task_list",
"assigned_to",
"due_date",
"completed",
"completed_date",
"note", "note",
"priority", "priority",
) ),
},
),
(
"Fälligkeit",
{
"fields": (
"due_date",
"assigned_to",
),
},
),
(
"Abgeschlossen",
{
"fields": (
"completed_date",
"completed",
),
}, },
), ),
) )

View File

@@ -1,3 +1,5 @@
from ckeditor.widgets import CKEditorWidget
from django import forms from django import forms
from django.contrib.admin.widgets import FilteredSelectMultiple from django.contrib.admin.widgets import FilteredSelectMultiple
from django.contrib.auth.models import User from django.contrib.auth.models import User
@@ -18,13 +20,11 @@ class DocumentInlineForm(forms.ModelForm):
model = Document model = Document
fields = [ fields = [
"title", "title",
"slug",
"date", "date",
] ]
labels = { labels = {
"title": _("Titel"), "title": _("Titel"),
"slug": _("Permalink"),
} }
@@ -65,6 +65,10 @@ class TaskAdminForm(forms.ModelForm):
"priority": _("Priorität"), "priority": _("Priorität"),
} }
widgets = {
"note": CKEditorWidget(config_name="default"),
}
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs) # to get the self.fields set super().__init__(*args, **kwargs) # to get the self.fields set
self.fields["assigned_to"].empty_label = "Alle" self.fields["assigned_to"].empty_label = "Alle"
@@ -79,7 +83,6 @@ class TaskCreateForm(forms.ModelForm):
fields = [ fields = [
"title", "title",
"shortterm",
"task_list", "task_list",
"due_date", "due_date",
"assigned_to", "assigned_to",
@@ -88,16 +91,15 @@ class TaskCreateForm(forms.ModelForm):
labels = { labels = {
"title": _("Titel des Tasks"), "title": _("Titel des Tasks"),
"shortterm": _("Kürzel für den Link (optional)"),
"task_list": _("Task-Gruppe"), "task_list": _("Task-Gruppe"),
"due_date": _("Fälligkeitsdatum"),
"assigned_to": _("Zuweisen an"), "assigned_to": _("Zuweisen an"),
"due_date": _("Fälligkeitsdatum"),
"note": _("Notizen"),
} }
widgets = { widgets = {
"due_date": DateInput( "due_date": DateInput(format=("%Y-%m-%d")),
format=("%Y-%m-%d"), "note": CKEditorWidget(config_name="intern"),
)
} }
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
@@ -137,20 +139,25 @@ class TaskUpdateForm(forms.ModelForm):
fields = [ fields = [
"assigned_to", "assigned_to",
"due_date", "due_date",
"priority", "completed",
"completed_date",
"note", "note",
"task_list", "task_list",
] ]
labels = { labels = {
"due_date": _("Fälligkeitsdatum"),
"assigned_to": _("Zuweisen an"), "assigned_to": _("Zuweisen an"),
"due_date": _("Fälligkeitsdatum"),
"completed": _("Abgeschlossen"),
"completed_date": _("Datum der Fertigstellung"),
"note": _("Notizen"),
} }
widgets = { widgets = {
"due_date": DateInput( "due_date": DateInput(
format=("%Y-%m-%d"), format=("%Y-%m-%d"),
), ),
"note": CKEditorWidget(config_name="intern"),
"task_list": HiddenInput, "task_list": HiddenInput,
} }
@@ -173,14 +180,12 @@ class DocumentCreateForm(forms.ModelForm):
fields = [ fields = [
"title", "title",
"shortterm",
"date", "date",
"task", "task",
] ]
labels = { labels = {
"title": _("Titel"), "title": _("Titel"),
"shortterm": _("Kürzel für den Link (optional)"),
"date": _("Datum"), "date": _("Datum"),
} }
@@ -197,7 +202,6 @@ class InternTaskCreateForm(TaskCreateForm):
fields = [ fields = [
"title", "title",
"shortterm",
"task_list", "task_list",
"due_date", "due_date",
"assigned_to", "assigned_to",
@@ -206,7 +210,6 @@ class InternTaskCreateForm(TaskCreateForm):
labels = { labels = {
"title": _("Titel des Tasks"), "title": _("Titel des Tasks"),
"shortterm": _("Kürzel für den Link"),
"task_list": _("Task-Gruppe"), "task_list": _("Task-Gruppe"),
"due_date": _("Fälligkeitsdatum"), "due_date": _("Fälligkeitsdatum"),
"assigned_to": _("Zuweisen an"), "assigned_to": _("Zuweisen an"),

View File

@@ -1,18 +1,18 @@
# Generated by Django 4.0.3 on 2022-04-20 20:40 # Generated by Django 4.0.6 on 2022-07-30 10:47
import datetime import datetime
from django.db import migrations, models from django.db import migrations, models
from django.db.models import F
import django.db.models.deletion import django.db.models.deletion
import django.db.models.expressions import django.db.models.expressions
from django.utils.text import slugify from django.utils.text import slugify
import fet2020.utils
def forwards_func(apps, schema_editor): def forwards_func(apps, schema_editor):
Tasks = apps.get_model("tasks", "Task") Tasks = apps.get_model("tasks", "Task")
for elem in Tasks.objects.all(): for elem in Tasks.objects.all():
elem.shortterm = slugify(elem.title[:25]) elem.slug_id = fet2020.utils.create_random_id()
elem.slug = slugify(elem.shortterm) elem.slug = elem.slug_id + "-" + slugify(elem.title)
elem.save() elem.save()
TaskLists = apps.get_model("tasks", "TaskList") TaskLists = apps.get_model("tasks", "TaskList")
@@ -35,13 +35,13 @@ class Migration(migrations.Migration):
), ),
migrations.AddField( migrations.AddField(
model_name='task', model_name='task',
name='shortterm', name='slug',
field=models.CharField(blank=True, max_length=25, null=True), field=models.SlugField(blank=True, unique=True),
), ),
migrations.AddField( migrations.AddField(
model_name='task', model_name='task',
name='slug', name='slug_id',
field=models.SlugField(blank=True, max_length=25, null=True), field=models.CharField(default=fet2020.utils.create_random_id, editable=False, max_length=8, unique=True),
), ),
migrations.AddField( migrations.AddField(
model_name='tasklist', model_name='tasklist',
@@ -58,13 +58,17 @@ class Migration(migrations.Migration):
name='name', name='name',
field=models.CharField(max_length=128), field=models.CharField(max_length=128),
), ),
migrations.AlterField(
model_name='tasklist',
name='slug',
field=models.SlugField(blank=True, unique=True),
),
migrations.CreateModel( migrations.CreateModel(
name='Document', name='Document',
fields=[ fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('title', models.CharField(max_length=128, verbose_name='Titel')), ('title', models.CharField(max_length=128, verbose_name='Titel')),
('shortterm', models.CharField(blank=True, max_length=20)), ('slug_id', models.CharField(default=fet2020.utils.create_random_id, editable=False, max_length=8, unique=True)),
('slug', models.SlugField(blank=True, max_length=20)),
('etherpad_key', models.CharField(blank=True, max_length=50)), ('etherpad_key', models.CharField(blank=True, max_length=50)),
('date', models.DateField(default=datetime.date.today, verbose_name='Datum')), ('date', models.DateField(default=datetime.date.today, verbose_name='Datum')),
('task', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='tasks.task')), ('task', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='tasks.task')),
@@ -74,24 +78,5 @@ class Migration(migrations.Migration):
'verbose_name_plural': 'Dokumente', 'verbose_name_plural': 'Dokumente',
}, },
), ),
migrations.AddConstraint(
model_name='document',
constraint=models.UniqueConstraint(fields=('title', 'date', 'task'), name='unique_task_document'),
),
migrations.RunPython(forwards_func), migrations.RunPython(forwards_func),
migrations.AlterField(
model_name='task',
name='shortterm',
field=models.CharField(blank=True, max_length=25),
),
migrations.AlterField(
model_name='task',
name='slug',
field=models.SlugField(blank=True, max_length=25),
),
migrations.AlterField(
model_name='tasklist',
name='slug',
field=models.SlugField(blank=True, unique=True),
),
] ]

View File

@@ -1,7 +1,8 @@
from datetime import date from datetime import date
from django.conf import settings from django.conf import settings
from django.core.validators import ValidationError
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.core.validators import ValidationError
from django.db import models from django.db import models
from django.db.models import F from django.db.models import F
from django.db.models.constraints import UniqueConstraint from django.db.models.constraints import UniqueConstraint
@@ -11,6 +12,7 @@ from django.utils.text import slugify
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from documents import create_pad from documents import create_pad
from fet2020.utils import create_random_id
from .managers import TaskManager from .managers import TaskManager
@@ -43,8 +45,10 @@ class TaskList(models.Model):
class Task(models.Model): class Task(models.Model):
title = models.CharField(verbose_name="Titel", max_length=128) title = models.CharField(verbose_name="Titel", max_length=128)
shortterm = models.CharField(max_length=25, blank=True) slug_id = models.CharField(
slug = models.SlugField(max_length=25, blank=True) default=create_random_id, max_length=8, unique=True, editable=False
)
slug = models.SlugField(unique=True, blank=True)
task_list = models.ForeignKey( task_list = models.ForeignKey(
TaskList, verbose_name="Aufgabenbereich", on_delete=models.CASCADE, null=True TaskList, verbose_name="Aufgabenbereich", on_delete=models.CASCADE, null=True
@@ -87,14 +91,12 @@ class Task(models.Model):
return self.title return self.title
def get_absolute_url(self): def get_absolute_url(self):
return reverse("tasks:task-detail", kwargs={"pk": self.id}) return reverse("tasks:task-detail", kwargs={"slug": self.slug})
def clean(self):
if not self.shortterm:
self.shortterm = slugify(self.title[:25])
self.slug = slugify(self.shortterm)
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
if not self.slug:
self.slug = self.slug_id + "-" + slugify(self.title)
if self.completed and not self.completed_date: if self.completed and not self.completed_date:
self.completed_date = timezone.now().date() self.completed_date = timezone.now().date()
@@ -107,10 +109,11 @@ class Task(models.Model):
class Document(models.Model): class Document(models.Model):
title = models.CharField(verbose_name="Titel", max_length=128) title = models.CharField(verbose_name="Titel", max_length=128)
shortterm = models.CharField(max_length=20, blank=True) slug_id = models.CharField(
slug = models.SlugField(max_length=20, blank=True) default=create_random_id, max_length=8, unique=True, editable=False
)
etherpad_key = models.CharField(max_length=50, blank=True) etherpad_key = models.CharField(max_length=50, blank=True)
date = models.DateField(verbose_name="Datum", default=date.today) date = models.DateField(verbose_name="Datum", default=date.today)
task = models.ForeignKey(Task, on_delete=models.CASCADE) task = models.ForeignKey(Task, on_delete=models.CASCADE)
@@ -121,19 +124,8 @@ class Document(models.Model):
verbose_name = "Dokument" verbose_name = "Dokument"
verbose_name_plural = "Dokumente" verbose_name_plural = "Dokumente"
constraints = [
# TODO: include lower/upper case - when Django 4.0, then go for it.
UniqueConstraint(
fields=["title", "date", "task"], name="unique_task_document"
),
]
def clean(self): def clean(self):
if not self.shortterm: pad_name = slugify(str(self.slug_id) + "-" + self.title[:40])
self.shortterm = slugify(self.title[:20])
self.slug = slugify(self.shortterm)
pad_name = slugify(str(self.date) + "-" + self.task.slug + "-" + self.slug)
if len(pad_name) > 50: if len(pad_name) > 50:
raise ValidationError( raise ValidationError(
_( _(

View File

@@ -10,7 +10,7 @@ app_name = apps.TasksConfig.name
urlpatterns = [ urlpatterns = [
path("", views.index, name="index"), path("", views.index, name="index"),
path("add/", TaskCreate.as_view(), name="task-create"), path("add/", TaskCreate.as_view(), name="task-create"),
path("<int:pk>/update/", TaskUpdate.as_view(), name="task-update"), path("<slug:slug>/", TaskDetail.as_view(), name="task-detail"),
path("<int:pk>/detail/", TaskDetail.as_view(), name="task-detail"), path("<slug:slug>/update/", TaskUpdate.as_view(), name="task-update"),
path("<int:pk>/add/", DocumentCreate.as_view(), name="docu-create"), path("<slug:slug>/add/", DocumentCreate.as_view(), name="docu-create"),
] ]

View File

@@ -1,6 +1,7 @@
import logging import logging
from collections import deque from collections import deque
from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.shortcuts import render from django.shortcuts import render
@@ -92,11 +93,11 @@ class TaskCreate(LoginRequiredMixin, CreateView):
class TaskUpdate(LoginRequiredMixin, UpdateView): class TaskUpdate(LoginRequiredMixin, UpdateView):
form_class = TaskUpdateForm
model = Task model = Task
template_name = "tasks/task_update.html" template_name = "tasks/task_update.html"
form_class = TaskUpdateForm
task_id = None slug = None
task_list = None task_list = None
def form_valid(self, form): def form_valid(self, form):
@@ -114,12 +115,12 @@ class TaskUpdate(LoginRequiredMixin, UpdateView):
return kwargs return kwargs
def get_initial(self): def get_initial(self):
self.task_id = self.kwargs.get("pk") self.slug = self.kwargs.get("slug")
self.task_list = Task.objects.get(id=self.task_id).task_list self.task_list = Task.objects.get(slug=self.slug).task_list
def get_success_url(self): def get_success_url(self):
kwargs = { kwargs = {
"pk": self.task_id, "slug": self.slug,
} }
return reverse("tasks:task-detail", kwargs=kwargs) return reverse("tasks:task-detail", kwargs=kwargs)
@@ -165,24 +166,24 @@ class DocumentCreate(LoginRequiredMixin, CreateView):
template_name = "tasks/attachment_create.html" template_name = "tasks/attachment_create.html"
form_class = DocumentCreateForm form_class = DocumentCreateForm
task_id = None slug = None
def form_valid(self, form): def form_valid(self, form):
form.instance.created_by = self.request.user form.instance.created_by = self.request.user
add_log_action(self.request, form, "tasks", "document", True) add_log_action(self.request, form, "tasks", "document", True)
return super().form_valid(form) return super().form_valid(form)
def get_initial(self):
self.task_id = self.kwargs.get("pk")
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
context["task"] = Task.objects.get(pk=self.task_id) context["task"] = Task.objects.get(slug=self.slug)
return context return context
def get_initial(self):
self.slug = self.kwargs.get("slug")
def get_success_url(self): def get_success_url(self):
kwargs = { kwargs = {
"pk": self.task_id, "slug": self.slug,
} }
return reverse("tasks:task-detail", kwargs=kwargs) return reverse("tasks:task-detail", kwargs=kwargs)

View File

@@ -28,16 +28,6 @@
<input type="text" id="id_title" name="title" class="mt-1 block w-full rounded-md border-gray-300 dark:border-none shadow-sm focus:border-none focus:ring focus:ring-blue-200 dark:focus:ring-sky-700 focus:ring-opacity-50" required> <input type="text" id="id_title" name="title" class="mt-1 block w-full rounded-md border-gray-300 dark:border-none shadow-sm focus:border-none focus:ring focus:ring-blue-200 dark:focus:ring-sky-700 focus:ring-opacity-50" required>
</label> </label>
<label>
<span class="text-gray-700 dark:text-gray-200">{{ form.shortterm.label }}</span>
{% if form.shortterm.errors %}
<div class="alert alert-danger">
<div class="alert-body">{{ form.shortterm.errors }}</div>
</div>
{% endif %}
<input type="text" id="id_shortterm" name="shortterm" class="mt-1 block w-full rounded-md border-gray-300 dark:border-none shadow-sm focus:border-none focus:ring focus:ring-blue-200 dark:focus:ring-sky-700 focus:ring-opacity-50">
</label>
<label> <label>
<span class="text-gray-700 dark:text-gray-200">{{ form.date.label }}</span> <span class="text-gray-700 dark:text-gray-200">{{ form.date.label }}</span>
{% if form.date.errors %} {% if form.date.errors %}

View File

@@ -95,7 +95,7 @@
<label class="mb-2 flex justify-between items-start"> <label class="mb-2 flex justify-between items-start">
<div class="inline-flex items-baseline mr-2"> <div class="inline-flex items-baseline mr-2">
<input type="checkbox" name="checkbox" value="{{ task.id }}" {% if task.completed %}checked{% endif %} class="rounded border-gray-300 dark:border-none text-proprietary shadow-sm focus:border-blue-300 focus:ring focus:ring-offset-0 focus:ring-blue-200 dark:focus:ring-sky-700 focus:ring-opacity-50"> <input type="checkbox" name="checkbox" value="{{ task.id }}" {% if task.completed %}checked{% endif %} class="rounded border-gray-300 dark:border-none text-proprietary shadow-sm focus:border-blue-300 focus:ring focus:ring-offset-0 focus:ring-blue-200 dark:focus:ring-sky-700 focus:ring-opacity-50">
<span class="ml-2">{{ task.title|truncatechars:45 }} <a href="{% url 'tasks:task-detail' task.id %}" class="inline-block text-proprietary dark:text-proprietary-lighter">Link <i class="fa-solid fa-link"></i></a></span> <span class="ml-2">{{ task.title|truncatechars:45 }} <a href="{% url 'tasks:task-detail' task.slug %}" class="inline-block text-proprietary dark:text-proprietary-lighter">Link <i class="fa-solid fa-link"></i></a></span>
</div> </div>
{% if task.due_date %} {% if task.due_date %}
<div class="inline-flex gap-2 flex-shrink-0"> <div class="inline-flex gap-2 flex-shrink-0">

View File

@@ -28,16 +28,6 @@
<input type="text" id="id_title" name="title" class="mt-1 block w-full rounded-md border-gray-300 dark:border-none shadow-sm focus:border-none focus:ring focus:ring-blue-200 dark:focus:ring-sky-700 focus:ring-opacity-50" required> <input type="text" id="id_title" name="title" class="mt-1 block w-full rounded-md border-gray-300 dark:border-none shadow-sm focus:border-none focus:ring focus:ring-blue-200 dark:focus:ring-sky-700 focus:ring-opacity-50" required>
</label> </label>
<label>
<span class="text-gray-700 dark:text-gray-200">{{ form.shortterm.label }}</span>
{% if form.shortterm.errors %}
<div class="alert alert-danger">
<div class="alert-body">{{ form.shortterm.errors }}</div>
</div>
{% endif %}
<input type="text" id="id_shortterm" name="shortterm" class="mt-1 block w-full rounded-md border-gray-300 dark:border-none shadow-sm focus:border-none focus:ring focus:ring-blue-200 dark:focus:ring-sky-700 focus:ring-opacity-50">
</label>
<label> <label>
<span class="text-gray-700 dark:text-gray-200">{{ form.task_list.label }}</span> <span class="text-gray-700 dark:text-gray-200">{{ form.task_list.label }}</span>
{% if form.task_list.errors %} {% if form.task_list.errors %}

View File

@@ -26,7 +26,7 @@
<section> <section>
<div class="documentList rounded divide-y divide-gray-300 dark:divide-gray-600"> <div class="documentList rounded divide-y divide-gray-300 dark:divide-gray-600">
<a href="{% url 'tasks:docu-create' task.id %}" class="flex justify-between"> <a href="{% url 'tasks:docu-create' task.slug %}" class="flex justify-between">
<h3 class="text-gray-800 dark:text-gray-200"><i class="fa-solid fa-plus fa-fw mr-1"></i>Neues Etherpad erstellen</h2> <h3 class="text-gray-800 dark:text-gray-200"><i class="fa-solid fa-plus fa-fw mr-1"></i>Neues Etherpad erstellen</h2>
</a> </a>
@@ -44,7 +44,7 @@
<a href="{% url 'intern:topic' topic.slug %}" class="btn btn-primary block place-self-end"><i class="fa-solid fa-pen-to-square mr-2"></i>Zu {{ topic.title }}</a> <a href="{% url 'intern:topic' topic.slug %}" class="btn btn-primary block place-self-end"><i class="fa-solid fa-pen-to-square mr-2"></i>Zu {{ topic.title }}</a>
{% endif %} {% endif %}
<a href="{% url 'tasks:task-update' task.id %}" class="btn btn-primary block place-self-end"><i class="fa-solid fa-pen-to-square mr-2"></i>Task bearbeiten</a> <a href="{% url 'tasks:task-update' task.slug %}" class="btn btn-primary block place-self-end"><i class="fa-solid fa-pen-to-square mr-2"></i>Task bearbeiten</a>
</div> </div>
</main> </main>
{% endblock %} {% endblock %}

View File

@@ -46,11 +46,42 @@
<input type="date" id="id_due_date" name="due_date" value="{{ task.due_date|date:"Y-m-d" }}" class="block w-full mt-1 rounded-md border-gray-300 dark:border-none shadow-sm focus:border-none focus:ring focus:ring-blue-200 dark:focus:ring-sky-700 focus:ring-opacity-50"> <input type="date" id="id_due_date" name="due_date" value="{{ task.due_date|date:"Y-m-d" }}" class="block w-full mt-1 rounded-md border-gray-300 dark:border-none shadow-sm focus:border-none focus:ring focus:ring-blue-200 dark:focus:ring-sky-700 focus:ring-opacity-50">
</label> </label>
<label>
<span class="text-gray-700 dark:text-gray-200">{{ form.completed_date.label }}</span>
{% if form.completed_date.errors %}
<div class="alert alert-danger">
<div class="alert-body">{{ form.completed_date.errors }}</div>
</div>
{% endif %}
<input type="date" id="id_completed_date" name="completed_date" value="{{ task.completed_date|date:"Y-m-d" }}" class="block w-full mt-1 rounded-md border-gray-300 dark:border-none shadow-sm focus:border-none focus:ring focus:ring-blue-200 dark:focus:ring-sky-700 focus:ring-opacity-50">
</label>
<label>
<input type="checkbox" id="id_completed" name="completed" value="{{ task.id }}" {% if task.completed %}checked{% endif %} class="rounded border-gray-300 dark:border-none text-proprietary shadow-sm focus:border-blue-300 focus:ring focus:ring-offset-0 focus:ring-blue-200 dark:focus:ring-sky-700 focus:ring-opacity-50">
<span class="text-gray-700 dark:text-gray-200">{{ form.completed.label }}</span>
{% if form.completed.errors %}
<div class="alert alert-danger">
<div class="alert-body">{{ form.completed.errors }}</div>
</div>
{% endif %}
</label>
<label class="block">
<span class="text-gray-700 dark:text-gray-200">{{ form.note.label }}</span>
{% if form.note.errors %}
<div class="alert alert-danger">
<div class="alert-body">{{ form.note.errors }}</div>
</div>
{% endif %}
{{ form.media }}
{{ form.note }}
</label>
<input type="hidden" name="task_list" value="{{ task_list.id }}" id="id_task_list"> <input type="hidden" name="task_list" value="{{ task_list.id }}" id="id_task_list">
<div class="flex flex-col-reverse sm:flex-row gap-3 justify-end pt-4 sm:pt-0"> <div class="flex flex-col-reverse sm:flex-row gap-3 justify-end pt-4 sm:pt-0">
<a href="{% url 'admin:tasks_task_change' task.id %}" class="block btn btn-secondary-proprietary">Task im Admin bearbeiten</a> <a href="{% url 'admin:tasks_task_change' task.id %}" class="block btn btn-secondary-proprietary">Task im Admin bearbeiten</a>
<input type="submit" class="block btn btn-primary" value="Hinzufügen"> <input type="submit" class="block btn btn-primary" value="Bearbeiten">
</div> </div>
</form> </form>
</div> </div>