Merge branch 'master' into lineup_as_table

This commit is contained in:
2021-11-15 09:22:20 -06:00
29 changed files with 9808 additions and 210 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

View File

@@ -2,5 +2,5 @@ from django.http import HttpResponse
from django.shortcuts import render from django.shortcuts import render
def welcome(request): def welcome(request):
pages = ['schedule', 'teams list', 'venues list', 'players list'] pages = ['events list', 'teams list', 'venues list', 'players list']
return render(request,'home.html',{'pages':pages}) return render(request,'home.html',{'pages':pages})

View File

@@ -1,7 +1,7 @@
from django.contrib import admin from django.contrib import admin
from .models import Event, Availability from .models import Event
# Register your models here. # Register your models here.
admin.site.register(Event) admin.site.register(Event)
admin.site.register(Availability)

View File

@@ -0,0 +1,16 @@
# Generated by Django 3.2.6 on 2021-11-14 23:59
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('events', '0003_delete_positioning'),
]
operations = [
migrations.DeleteModel(
name='Availability',
),
]

View File

@@ -12,23 +12,5 @@ class Event(models.Model):
def __str__(self): def __str__(self):
return f"{self.start:%Y-%m-%d %H:%M}" return f"{self.start:%Y-%m-%d %H:%M}"
class Availability(models.Model):
event = models.ForeignKey(Event, on_delete=models.CASCADE)
player = models.ForeignKey(Player, on_delete=models.CASCADE)
choices = [
('Yes', 'YES'),
('No', 'NO'),
('Maybe', 'MAY'),
('Unknown', 'UNK')
]
available = models.CharField(choices=choices, default='UNK',max_length = 7)
def __str__(self):
return f"{self.event}; {self.player}; {self.available}"
class Meta:
unique_together = ('event', 'player',)
verbose_name_plural = "availabilities"
class Season(models.Model): class Season(models.Model):
name = models.CharField(max_length=50) name = models.CharField(max_length=50)

View File

@@ -1,16 +0,0 @@
{% extends 'base.html' %}{% block title %} {{ title }} {% endblock %}{% block content %}
<h1>{{ title }}</h1>
<ol class="list-group">
{% for event in events %}
<li class="list-group-item fs-6">
<span class="fs-5 fw-bold" style="text-transform: uppercase">{{ event.away_team.name }} vs. {{ event.home_team.name }}</span> <br>
{{ event.start|date:"l, F j, Y g:i A" }} <br>
{{ event.venue.name }} <br>
<a class="btn btn-primary btn-sm" href="{% url 'edit event' event.id%}" role="button">Edit Event Details</a>
<a class="btn btn-primary btn-sm" href="{% url 'edit lineup' event_id=event.id%}" role="button">Edit Lineup</a>
</li>
{% endfor %}
</ol>
{% endblock %}

View File

@@ -6,8 +6,7 @@ from . import views
urlpatterns = [ urlpatterns = [
path('', views.root, name="root"), path('', views.root, name="root"),
path('schedule', views.schedule, name="schedule"), path('list', views.EventsListView.as_view(), name="events list"),
path('edit/<int:id>', views.edit, name="edit event"), path('edit/<int:id>', views.EventEditView.as_view(), name="edit event"),
path('edit', views.edit, name="edit event"), path('edit', views.EventEditView.as_view(), name="edit event"),
path('edit', views.edit, name="edit event")
] ]

View File

