Add ProjectRequestForm and ProjectRequestAdminForm with JSON-backed multi-selects and help texts

This commit is contained in:
Roman 2025-09-29 00:22:47 +02:00
parent 011e262df6
commit 4e6906e318
1 changed files with 115 additions and 0 deletions

View File

@ -5,6 +5,7 @@ from django.forms.renderers import DjangoTemplates
from django.utils.html import format_html from django.utils.html import format_html
from django.utils.safestring import mark_safe from django.utils.safestring import mark_safe
from django import forms from django import forms
from .models import ProjectRequest, PROJECT_CATEGORIES, WIKIMEDIA_CHOICES
from .models import ( from .models import (
TYPE_CHOICES, TYPE_CHOICES,
@ -306,3 +307,117 @@ class ListForm(BaseApplicationForm, CommonOrderMixin):
model = List model = List
fields = ['domain', 'address'] fields = ['domain', 'address']
exclude = ['intern_notes', 'survey_mail_send','mail_state'] exclude = ['intern_notes', 'survey_mail_send','mail_state']
class ProjectRequestForm(CommonOrderMixin, forms.ModelForm):
"""
Public-facing form for < 1000 EUR project requests.
Key points:
- JSONField-backed multi-selects are exposed as MultipleChoiceField with checkbox widgets.
- We return `list(...)` in clean_* so the JSONField gets a native list.
- Extra UX tweaks: textareas for long text, number inputs with min/max/step, help_texts with links via format_html.
"""
# Expose JSON-backed categories as a checkbox multi-select
categories = forms.MultipleChoiceField(
choices=[(c, c) for c in PROJECT_CATEGORIES],
widget=forms.CheckboxSelectMultiple,
label='Projektkategorie',
help_text='In welche dieser Kategorien lässt sich dein Projekt einordnen?'
)
# Expose JSON-backed wikimedia_projects as a checkbox multi-select
wikimedia_projects = forms.MultipleChoiceField(
choices=[(w, w) for w in WIKIMEDIA_CHOICES],
widget=forms.CheckboxSelectMultiple,
label='Wikimedia Projekt(e)',
help_text='Auf welches Wikimedia-Projekt bezieht sich dein Vorhaben?',
)
class Meta:
model = ProjectRequest
fields = [
'realname', 'email',
'name', 'description',
'categories', 'categories_other',
'wikimedia_projects', 'wikimedia_other',
'start', 'end', 'participants_estimated',
'page', 'group', 'location',
'cost', 'insurance', 'notes',
]
# Widgets are chosen for better UX and to gently guide valid inputs in the browser
widgets = {
'start': AdminDateWidget(),
'end': AdminDateWidget(),
# Long-text fields as textareas with sensible row counts
'description': forms.Textarea(attrs={'rows': 5}),
'notes': forms.Textarea(attrs={'rows': 6}),
# Integer-like fields: browser-side constraints (server still validates in the model)
'participants_estimated': forms.NumberInput(attrs={'min': 0, 'step': 1}),
'cost': forms.NumberInput(attrs={'min': 0, 'max': 1000, 'step': 1}),
}
# Human-readable help_texts; use format_html for safe HTML (links)
help_texts = {
'name': 'Bitte gib einen Namen für das Projekt an.',
'description': 'Bitte beschreibe kurz, was die Ziele deines Projekts sind.',
'participants_estimated': 'Wie viele Personen werden ungefähr an diesem Projekt teilnehmen?',
'page': 'Bitte gib einen Link zur Projektseite in den Wikimedia-Projekten an, wenn vorhanden.',
'group': 'Sofern zutreffend: Bitte gib an, welche Personen das Projekt gemeinsam mit dir organisieren.',
'location': 'Sofern zutreffend: Bitte gib hier den Ort an, an welchem das Projekt stattfinden wird.',
'cost': 'Wie hoch werden die Projektkosten voraussichtlich sein? Bitte gib diese auf volle Euro gerundet an.',
'insurance': format_html(
'Möchtest du die <a href="https://de.wikipedia.org/wiki/Wikipedia:F%C3%B6rderung/Versicherung"> Unfall- und Haftpflichtversicherung</a> von Wikimedia Deutschland in Anspruch nehmen?'),
'notes': format_html(
'Falls du noch weitere Informationen hast, teile sie gern an dieser Stelle mit uns. Für umfangreichere Informationen, schreibe uns eine E-Mail an <a href="mailto:community@wikimedia.de">community@wikimedia.de</a>.'),
}
# Persist multi-selects as Python lists so JSONField stores a JSON array
def clean_categories(self):
return list(self.cleaned_data.get('categories', []))
def clean_wikimedia_projects(self):
return list(self.cleaned_data.get('wikimedia_projects', []))
class ProjectRequestAdminForm(forms.ModelForm):
"""
Admin form for ProjectRequest.
Key points:
- Same checkbox multi-selects for JSON-backed fields to improve admin UX.
- Keep fields="__all__" so admin users can inspect/set workflow fields if needed.
- Do NOT add extra business logic here; validation lives in the model's clean().
"""
categories = forms.MultipleChoiceField(
choices=[(c, c) for c in PROJECT_CATEGORIES],
widget=forms.CheckboxSelectMultiple,
label='Projektkategorie'
)
wikimedia_projects = forms.MultipleChoiceField(
choices=[(w, w) for w in WIKIMEDIA_CHOICES],
widget=forms.CheckboxSelectMultiple,
label='Wikimedia Projekt(e)'
)
class Meta:
model = ProjectRequest
fields = "__all__"
# Make longer texts easier to edit in the admin UI
widgets = {
'description': forms.Textarea(attrs={'rows': 5}),
'notes': forms.Textarea(attrs={'rows': 6}),
}
# Ensure JSONField receives a list
def clean_categories(self):
return list(self.cleaned_data.get('categories', []))
def clean_wikimedia_projects(self):
return list(self.cleaned_data.get('wikimedia_projects', []))