2026-02-20 22:08:04 +01:00

124 lines
3.4 KiB
Markdown

# qualifiers-model
Erstellt und erweitert Django Models für das qualifiers-Modul (UEFA Qualifikationsturniere).
## Trigger
- Neue QNode, QMatch, QGame, QGrouping Models
- Model-Erweiterungen für Qualifiers
- "qualifiers model", "qnode", "qmatch", "qgame"
## Kontext
Das qualifiers-Modul verwaltet UEFA-Qualifikationsturniere mit folgender Hierarchie:
- **QPath** → QTier → QNode (Turnier-Struktur)
- **QNode** → QGrouping → QPosition (Gruppenbildung)
- **QNode** → QMatch → QGame (Spielpaarungen)
## Regeln
1. **Immer db_index für ForeignKeys setzen** wenn häufig gefiltert wird:
```python
scenario = models.ForeignKey('scheduler.Scenario', on_delete=models.CASCADE, db_index=True)
```
2. **Meta-Klasse mit indexes und constraints**:
```python
class Meta:
ordering = ['-tier__ypos', '-stage__xpos']
constraints = [
models.UniqueConstraint(fields=['name', 'scenario'], name='unique_qnode_name_scenario')
]
indexes = [
models.Index(fields=['scenario', 'tier', 'stage'], name='qnode_scenario_tier_stage_idx'),
]
```
3. **related_name konsistent benennen**:
- Plural für ForeignKey: `related_name='groupings'`
- Model-Name für M2M: `related_name='qnodes_seeded'`
4. **State-Machine Pattern für QNode**:
```python
NODESTATE_CHOICES = (
(0, "none"), # Warten auf Vorgänger
(1, "seeded"), # Teams zugeordnet
(2, "grouping"), # Gruppen gebildet
(3, "draw"), # Spiele ausgelost
(4, "finalized"), # Alle Ergebnisse da
)
```
5. **GameMixin für QGame verwenden**:
```python
from scheduler.models import GameMixin
class QGame(GameMixin):
# Erbt: homeGoals, awayGoals, resultEntered, season
qnode = models.ForeignKey(QNode, ...)
```
6. **Signals mit transaction.atomic()**:
```python
@receiver(post_save, sender=QGame)
def post_match_signal(sender, instance, created, **kwargs):
with transaction.atomic():
# Signal-Logik
```
## Beispiel: Neues Feld zu QNode
```python
# qualifiers/models.py
class QNode(models.Model):
# Existierende Felder...
# Neues Feld
auto_advance = models.BooleanField(
default=False,
help_text="Automatisch zum nächsten State wechseln"
)
```
## Beispiel: Neues Model
```python
# qualifiers/models.py
class QNodeViolation(models.Model):
"""Speichert Constraint-Verletzungen für einen Node."""
node = models.ForeignKey(
QNode,
on_delete=models.CASCADE,
related_name='violations',
db_index=True
)
scenario = models.ForeignKey(
'scheduler.Scenario',
on_delete=models.CASCADE,
db_index=True
)
type = models.CharField(max_length=50) # 'country_clash', 'distance', etc.
message = models.TextField()
severity = models.IntegerField(default=1) # 1=Warning, 2=Error
created_at = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ['-created_at']
indexes = [
models.Index(fields=['node', 'scenario'], name='qnodeviolation_node_scen_idx'),
]
```
## Migration erstellen
```bash
conda activate planner
python manage.py makemigrations qualifiers
python manage.py migrate qualifiers
```
## Referenz-Dateien
- [qualifiers/models.py](qualifiers/models.py) - Alle Models
- [docs/qualifiers/models/](docs/qualifiers/models/) - Dokumentation