@@ -1,43 +1,33 @@
from django.shortcuts import render, redirect, get_object_or_404 from django.shortcuts import render, redirect, get_object_or_404
from django.http import HttpResponse
from django.urls import reverse from django.urls import reverse
from .models import Event from .models import Event
from .forms import EventForm from .forms import EventForm
from django.http import HttpResponse from lib.views import BenchcoachListView, BenchcoachEditView
def root(request): def root(request):
return redirect('/events/schedule') return redirect(reverse('events list'))
def schedule(request): class EventsListView(BenchcoachListView):
events = Event.objects.all() Model = Event
return render(request, 'events/schedule.html', {'title':'Schedule', 'events': events}) edit_url = 'edit event'
list_url = 'events list'
page_title = "Events"
title_strf = '{item.away_team} vs. {item.home_team}'
body_strf = "{item.start:%a, %b %-d, %-I:%M %p},\n{item.venue}"
def edit(request, id=0): def get_context_data(self):
# if this is a POST request we need to process the form data context = super().get_context_data()
if request.method == 'POST': for item in context['items']:
# create a form instance and populate it with data from the request: item['buttons'].append(
if id: {
instance = get_object_or_404(Event, id=id) 'label': 'Edit Lineup',
form = EventForm(request.POST or None, instance=instance) 'href': reverse('edit lineup', args=[item['id']])
else: }
form = EventForm(request.POST or None) )
# check whether it's valid: return context
if form.is_valid():
# process the data in form.cleaned_data as required
# ...
# redirect to a new URL:
if id == 0: id = None
new_event, did_create = Event.objects.update_or_create(pk=id, defaults=form.cleaned_data)
return render(request, 'success.html', {'call_back':reverse('schedule'),'id':new_event.id}, status=201 if did_create else 200)
else:
return HttpResponse(status=400)
# if a GET (or any other method) we'll create a blank form class EventEditView(BenchcoachEditView):
else: Model = Event
if id: edit_url = 'edit event'
instance = get_object_or_404(Event, id=id) list_url = 'events list'
form = EventForm(request.POST or None, instance=instance) Form = EventForm
else:
form = EventForm
return render(request, 'edit.html', {'form': form, 'id': id, 'call_back': 'edit event'})

0
lib/__init__.py Normal file
View File

79
lib/views.py Normal file
View File

@@ -0,0 +1,79 @@
from django.shortcuts import render, redirect, get_object_or_404
from django.views import View
from django.views.generic.base import TemplateView
from django.forms.models import model_to_dict
from django import forms
from django.db import models
from django.http import HttpResponse, HttpResponseBadRequest
from django.urls import reverse
# from .models import Event
# from .forms import EventForm
from django.http import HttpResponse
class BenchcoachListView(TemplateView):
Model = models.Model
template_name = 'list.html'
edit_url = 'edit item'
list_url = 'items list'
template_name = 'list.html'
page_title = f"{Model.__name__}s"
title_strf = "{item}"
subtitle_strf = ""
body_strf = ""
def get_context_data(self):
items = self.Model.objects.all()
context = {
'title': self.page_title,
'items': [
{
'id': item.id,
'title': self.title_strf.format(item=item, **model_to_dict(item)),
'subtitle': self.subtitle_strf.format(item=item, **model_to_dict(item)),
'body': self.body_strf.format(item=item, **model_to_dict(item)),
'buttons': [
{
'label': 'Edit',
'href': reverse(self.edit_url, args=[item.id])
}
]
}
for item in items
]
}
return context
class BenchcoachEditView(TemplateView):
Form: forms.ModelForm = None
Model: models.Model = None
edit_url = 'edit item'
list_url = 'items list'
def post(self, request, *args, **kwargs):
id = kwargs.get('id')
# create a form instance and populate it with data from the request:
if id:
instance = get_object_or_404(self.Model, id=id)
form = self.Form(request.POST or None, instance=instance)
else:
form = self.Form(request.POST or None)
# check whether it's valid:
if form.is_valid():
# process the data in form.cleaned_data as required
# ...
# redirect to a new URL:
new_item, did_create = self.Model.objects.update_or_create(pk=id, defaults=form.cleaned_data)
return render(request, 'success.html', {'call_back_url': reverse(self.list_url), 'id': new_item.id},
status=201 if did_create else 200)
return HttpResponseBadRequest()
def get(self, request, *args, **kwargs):
pass
id = kwargs.get('id')
if id:
instance = get_object_or_404(self.Model, id=id)
form = self.Form(request.POST or None, instance=instance)
else:
form = self.Form
return render(request, 'edit.html', {'form': form, 'id': id, 'call_back': self.edit_url})

View File

@@ -1,3 +1,6 @@
from django.contrib import admin from django.contrib import admin
from .models import Availability, Positioning
# Register your models here. # Register your models here.
admin.site.register(Availability)
admin.site.register(Positioning)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,29 @@
# Generated by Django 3.2.6 on 2021-11-14 23:59
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('players', '0003_player_team'),
('events', '0004_delete_availability'),
('lineups', '0001_initial'),
]
operations = [
migrations.CreateModel(
name='Availability',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('available', models.IntegerField(choices=[(2, 'Yes'), (-1, 'No'), (1, 'MAY'), (0, 0)], default=0, max_length=7)),
('event', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='events.event')),
('player', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='players.player')),
],
options={
'verbose_name_plural': 'availabilities',
'unique_together': {('event', 'player')},
},
),
]

