Výroční sraz M&M #32
|
@ -150,6 +150,7 @@ INSTALLED_APPS = (
|
||||||
'personalni',
|
'personalni',
|
||||||
'soustredeni',
|
'soustredeni',
|
||||||
'treenode',
|
'treenode',
|
||||||
|
'vyroci',
|
||||||
|
|
||||||
# Admin upravy:
|
# Admin upravy:
|
||||||
|
|
||||||
|
|
|
@ -68,6 +68,9 @@ urlpatterns = [
|
||||||
# REST API
|
# REST API
|
||||||
# path('api/', include(router.urls)),
|
# path('api/', include(router.urls)),
|
||||||
|
|
||||||
|
# Výroční sraz
|
||||||
|
path('sraz/30-let/', include('vyroci.urls')),
|
||||||
zelvuska marked this conversation as resolved
Outdated
|
|||||||
|
|
||||||
]
|
]
|
||||||
|
|
||||||
# This is only needed when using runserver.
|
# This is only needed when using runserver.
|
||||||
|
|
0
vyroci/__init__.py
Normal file
7
vyroci/admin.py
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
from django.contrib import admin
|
||||||
|
|
||||||
|
from .models import UcastnikVyroci
|
||||||
|
|
||||||
|
# Register your models here.
|
||||||
|
|
||||||
|
admin.site.register(UcastnikVyroci)
|
5
vyroci/apps.py
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
|
class VyrociConfig(AppConfig):
|
||||||
|
name = 'vyroci'
|
14
vyroci/forms.py
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
from django.forms import ModelForm
|
||||||
|
from .models import UcastnikVyroci
|
||||||
|
|
||||||
|
|
||||||
|
class UcastnikVyrociForm(ModelForm):
|
||||||
|
class Meta:
|
||||||
|
model = UcastnikVyroci
|
||||||
|
fields = "__all__"
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
for field in ["kdy", "cojemam", "cislo", "dodat"]:
|
||||||
ledoian marked this conversation as resolved
ledoian
commented
Neumí se tohle nějak odkázat na vlastní fieldy? Čekal bych tam nějaké Neumí se tohle nějak odkázat na vlastní fieldy? Čekal bych tam nějaké `self.fields`. (Ale asi je to dost šumák, stejně se to jednou napíše, jednou použije a pak jednou možná smaže, takže je to spíš možnost se naučit nové triky s Djangem než potřeba upravit…)
ledoian
commented
Aha, to je jen podmnožina fieldů. OK then… Aha, to je jen podmnožina fieldů. OK then…
|
|||||||
|
self.fields[field].widget.attrs['rows'] = 2
|
||||||
|
self.fields[field].widget.attrs['cols'] = 22
|
27
vyroci/migrations/0001_initial.py
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
# Generated by Django 2.2.28 on 2023-06-02 18:55
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
initial = True
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='UcastnikVyroci',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('jmeno', models.CharField(help_text='Občanská identifikace účastníka víkendovky', max_length=256, verbose_name='Jméno a příjmení')),
|
||||||
|
('prezdivka', models.CharField(help_text='Zveřejňovaná identifikace účastníka víkendovky', max_length=256, verbose_name='Přezdívka (do seznamu účastníků, například Bětka N.)')),
|
||||||
zelvuska marked this conversation as resolved
Outdated
zelvuska
commented
Zveřejňovaná Zveřejňovaná
zelvuska
commented
Možná „Přezdívka (bude výše)“ Možná „Přezdívka (bude výše)“
|
|||||||
|
('email', models.EmailField(help_text='Kontakt na účastníka víkendovky', max_length=256, verbose_name='E-mail')),
|
||||||
|
('kdy', models.TextField(verbose_name='Řešil nebo organizoval jsi M&M? Kdy?')),
|
||||||
|
('cojemam', models.TextField(verbose_name='Co znamená M&M (a proč)?')),
|
||||||
|
('cislo', models.TextField(verbose_name='Co v M&Mí historii značí číslo 265252859812191058636308480000000?')),
|
||||||
|
('dodat', models.TextField(blank=True, null=True, verbose_name='Co chci ještě dodat?')),
|
||||||
zelvuska marked this conversation as resolved
Outdated
ledoian
commented
Tyhle fieldy vůbec nemusejí být krátké. Zvlášť dodat je potenciálně dlouhé a může mít i víc, než 256 znaků. (Pro srovnání, tenhle komentář sám o sobě má 188 znaků, resp. 214 bytů v UTF-8.) Tyhle fieldy vůbec nemusejí být krátké. Zvlášť dodat je potenciálně dlouhé a může mít i víc, než 256 znaků. (Pro srovnání, tenhle komentář sám o sobě má 188 znaků, resp. 214 bytů v UTF-8.)
ledoian
commented
Jo, a tenhle komentář se spíš týká modelu než migrace, ale podruhé se mi ho psát nechce :-) (103 znaků) Jo, a tenhle komentář se spíš týká modelu než migrace, ale podruhé se mi ho psát nechce :-) (103 znaků)
|
|||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
0
vyroci/migrations/__init__.py
Normal file
40
vyroci/models.py
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
from django.db import models
|
||||||
|
|
||||||
|
# Create your models here.
|
||||||
|
|
||||||
|
|
||||||
|
class UcastnikVyroci(models.Model):
|
||||||
|
|
||||||
|
jmeno = models.CharField(
|
||||||
|
"Jméno a příjmení", max_length=256, blank=False, null=False,
|
||||||
zelvuska marked this conversation as resolved
Outdated
zelvuska
commented
„příjmení“ „příjmení“
|
|||||||
|
help_text="Občanská identifikace účastníka víkendovky"
|
||||||
|
)
|
||||||
|
|
||||||
|
prezdivka = models.CharField(
|
||||||
|
"Přezdívka (do seznamu účastníků, například Bětka N.)", max_length=256, blank=False, null=False,
|
||||||
|
help_text="Zveřejňovaná identifikace účastníka víkendovky"
|
||||||
|
)
|
||||||
|
|
||||||
|
email = models.EmailField(
|
||||||
|
"E-mail", max_length=256, blank=False, null=False,
|
||||||
|
help_text="Kontakt na účastníka víkendovky"
|
||||||
|
)
|
||||||
|
|
||||||
|
kdy = models.TextField(
|
||||||
|
"Řešil nebo organizoval jsi M&M? Kdy?", blank=False,
|
||||||
|
null=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
cojemam = models.TextField(
|
||||||
|
"Co znamená M&M (a proč)?", blank=False, null=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
cislo = models.TextField(
|
||||||
|
"Co v M&Mí historii značí číslo 265252859812191058636308480000000?",
|
||||||
|
blank=False, null=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
dodat = models.TextField(
|
||||||
|
"Co chci ještě dodat?", blank=True, null=True,
|
||||||
|
)
|
||||||
|
|
62
vyroci/templates/vyroci/vyroci.html
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<h1>{% block nadpis1a %}M&Mí 30!*{% endblock nadpis1a %}</h1>
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<h4>*plným názvem M&Mí 265252859812191058636308480000000.</h4>
|
||||||
zelvuska marked this conversation as resolved
Outdated
zelvuska
commented
Nakonci „akcí“ místo „akci“. Nakonci „akcí“ místo „akci“.
|
|||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<p>Rádi bychom Tě pozvali na plánovaný M&Mí sraz, kde nalezneš možnost se setkat se současnými organizátory, minulými organizátory a účastníky, předminulými organizátory a účastníky, předpředminulými organizátory a účastníky a jinými M&Mími legendami.</p>
|
||||||
|
|
||||||
zelvuska marked this conversation as resolved
Outdated
ledoian
commented
Nevím, jaká je dohoda, ale možná je spíš žádoucí, aby byli všichni účastníci v databázi, protože jinak se na Káťu a (R)adima bude snadno zapomínat a nebude to vidět. Klidně bych je rovnou přidal v rámci migrace (a do kontextu pak klidně narval Nevím, jaká je dohoda, ale možná je spíš žádoucí, aby byli všichni účastníci v databázi, protože jinak se na Káťu a (R)adima bude snadno zapomínat a nebude to vidět.
Klidně bych je rovnou přidal v rámci migrace (a do kontextu pak klidně narval `seznam_ucastniku = ', '.join(u.prezdivka for u in ucastnici)`
zelvuska
commented
Přijde mi, že jednodušší bude je tam naházet ručně po nasazení… Přijde mi, že jednodušší bude je tam naházet ručně po nasazení…
ledoian
commented
Klidně, když se na to nezapomene (nebo když těm dvěma někdo řekne, že se mají prostě normálně zaregistrovat), spíš mi jde o to, aby tady nebyli nahardcodění, protože „určitě pojedou“. Klidně, když se na to nezapomene (nebo když těm dvěma někdo řekne, že se mají prostě normálně zaregistrovat), spíš mi jde o to, aby tady nebyli nahardcodění, protože „určitě pojedou“.
|
|||||||
|
<p>Těšit se můžeš na zábavnou akci pro všechny věkové kategorie. Pokud máš chuť se zúčastnit, tak neváhej a vyplň přihlašovací formulář níže (pokud plánuješ přijet jen na část víkendu nebo s sebou někoho vzít – třeba děti, tak to napiš do poznámky). Podrobnější informace o akci budeme rozesílat přibližně dva týdny před akcí.</p>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li> Kdy: pátek 22. – neděle 24. 9. 2023 </li>
|
||||||
|
<li> Kde: <a href="https://borovice.cz/inzerat/2587-zakladna-pratel-prirody-upirci-2">Klubovna Upírků v Libčicích n.V.</a></li>
|
||||||
|
<li> Kdo jede: {% for ucastnik in ucastnici %}{% if not forloop.first %}, {% endif %}{{ ucastnik.prezdivka }}{% endfor %}</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2>Přihlašovací formulář</h2>
|
||||||
|
|
||||||
|
<p><b>Tučně</b> popsaná pole jsou povinná.</p>
|
||||||
|
|
||||||
|
<form action="{% url 'vyrocni_sraz' %}" method="post">
|
||||||
|
<table class="form">
|
||||||
|
{{form.non_field_errors}}
|
||||||
|
{% for field in form %}
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<label class="field-label{% if field.field.required %} field-required{% endif %}" for="{{ field.id_for_label }}">
|
||||||
|
{{ field.label }}
|
||||||
|
</label>
|
||||||
|
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td {% if field.help_text %} class="field-with-comment"{% endif %}>
|
||||||
|
{{ field }}
|
||||||
|
<span class="field-comment">{{ field.help_text|safe }}</span>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
{% if field.errors %}
|
||||||
|
<tr>
|
||||||
|
<td colspan="2"><span class="field-error">{{ field.errors }}</span></td>
|
||||||
zelvuska marked this conversation as resolved
ledoian
commented
Non-field errors bych čekal spíš nahoře než dole… Non-field errors bych čekal spíš nahoře než dole…
|
|||||||
|
</tr>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</table>
|
||||||
|
|
||||||
zelvuska marked this conversation as resolved
ledoian
commented
Template prohlížím jen zběžně, pokud to dobře vypadá (i ve Chrome a Edgi :-P), tak je mi asi jedno, jak to vypadá… Template prohlížím jen zběžně, pokud to dobře vypadá (i ve Chrome a Edgi :-P), tak je mi asi jedno, jak to vypadá…
|
|||||||
|
{% csrf_token %}
|
||||||
|
|
||||||
|
<input type="submit" value="Přihlásit se!">
|
||||||
|
</form>
|
||||||
|
|
||||||
|
{% endblock content %}
|
31
vyroci/templates/vyroci/vyroci_list.html
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<h1>{% block nadpis1a %}M&Mí 30! odpovědi{% endblock nadpis1a %}</h1>
|
||||||
|
|
||||||
|
<table class="dosla_reseni">
|
||||||
|
<tr>
|
||||||
|
<th>Jméno</th>
|
||||||
|
<th>Přezdívka</th>
|
||||||
|
<th>E-mail</th>
|
||||||
|
<th>Kdy účastník/org</th>
|
||||||
|
<th>Co znamená M&M?</th>
|
||||||
|
<th>Co znamená číslo?</th>
|
||||||
|
<th>Něco dodat?</th>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
{% for u in object_list %}
|
||||||
zelvuska marked this conversation as resolved
Outdated
ledoian
commented
Tohle funguje? Měl jsem za to, že Jo, a když už jsme u toho, tak bych neobjektifikoval účastníky a tu iterační proměnou pojmenoval třeba Tohle funguje? Měl jsem za to, že `ListView` vyrábí v kontextu `object_list`… (A možná bych to malinko preferoval, kvůli konzistenci; byť by asi rozumné naopak bylo plošně všechny `object_list` přepsat na to, seznamy čeho to reálně jsou. Asi spíš výhledově, do Kanboardu…)
Jo, a když už jsme u toho, tak bych neobjektifikoval účastníky a tu iterační proměnou pojmenoval třeba `u`. Ale taky je to spíš taková poznámka, která by se spíš týkala nějaké dlouhodobější stránky, než téhle…
|
|||||||
|
<tr>
|
||||||
|
<td>{{ u.jmeno }}</td>
|
||||||
|
<td>{{ u.prezdivka }}</td>
|
||||||
|
<td>{{ u.email }}</td>
|
||||||
|
<td style="word-break: break-all">{{ u.kdy }}</td>
|
||||||
|
<td style="word-break: break-all">{{ u.cojemam }}</td>
|
||||||
|
<td style="word-break: break-all">{{ u.cislo }}</td>
|
||||||
|
<td style="word-break: break-all">{{ u.dodat }}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</table>
|
||||||
|
|
||||||
|
{% endblock content %}
|
17
vyroci/urls.py
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
from django.urls import path
|
||||||
|
|
||||||
|
from seminar.utils import org_required
|
||||||
|
from .views import VyrociView, VyrociListView
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
path(
|
||||||
|
'',
|
||||||
|
VyrociView.as_view(),
|
||||||
|
name='vyrocni_sraz'
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
'ucastnici/',
|
||||||
ledoian
commented
Ale ne, to jsme se nepochopili… Měl jsem na mysli, že by celý sraz bydlel v nějaké hlubině, typu Ten hlavní point je, že si nezabiješ adresu Navíc možná může být žádoucí, aby stránka téhle akce existovala na stejné adrese ještě dalších 30 let, aby si to mohli orgové připomínat (zvlášť, pokud bychom tam někde měli nějaké další materiály z akce nebo něco podobného). A taky mi přijde, že i seznam účastníků (IMO to fakt nejsou výsledky) sémanticky patří do „složky“ (stejného segmentu cesty) toho srazu, tedy že mají být někde pod tím, ne „vedle“. Řetězec A zároveň tím, že to bude mít v hlavních ¹Jo, jsem si vědom toho, že můžeš pak napsat Ale ne, to jsme se nepochopili… Měl jsem na mysli, že by celý sraz bydlel v nějaké hlubině, typu `mam.mff.cuni.cz/sraz-30let/` a tam už by byly jednoduché cesty – adresa bez dalšího suffixu (tj. tady by byl záznam pro prázdný řetězec) by vedla na tu hlavní stránku a pak třeba `mam.….cz/sraz-30let/ucastnici` by vedlo na seznam přihlášených účastníků.
Ten hlavní point je, že si nezabiješ adresu `mam.….cz/<něco užitečného>` touhle jednorázovou věcí, protože pokud by se někdo někdy rozhodl, že chce stránky i pro účastnické srazy (`mam.….cz/srazy/nebeska-rybna-2023`), tak tam tohle bude překážet¹. (Vzhledem k tomu, jak to bastlíme, bych fakt nečekal, že se někdo bude snažit aplikaci `vyroci` zobecnit pro libovolné další použití)
Navíc možná může být žádoucí, aby stránka téhle akce existovala na stejné adrese ještě dalších 30 let, aby si to mohli orgové připomínat (zvlášť, pokud bychom tam někde měli nějaké další materiály z akce nebo něco podobného).
A taky mi přijde, že i seznam účastníků (IMO to fakt nejsou výsledky) sémanticky patří do „složky“ (stejného segmentu cesty) toho srazu, tedy že mají být někde pod tím, ne „vedle“.
Řetězec `sraz-30let` se může změnit, případně by asi šlo to vyloženě schovat do něčeho jako `/srazy/org30let/`, ale pozor na to, že tím by se opět zabetonovala cestová hierarchie (i.e. pokud se někdy někdo rozhodne, že pro případný účastnický sraz chce spíš adresu `mam.….cz/sraz/nebeska-rybna-2023`, tak pak vzniknou vedle sebe složky `/sraz/` i `/srazy/` a bude to mást orgy a webaře a nic s tím nepůjde (bez rozbití odkazů) udělat. Pokud první segment cesty bude něco hodně specifického (`sraz-30let` asi splňuje), tak je malá šance, že to s něčím bude kolidovat a tedy že může vzniknout potřeba to přesouvat.)
A zároveň tím, že to bude mít v hlavních `urls.py` vynucený vlastní prefix cesty, tak bude zřejmé, odkud se to bere, narozdíl od includu na prázdnou cestu, ke kterým je netriviální dohledat URLconf záznam (a tedy tranzitivně i view).
¹Jo, jsem si vědom toho, že můžeš pak napsat `path('', include(…))` do aplikace pro výročí, ale to už je evidentní prasárna a nepůjde se v tom vyznat.
ledoian
commented
Možná napíšu patch, ono bude zřejmější, jak to myslím, v kódu a ne to tady rozepisovat (byť argumenty zůstanou tady…) Možná napíšu patch, ono bude zřejmější, jak to myslím, v kódu a ne to tady rozepisovat (byť argumenty zůstanou tady…)
ledoian
commented
!33
|
|||||||
|
org_required(VyrociListView.as_view()),
|
||||||
|
name='vyrocni_sraz_ucastnici'
|
||||||
|
),
|
||||||
|
]
|
36
vyroci/views.py
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
from django.views.generic import FormView, ListView
|
||||||
|
|
||||||
|
from seminar.models import Osoba
|
||||||
|
from seminar.views import formularOKView
|
||||||
|
from .forms import UcastnikVyrociForm
|
||||||
|
from .models import UcastnikVyroci
|
||||||
|
|
||||||
|
|
||||||
|
# Create your views here.
|
||||||
|
|
||||||
|
class VyrociView(FormView):
|
||||||
|
template_name = 'vyroci/vyroci.html'
|
||||||
|
form_class = UcastnikVyrociForm
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super().get_context_data(**kwargs)
|
||||||
|
context['ucastnici'] = UcastnikVyroci.objects.all()
|
||||||
|
return context
|
||||||
|
|
||||||
|
def form_valid(self, form):
|
||||||
|
form.save()
|
||||||
|
|
||||||
|
return formularOKView(self.request, "Úspěšně ses přihlásil na sraz")
|
||||||
zelvuska marked this conversation as resolved
Outdated
zelvuska
commented
„ses přihlásil na sraz“ „ses přihlásil na sraz“
|
|||||||
|
def get_initial(self):
|
||||||
|
initial = super().get_initial()
|
||||||
|
if self.request.user.is_authenticated:
|
||||||
|
osoba = Osoba.objects.filter(user=self.request.user).first()
|
||||||
|
if osoba is not None:
|
||||||
|
initial["jmeno"] = osoba.plne_jmeno()
|
||||||
|
initial["email"] = osoba.email
|
||||||
|
return initial
|
||||||
|
|
||||||
|
|
||||||
|
class VyrociListView(ListView):
|
||||||
|
template_name = 'vyroci/vyroci_list.html'
|
||||||
|
model = UcastnikVyroci
|
Nechceš tomu radši vyrobit složku? Přijde mi, že zrovna tohle nemusí úplně plevelit kořenovou cestu, když je to jednorázová akce prakticky bez jakýchkoliv dalších souvislostí. A klidně i jako
org-sraz
nebo dokoncesraz-30-let
, ať nám kdyžtak zbyde/sraz
na nějaké častější aktivity (resp. ať až se to zruší nevzniknou falešně oživené odkazy, které ale povedou někam jinam)