add lineup entry (analogous to positioning)
This commit is contained in:
21
teamsnap/forms.py
Normal file
21
teamsnap/forms.py
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
from django import forms
|
||||||
|
from .models import LineupEntry
|
||||||
|
from events.models import Event
|
||||||
|
from players.models import Player
|
||||||
|
from django.forms import modelformset_factory, inlineformset_factory, BaseModelFormSet,formset_factory
|
||||||
|
from crispy_forms.helper import FormHelper, Layout
|
||||||
|
|
||||||
|
class LineupEntryForm(forms.ModelForm):
|
||||||
|
availability = None
|
||||||
|
class Meta:
|
||||||
|
model = LineupEntry
|
||||||
|
widgets = {
|
||||||
|
'label': forms.Select(attrs={'class': 'form-control form-control-sm'})
|
||||||
|
}
|
||||||
|
exclude = ()
|
||||||
|
|
||||||
|
LineupEntryFormSet = modelformset_factory(
|
||||||
|
model=LineupEntry,
|
||||||
|
form=LineupEntryForm,
|
||||||
|
extra=0
|
||||||
|
)
|
||||||
27
teamsnap/migrations/0011_lineupentry.py
Normal file
27
teamsnap/migrations/0011_lineupentry.py
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
# Generated by Django 3.2.6 on 2021-11-21 18:47
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('teamsnap', '0010_event_is_game'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='LineupEntry',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('label', models.PositiveSmallIntegerField(blank=True, choices=[(11, 'EH'), (1, 'P'), (2, 'C'), (3, '1B'), (4, '2B'), (5, '3B'), (6, 'SS'), (7, 'LF'), (8, 'CF'), (9, 'RF'), (10, 'DH')], default=None, null=True)),
|
||||||
|
('sequence', models.PositiveSmallIntegerField(default=0, null=True)),
|
||||||
|
('event', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='teamsnap.event')),
|
||||||
|
('member', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='teamsnap.member')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'unique_together': {('member', 'event')},
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
||||||
23
teamsnap/migrations/0012_auto_20211121_2010.py
Normal file
23
teamsnap/migrations/0012_auto_20211121_2010.py
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
# Generated by Django 3.2.6 on 2021-11-21 20:10
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('teamsnap', '0011_lineupentry'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='lineupentry',
|
||||||
|
name='name',
|
||||||
|
field=models.CharField(max_length=50, null=True),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='lineupentry',
|
||||||
|
name='teamsnap_id',
|
||||||
|
field=models.CharField(max_length=10, null=True, unique=True),
|
||||||
|
),
|
||||||
|
]
|
||||||
17
teamsnap/migrations/0013_remove_lineupentry_name.py
Normal file
17
teamsnap/migrations/0013_remove_lineupentry_name.py
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
# Generated by Django 3.2.6 on 2021-11-21 20:10
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('teamsnap', '0012_auto_20211121_2010'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='lineupentry',
|
||||||
|
name='name',
|
||||||
|
),
|
||||||
|
]
|
||||||
18
teamsnap/migrations/0014_alter_lineupentry_teamsnap_id.py
Normal file
18
teamsnap/migrations/0014_alter_lineupentry_teamsnap_id.py
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 3.2.6 on 2021-11-21 20:46
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('teamsnap', '0013_remove_lineupentry_name'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='lineupentry',
|
||||||
|
name='teamsnap_id',
|
||||||
|
field=models.CharField(blank=True, max_length=10, null=True, unique=True),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -106,4 +106,28 @@ class Availability(TeamsnapBaseModel):
|
|||||||
return f"{self.member} - {self.event} ({self.teamsnap_id})"
|
return f"{self.member} - {self.event} ({self.teamsnap_id})"
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name_plural = "availabilities"
|
verbose_name_plural = "availabilities"
|
||||||
|
|
||||||
|
class LineupEntry(TeamsnapBaseModel):
|
||||||
|
name = None
|
||||||
|
teamsnap_id = models.CharField(max_length=10, unique=True, null=True, blank=True)
|
||||||
|
member = models.ForeignKey(Member, on_delete=models.CASCADE)
|
||||||
|
event = models.ForeignKey(Event, on_delete=models.CASCADE)
|
||||||
|
positions = [
|
||||||
|
(11, 'EH'),
|
||||||
|
(1, 'P'),
|
||||||
|
(2, 'C'),
|
||||||
|
(3, '1B'),
|
||||||
|
(4, '2B'),
|
||||||
|
(5, '3B'),
|
||||||
|
(6, 'SS'),
|
||||||
|
(7, 'LF'),
|
||||||
|
(8, 'CF'),
|
||||||
|
(9, 'RF'),
|
||||||
|
(10,'DH')
|
||||||
|
]
|
||||||
|
label = models.PositiveSmallIntegerField(choices=positions, default=None, null=True, blank=True)
|
||||||
|
sequence = models.PositiveSmallIntegerField(default=0, null=True, blank=True)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
unique_together = ('member', 'event',)
|
||||||
|
|||||||
@@ -1,9 +1,19 @@
|
|||||||
from django.shortcuts import render, redirect
|
from django.shortcuts import render, redirect
|
||||||
|
|
||||||
# from .teamsnap.api import TeamSnap, Team, Event, Availability
|
# from .teamsnap.api import TeamSnap, Team, Event, Availability
|
||||||
from .models import User, Member, Team, Event, Location
|
from .models import User, Member, Team, Event, Location, LineupEntry
|
||||||
from django.views.generic.list import ListView
|
from django.views.generic.list import ListView
|
||||||
from lib.views import BenchcoachListView
|
from lib.views import BenchcoachListView
|
||||||
|
from .forms import LineupEntryForm, LineupEntryFormSet
|
||||||
|
from django.forms.models import model_to_dict
|
||||||
|
from django.urls import reverse
|
||||||
|
from django.db.models import Case, When
|
||||||
|
|
||||||
|
def queryset_from_ids(Model, id_list):
|
||||||
|
#https://stackoverflow.com/questions/4916851/django-get-a-queryset-from-array-of-ids-in-specific-order
|
||||||
|
preserved = Case(*[When(pk=pk, then=pos) for pos, pk in enumerate(id_list)])
|
||||||
|
queryset = Model.objects.filter(pk__in=id_list).order_by(preserved)
|
||||||
|
return queryset
|
||||||
|
|
||||||
def edit_event(request, id):
|
def edit_event(request, id):
|
||||||
event = Event.objects.get(id = id)
|
event = Event.objects.get(id = id)
|
||||||
@@ -17,19 +27,82 @@ class EventsListView(BenchcoachListView):
|
|||||||
title_strf = '{item.formatted_title}'
|
title_strf = '{item.formatted_title}'
|
||||||
body_strf = "{item.start_date:%a, %b %-d, %-I:%M %p},\n{item.location.name}"
|
body_strf = "{item.start_date:%a, %b %-d, %-I:%M %p},\n{item.location.name}"
|
||||||
|
|
||||||
# def get_context_data(self):
|
def get_context_data(self):
|
||||||
# context = super().get_context_data()
|
context = super().get_context_data()
|
||||||
# for item in context['items']:
|
for item in context['items']:
|
||||||
# item['buttons'].append(
|
item['buttons'].append(
|
||||||
# {
|
{
|
||||||
# 'label': 'Edit Lineup',
|
'label': 'Edit Lineup',
|
||||||
# 'href': reverse('edit lineup', args=[item['id']])
|
'href': reverse('teamsnap edit lineup', args=[item['id']])
|
||||||
# }
|
}
|
||||||
# )
|
)
|
||||||
# return context
|
return context
|
||||||
|
|
||||||
class TeamListView(ListView):
|
class TeamListView(BenchcoachListView):
|
||||||
model = Team
|
Model = Team
|
||||||
|
edit_url = 'teamsnap edit team'
|
||||||
|
list_url = 'teamsnap list teams'
|
||||||
|
page_title = "TeamSnap Teams"
|
||||||
|
|
||||||
class LocationListView(ListView):
|
class LocationListView(BenchcoachListView):
|
||||||
model = Location
|
Model = Location
|
||||||
|
edit_url = 'teamsnap edit location'
|
||||||
|
list_url = 'teamsnap list locations'
|
||||||
|
page_title = "TeamSnap Locations"
|
||||||
|
|
||||||
|
def edit_lineup(request, event_id):
|
||||||
|
|
||||||
|
if request.method == 'POST':
|
||||||
|
# create a form instance and populate it with data from the request:
|
||||||
|
formset = LineupEntryFormSet(request.POST)
|
||||||
|
for form in formset:
|
||||||
|
if form.is_valid():
|
||||||
|
# process the data in form.cleaned_data as required
|
||||||
|
# ...
|
||||||
|
# redirect to a new URL:
|
||||||
|
|
||||||
|
if isinstance(form.cleaned_data['id'], LineupEntry):
|
||||||
|
positioning_id = form.cleaned_data.pop('id').id #FIXME this is a workaround, not sure why it is necessary
|
||||||
|
positioning = LineupEntry.objects.filter(id=positioning_id)
|
||||||
|
positioning.update(**form.cleaned_data)
|
||||||
|
did_create = False
|
||||||
|
else:
|
||||||
|
positioning = LineupEntry.objects.create(**form.cleaned_data, event_id=event_id)
|
||||||
|
did_create = True
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
return render(request, 'success.html', {'call_back':'teamsnap edit lineup','id':event_id, 'errors':[error for error in formset.errors if error]}, status=200)
|
||||||
|
# return render(request, 'success.html', {'call_back':'schedule'})
|
||||||
|
event = Event.objects.get(id=event_id)
|
||||||
|
members = Member.objects.filter(is_non_player=False).prefetch_related('availability_set', 'lineupentry_set')
|
||||||
|
# players_d.sort(key=lambda d: (-d['availability'].available, d['last_name']))
|
||||||
|
|
||||||
|
for member in members:
|
||||||
|
LineupEntry.objects.get_or_create(member_id=member.id, event_id=event_id)
|
||||||
|
|
||||||
|
qs_starting_lineup = LineupEntry.objects.filter(event_id=event_id, sequence__isnull=False, sequence__gt=0).order_by('sequence')
|
||||||
|
qs_bench = LineupEntry.objects.filter(event_id=event_id, sequence=0).prefetch_related('member__availability_set').order_by('member__last_name')
|
||||||
|
|
||||||
|
# This is all a compromise to get the sorting just the way I wanted. THERE'S GOT TO BE A BETTER WAY
|
||||||
|
ids_starting_lineup = [item.id for item in qs_starting_lineup]
|
||||||
|
ids_bench_available = [item.id for item in qs_bench
|
||||||
|
if item.member.availability_set.get(event_id=event_id).status_code == 1]
|
||||||
|
ids_bench_maybe = [item.id for item in qs_bench
|
||||||
|
if item.member.availability_set.get(event_id=event_id).status_code == 2]
|
||||||
|
ids_bench_no = [item.id for item in qs_bench
|
||||||
|
if item.member.availability_set.get(event_id=event_id).status_code == 0]
|
||||||
|
ids_bench_unknown = [item.id for item in qs_bench
|
||||||
|
if item.member.availability_set.get(event_id=event_id).status_code is None]
|
||||||
|
qset = queryset_from_ids(LineupEntry, ids_starting_lineup + ids_bench_available + ids_bench_maybe + ids_bench_no + ids_bench_unknown)
|
||||||
|
|
||||||
|
formset = LineupEntryFormSet(queryset=qset)
|
||||||
|
|
||||||
|
for f in formset:
|
||||||
|
if f.instance.member_id:
|
||||||
|
f.availability = f.instance.member.availability_set.get(event_id=event_id)
|
||||||
|
# f.statline = f.instance.member.statline_set.get()
|
||||||
|
|
||||||
|
return render(request, 'teamsnap/lineup.html', {'title': 'Lineup',
|
||||||
|
'event': event,
|
||||||
|
'formset': formset,
|
||||||
|
})
|
||||||
Reference in New Issue
Block a user