View File

@@ -0,0 +1,18 @@
# Generated by Django 3.2.6 on 2021-11-15 00:32
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('lineups', '0002_availability'),
]
operations = [
migrations.AlterField(
model_name='availability',
name='available',
field=models.IntegerField(choices=[(2, 'Yes'), (0, 'No'), (1, 'MAY'), (-1, 0)], default=-1),
),
]

View File

@@ -0,0 +1,18 @@
# Generated by Django 3.2.6 on 2021-11-15 00:40
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('lineups', '0003_alter_availability_available'),
]
operations = [
migrations.AlterField(
model_name='availability',
name='available',
field=models.IntegerField(choices=[(2, 'Yes'), (0, 'No'), (1, 'Maybe'), (-1, 'Unknown')], default=-1),
),
]

View File

@@ -24,3 +24,26 @@ class Positioning(models.Model):
class Meta: class Meta:
unique_together = ('player', 'event',) unique_together = ('player', 'event',)
class Availability(models.Model):
YES = 2
MAYBE = 1
NO = 0
UNKNOWN = -1
event = models.ForeignKey(Event, on_delete=models.CASCADE)
player = models.ForeignKey(Player, on_delete=models.CASCADE)
choices = [
(YES, 'Yes'),
(NO, 'No'),
(MAYBE, 'Maybe'),
(UNKNOWN, 'Unknown')
]
available = models.IntegerField(choices=choices, default=UNKNOWN)
def __str__(self):
return f"{self.event}; {self.player}; {self.available}"
class Meta:
unique_together = ('event', 'player',)
verbose_name_plural = "availabilities"

View File

@@ -7,7 +7,8 @@
{{ event.venue.name }} <br> {{ event.venue.name }} <br>
<div class="container"> <div class="container">
<div class="row"> <div class="row">
<div class="col-6"> <div class="col-md-6">
<h6>Lineup</h6>
{# <ul class="list-group">#} {# <ul class="list-group">#}
<form action="{% url 'edit lineup' event_id=event.id%}" method="post"> <form action="{% url 'edit lineup' event_id=event.id%}" method="post">
@@ -35,10 +36,23 @@
</form> </form>
</div> </div>
<div class="col-6"> <div class="col-md-6">
<h6>Players</h6>
<ul class="list-group"> <ul class="list-group">
{% for player in players %} {% for player in players %}
<li class="list-group-item">{{ player.first_name }} {{ player.last_name }}</li> <li class="list-group-item">
{% if player.availability.available == 2 %}
<img class="bg-success p-2 rounded-circle" width="5" height="5"><span class="visually-hidden">Yes</span></img>
{% elif player.availability.available == 1%}
<img class="bg-info p-2 rounded-circle" width="5" height="5"><span class="visually-hidden">Maybe</span></span>
{% elif player.availability.available == 0%}
<img class="bg-danger p-2 rounded-circle" width="5" height="5"><span class="visually-hidden">No</span></span>
{% elif player.availability.available == -1%}
<img class="bg-secondary p-2 rounded-circle" width="5" height="5"><span class="visually-hidden">Unknown</span></span>
{% endif %}
{{ player.first_name }} {{ player.last_name }}
<code><small>{{ player.statline }}</small></code>
</li>
{% endfor %} {% endfor %}
</ul> </ul>
</div> </div>

View File

@@ -1,11 +1,9 @@
from django.shortcuts import render, redirect, get_object_or_404 from django.shortcuts import render, redirect, get_object_or_404
from django.forms import formset_factory
from .models import Positioning from .models import Positioning
from .forms import PositioningFormSet from .forms import PositioningFormSet
from django.http import HttpResponse
from django import forms
from events.models import Event from events.models import Event
from players.models import Player from players.models import Player
from django.forms.models import model_to_dict
# Create your views here. # Create your views here.
def edit(request, event_id): def edit(request, event_id):
@@ -31,7 +29,17 @@ def edit(request, event_id):
return render(request, 'success.html', {'call_back':'edit lineup','id':event_id}, status=200) return render(request, 'success.html', {'call_back':'edit lineup','id':event_id}, status=200)
# return render(request, 'success.html', {'call_back':'schedule'}) # return render(request, 'success.html', {'call_back':'schedule'})
event = Event.objects.get(id=event_id) event = Event.objects.get(id=event_id)
players = Player.objects.all() players = Player.objects.all().prefetch_related('availability_set', 'statline_set')
players = [
{
**model_to_dict(player),
'availability':player.availability_set.get(event_id=event_id),
# 'available_value': player.availability_set.get(event_id=event_id).available,
'statline': player.statline_set.get(player_id=player.id)
}
for player in players
]
players.sort(key=lambda d: d['availability'].available, reverse = True)
qset = Positioning.objects.filter(event_id=event_id, order__isnull = False) qset = Positioning.objects.filter(event_id=event_id, order__isnull = False)
formset = PositioningFormSet(queryset=qset) formset = PositioningFormSet(queryset=qset)
for form in formset: for form in formset:

View File

@@ -223,5 +223,255 @@
"jersey_number": 45, "jersey_number": 45,
"last_name": "Kelly" "last_name": "Kelly"
} }
},
{
"model": "players.statline",
"pk": null,
"fields": {
"batting_avg": 0.417,
"onbase_pct": 0.488,
"player_id": 1,
"slugging_pct": 0.472
}
},
{
"model": "players.statline",
"pk": null,
"fields": {
"batting_avg": 0.422,
"onbase_pct": 0.518,
"player_id": 2,
"slugging_pct": 0.667
}
},
{
"model": "players.statline",
"pk": null,
"fields": {
"batting_avg": 0,
"onbase_pct": 0.2,
"player_id": 3,
"slugging_pct": 0
}
},
{
"model": "players.statline",
"pk": null,
"fields": {
"batting_avg": 0.061,
"onbase_pct": 0.233,
"player_id": 4,
"slugging_pct": 0.061
}
},
{
"model": "players.statline",
"pk": null,
"fields": {
"batting_avg": 0.282,
"onbase_pct": 0.338,
"player_id": 5,
"slugging_pct": 0.296
}
},
{
"model": "players.statline",
"pk": null,
"fields": {
"batting_avg": 0.267,
"onbase_pct": 0.333,
"player_id": 6,
"slugging_pct": 0.3
}
},
{
"model": "players.statline",
"pk": null,
"fields": {
"batting_avg": 0.214,
"onbase_pct": 0.235,
"player_id": 7,
"slugging_pct": 0.357
}
},
{
"model": "players.statline",
"pk": null,
"fields": {
"batting_avg": 0.219,
"onbase_pct": 0.324,
"player_id": 8,
"slugging_pct": 0.344
}
},
{
"model": "players.statline",
"pk": null,
"fields": {
"batting_avg": 0.28,
"onbase_pct": 0.28,
"player_id": 9,
"slugging_pct": 0.32
}
},
{
"model": "players.statline",
"pk": null,
"fields": {
"batting_avg": 0.333,
"onbase_pct": 0.424,
"player_id": 10,
"slugging_pct": 0.373
}
},
{
"model": "players.statline",
"pk": null,
"fields": {
"batting_avg": 0,
"onbase_pct": 0.25,
"player_id": 11,
"slugging_pct": 0
}
},
{
"model": "players.statline",
"pk": null,
"fields": {
"batting_avg": 0,
"onbase_pct": 0,
"player_id": 12,
"slugging_pct": 0
}
},
{
"model": "players.statline",
"pk": null,
"fields": {
"batting_avg": 0.379,
"onbase_pct": 0.379,
"player_id": 13,
"slugging_pct": 0.552
}
},
{
"model": "players.statline",
"pk": null,
"fields": {
"batting_avg": 0.095,
"onbase_pct": 0.174,
"player_id": 14,
"slugging_pct": 0.143
}
},
{
"model": "players.statline",
"pk": null,
"fields": {
"batting_avg": 0.41,
"onbase_pct": 0.486,
"player_id": 15,
"slugging_pct": 0.525
}
},
{
"model": "players.statline",
"pk": null,
"fields": {
"batting_avg": 0.357,
"onbase_pct": 0.406,
"player_id": 16,
"slugging_pct": 0.536
}
},
{
"model": "players.statline",
"pk": null,
"fields": {
"batting_avg": 0.185,
"onbase_pct": 0.312,
"player_id": 17,
"slugging_pct": 0.259
}
},
{
"model": "players.statline",
"pk": null,
"fields": {
"batting_avg": 0.299,
"onbase_pct": 0.378,
"player_id": 18,
"slugging_pct": 0.391
}
},
{
"model": "players.statline",
"pk": null,
"fields": {
"batting_avg": 0.438,
"onbase_pct": 0.571,
"player_id": 19,
"slugging_pct": 0.781
}
},
{
"model": "players.statline",
"pk": null,
"fields": {
"batting_avg": 0.333,
"onbase_pct": 0.417,
"player_id": 20,
"slugging_pct": 0.367
}
},
{
"model": "players.statline",
"pk": null,
"fields": {
"batting_avg": 0.333,
"onbase_pct": 0.41,
"player_id": 22,
"slugging_pct": 0.522
}
},
{
"model": "players.statline",
"pk": null,
"fields": {
"batting_avg": 0.062,
"onbase_pct": 0.211,
"player_id": 23,
"slugging_pct": 0.125
}
},
{
"model": "players.statline",
"pk": null,
"fields": {
"batting_avg": 0.5,
"onbase_pct": 0.611,
"player_id": 24,
"slugging_pct": 0.5
}
},
{
"model": "players.statline",
"pk": null,
"fields": {
"batting_avg": 0.25,
"onbase_pct": 0.25,
"player_id": 25,
"slugging_pct": 0.5
}
},
{
"model": "players.statline",
"pk": null,
"fields": {
"batting_avg": 0,
"onbase_pct": 0,
"player_id": 21,
"slugging_pct": 0
}
} }
] ]

View File

@@ -20,7 +20,7 @@ class StatLine(models.Model):
slugging_pct = models.DecimalField(max_digits=4, decimal_places=3, default=0) slugging_pct = models.DecimalField(max_digits=4, decimal_places=3, default=0)
def __str__(self): def __str__(self):
return f"{self.batting_avg}/{self.onbase_pct}/{self.slugging_pct}" return f"{self.slash_line}"
@property @property
def slash_line(self): def slash_line(self):

View File

@@ -1,10 +1,12 @@
from django.urls import path, include from django.urls import path, include
from .views import PlayerListView, PlayerEditView
from . import views from . import views
urlpatterns = [ urlpatterns = [
path('', views.root, name="root"), path('', views.root, name="root"),
path('list', views.list, name="players list"), path('list', PlayerListView.as_view(), name='players list'),
path('edit/<int:id>', views.edit, name="edit player"), path('edit/<int:id>', PlayerEditView.as_view(), name="edit player"),
path('edit', views.edit, name="edit player") path('edit', PlayerEditView.as_view(), name="edit player")
] ]

View File

@@ -1,48 +1,26 @@
from django.shortcuts import render, redirect, get_object_or_404 from django.shortcuts import render, redirect, get_object_or_404
from django.views.generic.list import ListView
from django.http import HttpResponse from django.http import HttpResponse
from django.urls import reverse from django.urls import reverse
from .models import Player from .models import Player
from .forms import PlayerForm from .forms import PlayerForm
from lib.views import BenchcoachListView, BenchcoachEditView
# Create your views here. # Create your views here.
class PlayerListView(BenchcoachListView):
Model = Player
edit_url = 'edit player'
list_url = 'players list'
page_title = "Players"
title_strf = "{first_name} {last_name}"
subtitle_strf = "#{jersey_number}"
def root(request): def root(request):
return redirect('/players/list') return redirect('/players/list')
def list(request): class PlayerEditView(BenchcoachEditView):
players = Player.objects.all() Form = PlayerForm
return render(request, 'list.html', {'title': "Players", Model = Player
'items': [ edit_url = 'edit player'
{'id':player.id, list_url = 'players list'
'title':f"{player.first_name} {player.last_name}",
'subtitle':f"{player.jersey_number}"
}
for player in players],
'edit_url_name': 'edit player'})
def edit(request, id=0):
# if this is a POST request we need to process the form data
if request.method == 'POST':
# create a form instance and populate it with data from the request:
if id:
instance = get_object_or_404(Player, id=id)
form = PlayerForm(request.POST or None, instance=instance)
else:
form = PlayerForm(request.POST or None)
# check whether it's valid:
if form.is_valid():
# process the data in form.cleaned_data as required
if id == 0: id = None
new_player, did_create = Player.objects.update_or_create(pk=id, defaults=form.cleaned_data)
return render(request, 'success.html', {'call_back':reverse('players list'),'id':new_player.id}, status=201 if did_create else 200)
else:
return HttpResponse(status=400)
# if a GET (or any other method) we'll create a blank form
else:
if id:
instance = get_object_or_404(Player, id=id)
form = PlayerForm(request.POST or None, instance=instance)
else:
form = PlayerForm
return render(request, 'edit.html', {'form': form, 'id': id, 'call_back':'edit player'})

19
requirements.txt Normal file
View File

@@ -0,0 +1,19 @@
asgiref==3.4.1
beautifulsoup4==4.9.3
certifi==2021.5.30
charset-normalizer==2.0.4
Django==3.2.6
idna==3.2
importlib-metadata==3.10.1
libsass==0.21.0
Pillow==8.3.1
PyYAML==6.0
requests==2.26.0
six==1.16.0
soupsieve==2.2.1
sqlparse==0.4.1
urllib3==1.26.6
zipp==3.5.0
django-bootstrap-v5==1.0.7
django-crispy-forms
psycopg2

View File

@@ -6,7 +6,7 @@ from . import views
urlpatterns = [ urlpatterns = [
path('', views.root, name="root"), path('', views.root, name="root"),
path('list', views.list, name="teams list"), path('list', views.TeamsListView.as_view(), name="teams list"),
path('edit/<int:id>', views.edit, name="edit team"), path('edit/<int:id>', views.TeamEditView.as_view(), name="edit team"),
path('edit', views.edit, name="edit team") path('edit', views.TeamEditView.as_view(), name="edit team")
] ]

View File

@@ -3,43 +3,19 @@ from django.http import HttpResponse
from django.urls import reverse from django.urls import reverse
from .forms import TeamForm from .forms import TeamForm
from .models import Team from .models import Team
from lib.views import BenchcoachListView, BenchcoachEditView
def root(request): def root(request):
return redirect('/teams/list') return redirect(reverse('teams list'))
def list(request): class TeamsListView(BenchcoachListView):
teams = Team.objects.all() Model = Team
return render(request, 'list.html', {'title': "Players", edit_url = 'edit team'
'items': [ list_url = 'teams list'
{'id':team.id, page_title = "Teams"
'title':f"{team.name}"
}
for team in teams],
'edit_url_name': 'edit team'})
def edit(request, id=0): class TeamEditView(BenchcoachEditView):
# if this is a POST request we need to process the form data Model = Team
if request.method == 'POST': edit_url = 'edit team'
# create a form instance and populate it with data from the request: list_url = 'teams list'
if id: Form = TeamForm
instance = get_object_or_404(Team, id=id)
form = TeamForm(request.POST or None, instance=instance)
else:
form = TeamForm(request.POST or None)
# check whether it's valid:
if form.is_valid():
# process the data in form.cleaned_data as required
# ...
# redirect to a new URL:
new_team, did_create = Team.objects.update_or_create(pk=id, defaults=form.cleaned_data)
return render(request, 'success.html', {'call_back_url':reverse('teams list'), 'id':new_team.id},status=201 if did_create else 200)
# if a GET (or any other method) we'll create a blank form
else:
if id:
instance = get_object_or_404(Team, id=id)
form = TeamForm(request.POST or None, instance=instance)
else:
form = TeamForm
return render(request, 'edit.html', {'form': form, 'id': id, 'call_back':'edit team'})

View File

@@ -8,19 +8,24 @@
{% bootstrap_css %} {% bootstrap_css %}
{% bootstrap_javascript %} {% bootstrap_javascript %}
<link rel='stylesheet' href="{% static 'base.css' %}"> <link rel='stylesheet' href="{% static 'base.css' %}">
<link rel="shortcut icon" type="image/png" href="{% static 'favicon.ico' %}">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="BenchCoach">
<meta name='viewport' content='viewport-fit=cover, width=device-width, initial-scale=1.0'>
<link rel="apple-touch-icon" href="{% static 'favicon.ico' %}">
</head> </head>
<body class="bg-light"> <body class="bg-light">
<nav class="navbar navbar-expand-md navbar-dark bg-dark fixed-top"> <nav class="navbar navbar-expand-md navbar-dark bg-dark fixed-top" style="padding-top: env(safe-area-inset-top);">
<div class="container-fluid"> <div class="container-fluid">
<a class="navbar-brand fw-bolder text-uppercase" href="{% url 'home' %}">⚾️ Bench Coach</a> <a class="navbar-brand fw-bolder text-uppercase" href="{% url 'home' %}">⚾️ Bench Coach</a>
<div class="collapse navbar-collapse"> <div class="collapse navbar-collapse">
<ul class="navbar-nav mr-auto"> <ul class="navbar-nav mr-auto">
<li> <li>
<a class="nav-link" href="{% url 'schedule' %}">Schedule</a> <a class="nav-link" href="{% url 'events list' %}">Events</a>
</li> </li>
<li class="nav-item"> <li class="nav-item">
<a class="nav-link" href="{% url 'players list' %}">Players</a> <a class="nav-link" href="{% url 'players list' %}">Players</a>

View File

@@ -7,9 +7,15 @@
<ol class="list-group"> <ol class="list-group">
{% for item in items %} {% for item in items %}
<li class="list-group-item"> <li class="list-group-item">
<span class="fs-5 fw-bold">{{ item.title }}</span> <span class="fs-6">{{ item.subtitle }}</span> <span class="fs-5 fw-bold">{{ item.title }}</span>
<span class="fs-6">{{ item.subtitle }}</span>
{% if item.body %}
<br><span class="fs-6">{{ item.body }}</span>
{% endif %}
<br> <br>
<a class="btn btn-primary btn-sm" href="{% url edit_url_name item.id%}" role="button">Edit</a> {% for button in item.buttons %}
<a class="btn btn-primary btn-sm" href="{{ button.href }}" role="button">{{ button.label }}</a>
{% endfor %}
</li> </li>
{% endfor %} {% endfor %}
</ol> </ol>

View File

@@ -4,7 +4,7 @@ from . import views
urlpatterns = [ urlpatterns = [
path('', views.root, name="root"), path('', views.root, name="root"),
path('list', views.list, name="venues list"), path('list', views.VenueListView.as_view(), name="venues list"),
path('edit/<int:id>', views.edit, name="edit venue"), path('edit/<int:id>', views.VenueEditView.as_view(), name="edit venue"),
path('edit', views.edit, name="edit venue") path('edit', views.VenueEditView.as_view(), name="edit venue")
] ]

View File

@@ -3,45 +3,19 @@ from django.http import HttpResponse, HttpResponseBadRequest
from django.urls import reverse from django.urls import reverse
from .models import Venue from .models import Venue
from .forms import VenueForm from .forms import VenueForm
from lib.views import BenchcoachListView, BenchcoachEditView
def root(request): def root(request):
return redirect('/venues/list') return redirect('/venues/list')
def list(request): class VenueListView(BenchcoachListView):
venues = Venue.objects.all() Model = Venue
return render(request, 'list.html', {'title': "Venues", edit_url = 'edit venue'
'items': [ list_url = 'venues list'
{'id':venue.id, page_title = "Venues"
'title':f"{venue.name}"
}
for venue in venues],
'edit_url_name': 'edit venue'})
class VenueEditView(BenchcoachEditView):
def edit(request, id=0): Model = Venue
# if this is a POST request we need to process the form data edit_url = 'edit venue'
if request.method == 'POST': list_url = 'venues list'
# create a form instance and populate it with data from the request: Form = VenueForm
if id:
instance = get_object_or_404(Venue, id=id)
form = VenueForm(request.POST or None, instance=instance)
else:
form = VenueForm(request.POST or None)
# check whether it's valid:
if form.is_valid():
# process the data in form.cleaned_data as required
# ...
# redirect to a new URL:
new_venue, did_create = Venue.objects.update_or_create(pk=id, defaults=form.cleaned_data)
return render(request, 'success.html', {'call_back_url':reverse('venues list'), 'id':new_venue.id}, status=201 if did_create else 200)
return HttpResponseBadRequest()
# if a GET (or any other method) we'll create a blank form
else:
if id:
instance = get_object_or_404(Venue, id=id)
form = VenueForm(request.POST or None, instance=instance)
else:
form = VenueForm
return render(request, 'edit.html', {'form': form, 'id': id, 'call_back': 'edit venue'})