From e2ad5676c7f6463f50691db9f4d77515547b17ea Mon Sep 17 00:00:00 2001 From: Corban-Lee <77944149+XordK@users.noreply.github.com> Date: Wed, 10 May 2023 00:58:38 +0100 Subject: [PATCH] Crude section/teams implementation do not merge to main, very buggy rough implementation of sorting between teams and sections. I have rewritten many areas. --- src/mainapp/admin.py | 32 +- src/mainapp/fixtures/members_fixture.json | 1032 +++++++++++++++-- src/mainapp/fixtures/teams_fixture.json | 54 +- .../commands/create_members_fixture.py | 44 +- src/mainapp/migrations/0001_initial.py | 9 +- ...eam_number_team_name_alter_section_name.py | 23 + src/mainapp/models.py | 159 ++- src/mainapp/templates/teams.html | 4 +- src/mainapp/urls.py | 2 +- src/mainapp/views.py | 44 +- src/static/js/teams.js | 40 +- 11 files changed, 1186 insertions(+), 257 deletions(-) create mode 100644 src/mainapp/migrations/0002_rename_team_number_team_name_alter_section_name.py diff --git a/src/mainapp/admin.py b/src/mainapp/admin.py index 045e89c..9ba3b88 100644 --- a/src/mainapp/admin.py +++ b/src/mainapp/admin.py @@ -2,17 +2,17 @@ from django.contrib import admin -from .models import Peg, Member, Team +from .models import Member, Team, Section -@admin.register(Peg) -class PegAdmin(admin.ModelAdmin): - """Admin model for the Peg model.""" +# @admin.register(Peg) +# class PegAdmin(admin.ModelAdmin): +# """Admin model for the Peg model.""" - change_list_template = "entities/bulk_pegging.html" - readonly_fields = ("peg_number",) - list_display = ("peg_number",) - search_fields = ("peg_number",) +# change_list_template = "entities/bulk_pegging.html" +# readonly_fields = ("peg_number",) +# list_display = ("peg_number",) +# search_fields = ("peg_number",) @admin.register(Member) @@ -28,14 +28,14 @@ class MemberAdmin(admin.ModelAdmin): class TeamAdmin(admin.ModelAdmin): """Admin model for the Team model.""" - readonly_fields = ("team_number",) - list_display = ("team_number",) - search_fields = ("team_number",) + readonly_fields = ("name",) + list_display = ("name",) + search_fields = ("name",) -# @admin.register(Section) -# class SectionAdmin(admin.ModelAdmin): -# """Admin model for the Section model.""" +@admin.register(Section) +class SectionAdmin(admin.ModelAdmin): + """Admin model for the Section model.""" -# list_display = ("character",) -# search_fields = ("character",) + list_display = ("name",) + search_fields = ("name",) diff --git a/src/mainapp/fixtures/members_fixture.json b/src/mainapp/fixtures/members_fixture.json index cd00fae..8c884d3 100644 --- a/src/mainapp/fixtures/members_fixture.json +++ b/src/mainapp/fixtures/members_fixture.json @@ -3,300 +3,1100 @@ "model": "mainapp.member", "pk": 1, "fields": { - "first_name": "Robert", - "last_name": "Reid", + "first_name": "Duane", + "last_name": "Bent", "team": 1, - "peg_number": null + "peg_number": null, + "section": "A" } }, { "model": "mainapp.member", "pk": 2, "fields": { - "first_name": "Ronald", - "last_name": "Jones", + "first_name": "Erwin", + "last_name": "Napier", "team": 1, - "peg_number": null + "peg_number": 1, + "section": "B" } }, { "model": "mainapp.member", "pk": 3, "fields": { - "first_name": "Casey", - "last_name": "Cohen", + "first_name": "Arthur", + "last_name": "Dillon", "team": 1, - "peg_number": null + "peg_number": 2, + "section": "C" } }, { "model": "mainapp.member", "pk": 4, "fields": { - "first_name": "James", - "last_name": "Scudder", - "team": 2, - "peg_number": null + "first_name": "William", + "last_name": "Hector", + "team": 1, + "peg_number": 3, + "section": "D" } }, { "model": "mainapp.member", "pk": 5, "fields": { - "first_name": "Randall", - "last_name": "Young", - "team": 2, - "peg_number": null + "first_name": "Warren", + "last_name": "Dixon", + "team": 1, + "peg_number": 4, + "section": "E" } }, { "model": "mainapp.member", "pk": 6, "fields": { - "first_name": "Helen", - "last_name": "Doak", - "team": 2, - "peg_number": null + "first_name": "Hallie", + "last_name": "Fountain", + "team": 1, + "peg_number": 5, + "section": "F" } }, { "model": "mainapp.member", "pk": 7, "fields": { - "first_name": "Brenda", - "last_name": "Powell", - "team": 3, - "peg_number": null + "first_name": "Hal", + "last_name": "Fisher", + "team": 1, + "peg_number": 6, + "section": "G" } }, { "model": "mainapp.member", "pk": 8, "fields": { - "first_name": "Constance", - "last_name": "Abild", - "team": 3, - "peg_number": null + "first_name": "Lamar", + "last_name": "Ferguson", + "team": 1, + "peg_number": 7, + "section": "H" } }, { "model": "mainapp.member", "pk": 9, "fields": { - "first_name": "Patsy", - "last_name": "Branham", - "team": 3, - "peg_number": null + "first_name": "Alix", + "last_name": "Campbell", + "team": 1, + "peg_number": 8, + "section": "I" } }, { "model": "mainapp.member", "pk": 10, "fields": { - "first_name": "Cheryl", - "last_name": "Sears", - "team": 4, - "peg_number": null + "first_name": "Jule", + "last_name": "Oleary", + "team": 1, + "peg_number": 9, + "section": "J" } }, { "model": "mainapp.member", "pk": 11, "fields": { - "first_name": "Justin", - "last_name": "Cramer", - "team": 4, - "peg_number": null + "first_name": "Dorothy", + "last_name": "Maginnis", + "team": 2, + "peg_number": 10, + "section": "K" } }, { "model": "mainapp.member", "pk": 12, "fields": { - "first_name": "Theodore", - "last_name": "Wilson", - "team": 4, - "peg_number": null + "first_name": "George", + "last_name": "Lofgren", + "team": 2, + "peg_number": 11, + "section": "L" } }, { "model": "mainapp.member", "pk": 13, "fields": { - "first_name": "Geneva", - "last_name": "Low", - "team": 5, - "peg_number": null + "first_name": "Evita", + "last_name": "Tolentino", + "team": 2, + "peg_number": 12, + "section": "M" } }, { "model": "mainapp.member", "pk": 14, "fields": { - "first_name": "John", - "last_name": "Burtt", - "team": 5, - "peg_number": null + "first_name": "David", + "last_name": "Bundy", + "team": 2, + "peg_number": 13, + "section": "N" } }, { "model": "mainapp.member", "pk": 15, "fields": { - "first_name": "Alfred", - "last_name": "Diaz", - "team": 5, - "peg_number": null + "first_name": "Ellen", + "last_name": "Ota", + "team": 2, + "peg_number": 14, + "section": "O" } }, { "model": "mainapp.member", "pk": 16, "fields": { - "first_name": "Arthur", - "last_name": "Alton", - "team": 6, - "peg_number": null + "first_name": "Vivian", + "last_name": "Myers", + "team": 2, + "peg_number": 15, + "section": "P" } }, { "model": "mainapp.member", "pk": 17, "fields": { - "first_name": "Vicki", - "last_name": "Greer", - "team": 6, - "peg_number": null + "first_name": "Brenda", + "last_name": "Getty", + "team": 2, + "peg_number": 16, + "section": "Q" } }, { "model": "mainapp.member", "pk": 18, "fields": { - "first_name": "Lewis", - "last_name": "Segovia", - "team": 6, - "peg_number": null + "first_name": "Charles", + "last_name": "Adams", + "team": 2, + "peg_number": 17, + "section": "R" } }, { "model": "mainapp.member", "pk": 19, "fields": { - "first_name": "Vince", - "last_name": "Robinson", - "team": 7, - "peg_number": null + "first_name": "Stephen", + "last_name": "Patterson", + "team": 2, + "peg_number": 18, + "section": "S" } }, { "model": "mainapp.member", "pk": 20, "fields": { - "first_name": "Blake", - "last_name": "Mueller", - "team": 7, - "peg_number": null + "first_name": "Christine", + "last_name": "Reynolds", + "team": 2, + "peg_number": 19, + "section": "T" } }, { "model": "mainapp.member", "pk": 21, "fields": { - "first_name": "Luis", - "last_name": "Hazel", - "team": 7, - "peg_number": null + "first_name": "Mary", + "last_name": "Baca", + "team": 3, + "peg_number": 20, + "section": "U" } }, { "model": "mainapp.member", "pk": 22, "fields": { - "first_name": "Diane", - "last_name": "Lloyd", - "team": 8, - "peg_number": null + "first_name": "Sandra", + "last_name": "Nunez", + "team": 3, + "peg_number": 21, + "section": "V" } }, { "model": "mainapp.member", "pk": 23, "fields": { - "first_name": "Jamey", - "last_name": "Mendes", - "team": 8, - "peg_number": null + "first_name": "Gina", + "last_name": "Jett", + "team": 3, + "peg_number": 22, + "section": "W" } }, { "model": "mainapp.member", "pk": 24, "fields": { - "first_name": "Virgilio", - "last_name": "Nixon", - "team": 8, - "peg_number": null + "first_name": "Jessica", + "last_name": "Bacot", + "team": 3, + "peg_number": 23, + "section": "X" } }, { "model": "mainapp.member", "pk": 25, "fields": { - "first_name": "Rodney", - "last_name": "White", - "team": 9, - "peg_number": null + "first_name": "Nancy", + "last_name": "Seifert", + "team": 3, + "peg_number": 24, + "section": "Y" } }, { "model": "mainapp.member", "pk": 26, "fields": { - "first_name": "Kathleen", - "last_name": "Ashe", - "team": 9, - "peg_number": null + "first_name": "Edith", + "last_name": "Roberts", + "team": 3, + "peg_number": 25, + "section": "Z" } }, { "model": "mainapp.member", "pk": 27, "fields": { - "first_name": "Stephanie", - "last_name": "Taylor", - "team": 9, - "peg_number": null + "first_name": "Jean", + "last_name": "Klein", + "team": 3, + "peg_number": 26, + "section": "ZA" } }, { "model": "mainapp.member", "pk": 28, "fields": { - "first_name": "John", - "last_name": "Brennan", - "team": 10, - "peg_number": null + "first_name": "Gertrude", + "last_name": "Young", + "team": 3, + "peg_number": 27, + "section": "ZB" } }, { "model": "mainapp.member", "pk": 29, "fields": { - "first_name": "Kenneth", - "last_name": "Duff", - "team": 10, - "peg_number": null + "first_name": "John", + "last_name": "Walker", + "team": 3, + "peg_number": 28, + "section": "ZC" } }, { "model": "mainapp.member", "pk": 30, "fields": { - "first_name": "Matthew", - "last_name": "Whitesell", + "first_name": "Jeanette", + "last_name": "Parker", + "team": 3, + "peg_number": 29, + "section": "ZD" + } + }, + { + "model": "mainapp.member", + "pk": 31, + "fields": { + "first_name": "Tracey", + "last_name": "Kilgore", + "team": 4, + "peg_number": 30, + "section": "ZE" + } + }, + { + "model": "mainapp.member", + "pk": 32, + "fields": { + "first_name": "Jeff", + "last_name": "Seigler", + "team": 4, + "peg_number": 31, + "section": "ZF" + } + }, + { + "model": "mainapp.member", + "pk": 33, + "fields": { + "first_name": "Victoria", + "last_name": "Callahan", + "team": 4, + "peg_number": 32, + "section": "ZG" + } + }, + { + "model": "mainapp.member", + "pk": 34, + "fields": { + "first_name": "Josie", + "last_name": "Davis", + "team": 4, + "peg_number": 33, + "section": "ZH" + } + }, + { + "model": "mainapp.member", + "pk": 35, + "fields": { + "first_name": "John", + "last_name": "Kissane", + "team": 4, + "peg_number": 34, + "section": "ZI" + } + }, + { + "model": "mainapp.member", + "pk": 36, + "fields": { + "first_name": "Dina", + "last_name": "Carney", + "team": 4, + "peg_number": 35, + "section": "ZJ" + } + }, + { + "model": "mainapp.member", + "pk": 37, + "fields": { + "first_name": "Miguel", + "last_name": "Young", + "team": 4, + "peg_number": 36, + "section": "ZK" + } + }, + { + "model": "mainapp.member", + "pk": 38, + "fields": { + "first_name": "Paulette", + "last_name": "Hartman", + "team": 4, + "peg_number": 37, + "section": "ZL" + } + }, + { + "model": "mainapp.member", + "pk": 39, + "fields": { + "first_name": "Donald", + "last_name": "Leblanc", + "team": 4, + "peg_number": 38, + "section": "ZM" + } + }, + { + "model": "mainapp.member", + "pk": 40, + "fields": { + "first_name": "Brian", + "last_name": "Diaz", + "team": 4, + "peg_number": 39, + "section": "ZN" + } + }, + { + "model": "mainapp.member", + "pk": 41, + "fields": { + "first_name": "Howard", + "last_name": "Kerr", + "team": 5, + "peg_number": 40, + "section": "ZO" + } + }, + { + "model": "mainapp.member", + "pk": 42, + "fields": { + "first_name": "Elsie", + "last_name": "Servais", + "team": 5, + "peg_number": 41, + "section": "ZP" + } + }, + { + "model": "mainapp.member", + "pk": 43, + "fields": { + "first_name": "Michael", + "last_name": "Golden", + "team": 5, + "peg_number": 42, + "section": "ZQ" + } + }, + { + "model": "mainapp.member", + "pk": 44, + "fields": { + "first_name": "Pedro", + "last_name": "Beyer", + "team": 5, + "peg_number": 43, + "section": "ZR" + } + }, + { + "model": "mainapp.member", + "pk": 45, + "fields": { + "first_name": "Barbara", + "last_name": "Vallejos", + "team": 5, + "peg_number": 44, + "section": "ZS" + } + }, + { + "model": "mainapp.member", + "pk": 46, + "fields": { + "first_name": "Kenneth", + "last_name": "Hartry", + "team": 5, + "peg_number": 45, + "section": "ZT" + } + }, + { + "model": "mainapp.member", + "pk": 47, + "fields": { + "first_name": "Sandra", + "last_name": "Harrison", + "team": 5, + "peg_number": 46, + "section": "ZU" + } + }, + { + "model": "mainapp.member", + "pk": 48, + "fields": { + "first_name": "Elizabeth", + "last_name": "Hwang", + "team": 5, + "peg_number": 47, + "section": "ZV" + } + }, + { + "model": "mainapp.member", + "pk": 49, + "fields": { + "first_name": "Francis", + "last_name": "Cain", + "team": 5, + "peg_number": 48, + "section": "ZW" + } + }, + { + "model": "mainapp.member", + "pk": 50, + "fields": { + "first_name": "Annie", + "last_name": "Potter", + "team": 5, + "peg_number": 49, + "section": "ZX" + } + }, + { + "model": "mainapp.member", + "pk": 51, + "fields": { + "first_name": "Dennis", + "last_name": "Raymond", + "team": 6, + "peg_number": 50, + "section": "ZY" + } + }, + { + "model": "mainapp.member", + "pk": 52, + "fields": { + "first_name": "Jeffrey", + "last_name": "Lytle", + "team": 6, + "peg_number": 51, + "section": "ZZ" + } + }, + { + "model": "mainapp.member", + "pk": 53, + "fields": { + "first_name": "Crystal", + "last_name": "Ware", + "team": 6, + "peg_number": 52, + "section": "ZZA" + } + }, + { + "model": "mainapp.member", + "pk": 54, + "fields": { + "first_name": "Marie", + "last_name": "Zeiler", + "team": 6, + "peg_number": 53, + "section": "ZZB" + } + }, + { + "model": "mainapp.member", + "pk": 55, + "fields": { + "first_name": "Dan", + "last_name": "Febres", + "team": 6, + "peg_number": 54, + "section": "ZZC" + } + }, + { + "model": "mainapp.member", + "pk": 56, + "fields": { + "first_name": "Edward", + "last_name": "Millard", + "team": 6, + "peg_number": 55, + "section": "ZZD" + } + }, + { + "model": "mainapp.member", + "pk": 57, + "fields": { + "first_name": "Duncan", + "last_name": "Preciado", + "team": 6, + "peg_number": 56, + "section": "ZZE" + } + }, + { + "model": "mainapp.member", + "pk": 58, + "fields": { + "first_name": "Ina", + "last_name": "Lara", + "team": 6, + "peg_number": 57, + "section": "ZZF" + } + }, + { + "model": "mainapp.member", + "pk": 59, + "fields": { + "first_name": "James", + "last_name": "Ortiz", + "team": 6, + "peg_number": 58, + "section": "ZZG" + } + }, + { + "model": "mainapp.member", + "pk": 60, + "fields": { + "first_name": "Tomoko", + "last_name": "Best", + "team": 6, + "peg_number": 59, + "section": "ZZH" + } + }, + { + "model": "mainapp.member", + "pk": 61, + "fields": { + "first_name": "James", + "last_name": "Ramerez", + "team": 7, + "peg_number": 60, + "section": "ZZI" + } + }, + { + "model": "mainapp.member", + "pk": 62, + "fields": { + "first_name": "Rebbeca", + "last_name": "Schultz", + "team": 7, + "peg_number": 61, + "section": "ZZJ" + } + }, + { + "model": "mainapp.member", + "pk": 63, + "fields": { + "first_name": "John", + "last_name": "Hogue", + "team": 7, + "peg_number": 62, + "section": "ZZK" + } + }, + { + "model": "mainapp.member", + "pk": 64, + "fields": { + "first_name": "Yessenia", + "last_name": "Garcia", + "team": 7, + "peg_number": 63, + "section": "ZZL" + } + }, + { + "model": "mainapp.member", + "pk": 65, + "fields": { + "first_name": "Elvira", + "last_name": "Lehnen", + "team": 7, + "peg_number": 64, + "section": "ZZM" + } + }, + { + "model": "mainapp.member", + "pk": 66, + "fields": { + "first_name": "Ernest", + "last_name": "Thomas", + "team": 7, + "peg_number": 65, + "section": "ZZN" + } + }, + { + "model": "mainapp.member", + "pk": 67, + "fields": { + "first_name": "Richard", + "last_name": "Bowman", + "team": 7, + "peg_number": 66, + "section": "ZZO" + } + }, + { + "model": "mainapp.member", + "pk": 68, + "fields": { + "first_name": "Lisa", + "last_name": "Gilmore", + "team": 7, + "peg_number": 67, + "section": "ZZP" + } + }, + { + "model": "mainapp.member", + "pk": 69, + "fields": { + "first_name": "Diane", + "last_name": "Coleman", + "team": 7, + "peg_number": 68, + "section": "ZZQ" + } + }, + { + "model": "mainapp.member", + "pk": 70, + "fields": { + "first_name": "Ellie", + "last_name": "Sheppard", + "team": 7, + "peg_number": 69, + "section": "ZZR" + } + }, + { + "model": "mainapp.member", + "pk": 71, + "fields": { + "first_name": "Michael", + "last_name": "Cruz", + "team": 8, + "peg_number": 70, + "section": "ZZS" + } + }, + { + "model": "mainapp.member", + "pk": 72, + "fields": { + "first_name": "Mary", + "last_name": "Nimmo", + "team": 8, + "peg_number": 71, + "section": "ZZT" + } + }, + { + "model": "mainapp.member", + "pk": 73, + "fields": { + "first_name": "James", + "last_name": "Davis", + "team": 8, + "peg_number": 72, + "section": "ZZU" + } + }, + { + "model": "mainapp.member", + "pk": 74, + "fields": { + "first_name": "Mary", + "last_name": "Holmes", + "team": 8, + "peg_number": 73, + "section": "ZZV" + } + }, + { + "model": "mainapp.member", + "pk": 75, + "fields": { + "first_name": "Ruby", + "last_name": "Rosario", + "team": 8, + "peg_number": 74, + "section": "ZZW" + } + }, + { + "model": "mainapp.member", + "pk": 76, + "fields": { + "first_name": "Brenda", + "last_name": "Mcclinton", + "team": 8, + "peg_number": 75, + "section": "ZZX" + } + }, + { + "model": "mainapp.member", + "pk": 77, + "fields": { + "first_name": "Gregory", + "last_name": "Looft", + "team": 8, + "peg_number": 76, + "section": "ZZY" + } + }, + { + "model": "mainapp.member", + "pk": 78, + "fields": { + "first_name": "Bertha", + "last_name": "Acevedo", + "team": 8, + "peg_number": 77, + "section": "ZZZ" + } + }, + { + "model": "mainapp.member", + "pk": 79, + "fields": { + "first_name": "Daniel", + "last_name": "Baldwin", + "team": 8, + "peg_number": 78, + "section": "ZZZA" + } + }, + { + "model": "mainapp.member", + "pk": 80, + "fields": { + "first_name": "Paulette", + "last_name": "Buxton", + "team": 8, + "peg_number": 79, + "section": "ZZZB" + } + }, + { + "model": "mainapp.member", + "pk": 81, + "fields": { + "first_name": "Ramona", + "last_name": "Ballard", + "team": 9, + "peg_number": 80, + "section": "ZZZC" + } + }, + { + "model": "mainapp.member", + "pk": 82, + "fields": { + "first_name": "James", + "last_name": "Martinez", + "team": 9, + "peg_number": 81, + "section": "ZZZD" + } + }, + { + "model": "mainapp.member", + "pk": 83, + "fields": { + "first_name": "Christopher", + "last_name": "Hill", + "team": 9, + "peg_number": 82, + "section": "ZZZE" + } + }, + { + "model": "mainapp.member", + "pk": 84, + "fields": { + "first_name": "Holly", + "last_name": "Parker", + "team": 9, + "peg_number": 83, + "section": "ZZZF" + } + }, + { + "model": "mainapp.member", + "pk": 85, + "fields": { + "first_name": "Laurie", + "last_name": "Hamburger", + "team": 9, + "peg_number": 84, + "section": "ZZZG" + } + }, + { + "model": "mainapp.member", + "pk": 86, + "fields": { + "first_name": "David", + "last_name": "Oldenkamp", + "team": 9, + "peg_number": 85, + "section": "ZZZH" + } + }, + { + "model": "mainapp.member", + "pk": 87, + "fields": { + "first_name": "Wallace", + "last_name": "Rolle", + "team": 9, + "peg_number": 86, + "section": "ZZZI" + } + }, + { + "model": "mainapp.member", + "pk": 88, + "fields": { + "first_name": "Janice", + "last_name": "Foster", + "team": 9, + "peg_number": 87, + "section": "ZZZJ" + } + }, + { + "model": "mainapp.member", + "pk": 89, + "fields": { + "first_name": "Victor", + "last_name": "Cothran", + "team": 9, + "peg_number": 88, + "section": "ZZZK" + } + }, + { + "model": "mainapp.member", + "pk": 90, + "fields": { + "first_name": "James", + "last_name": "Allen", + "team": 9, + "peg_number": 89, + "section": "ZZZL" + } + }, + { + "model": "mainapp.member", + "pk": 91, + "fields": { + "first_name": "Gordon", + "last_name": "Fultz", "team": 10, - "peg_number": null + "peg_number": 90, + "section": "ZZZM" + } + }, + { + "model": "mainapp.member", + "pk": 92, + "fields": { + "first_name": "Joel", + "last_name": "Martin", + "team": 10, + "peg_number": 91, + "section": "ZZZN" + } + }, + { + "model": "mainapp.member", + "pk": 93, + "fields": { + "first_name": "David", + "last_name": "Greenfield", + "team": 10, + "peg_number": 92, + "section": "ZZZO" + } + }, + { + "model": "mainapp.member", + "pk": 94, + "fields": { + "first_name": "Alfred", + "last_name": "Cable", + "team": 10, + "peg_number": 93, + "section": "ZZZP" + } + }, + { + "model": "mainapp.member", + "pk": 95, + "fields": { + "first_name": "Linda", + "last_name": "Mann", + "team": 10, + "peg_number": 94, + "section": "ZZZQ" + } + }, + { + "model": "mainapp.member", + "pk": 96, + "fields": { + "first_name": "Troy", + "last_name": "Alvardo", + "team": 10, + "peg_number": 95, + "section": "ZZZR" + } + }, + { + "model": "mainapp.member", + "pk": 97, + "fields": { + "first_name": "Joseph", + "last_name": "Douglas", + "team": 10, + "peg_number": 96, + "section": "ZZZS" + } + }, + { + "model": "mainapp.member", + "pk": 98, + "fields": { + "first_name": "William", + "last_name": "Randel", + "team": 10, + "peg_number": 97, + "section": "ZZZT" + } + }, + { + "model": "mainapp.member", + "pk": 99, + "fields": { + "first_name": "James", + "last_name": "Richardson", + "team": 10, + "peg_number": 98, + "section": "ZZZU" + } + }, + { + "model": "mainapp.member", + "pk": 100, + "fields": { + "first_name": "Bradley", + "last_name": "Suber", + "team": 10, + "peg_number": 99, + "section": "ZZZV" } } ] \ No newline at end of file diff --git a/src/mainapp/fixtures/teams_fixture.json b/src/mainapp/fixtures/teams_fixture.json index 65f6286..1c3ecb6 100644 --- a/src/mainapp/fixtures/teams_fixture.json +++ b/src/mainapp/fixtures/teams_fixture.json @@ -2,71 +2,71 @@ { "model": "mainapp.team", "pk": 1, - "fields": { - "section_letter": "D" - } - }, - { - "model": "mainapp.team", - "pk": 2, - "fields": { - "section_letter": "P" - } - }, - { - "model": "mainapp.team", - "pk": 3, - "fields": { - "section_letter": "L" - } - }, - { - "model": "mainapp.team", - "pk": 4, "fields": { "section_letter": "M" } }, + { + "model": "mainapp.team", + "pk": 2, + "fields": { + "section_letter": "K" + } + }, + { + "model": "mainapp.team", + "pk": 3, + "fields": { + "section_letter": "Q" + } + }, + { + "model": "mainapp.team", + "pk": 4, + "fields": { + "section_letter": "V" + } + }, { "model": "mainapp.team", "pk": 5, "fields": { - "section_letter": "Z" + "section_letter": "U" } }, { "model": "mainapp.team", "pk": 6, "fields": { - "section_letter": "Y" + "section_letter": "H" } }, { "model": "mainapp.team", "pk": 7, "fields": { - "section_letter": "J" + "section_letter": "A" } }, { "model": "mainapp.team", "pk": 8, "fields": { - "section_letter": "W" + "section_letter": "D" } }, { "model": "mainapp.team", "pk": 9, "fields": { - "section_letter": "T" + "section_letter": "P" } }, { "model": "mainapp.team", "pk": 10, "fields": { - "section_letter": "F" + "section_letter": "G" } } ] \ No newline at end of file diff --git a/src/mainapp/management/commands/create_members_fixture.py b/src/mainapp/management/commands/create_members_fixture.py index ebed5e8..9365430 100644 --- a/src/mainapp/management/commands/create_members_fixture.py +++ b/src/mainapp/management/commands/create_members_fixture.py @@ -1,12 +1,46 @@ -import random import names import json +from typing import Optional, List, Set +from string import ascii_uppercase + from django.core.management.base import BaseCommand -from mainapp.models import Member, Team + +from mainapp.models import Member, Team, SectionValidator # TODO: refactor this file like create_teams_fixtures.py + +# SECTION_LETTERS = ascii_uppercase + + +# def get_next_available_section(member: Member, section_validator: SectionValidator) -> Optional[str]: +# """Returns the next available section for a member.""" +# member_sections = member.sections.all().values_list('name', flat=True) +# used_sections = set(member_sections) + +# if not member_sections: +# return "A" + +# used_sections = sorted(used_sections) + +# last_section = member_sections[-1] +# last_section_index = SECTION_LETTERS.index(last_section) + +# for i in range(last_section_index + 1, len(SECTION_LETTERS)): +# section = SECTION_LETTERS[i] +# if section_validator.is_valid_section(section) and section not in used_sections: +# return section + +# for i in range(last_section_index - 1, -1, -1): +# section = SECTION_LETTERS[i] +# if section_validator.is_valid_section(section) and section not in used_sections: +# return section + +# return None + + + class Command(BaseCommand): help = "Creates a fixture with randomly generated Member objects" @@ -25,11 +59,9 @@ class Command(BaseCommand): for _ in range(num_members): first_name = names.get_first_name() last_name = names.get_last_name() - member = Member(first_name=first_name, last_name=last_name, team=team) + member = Member.objects.create(first_name=first_name, last_name=last_name, team=team) members.append(member) - Member.objects.bulk_create(members) - self.stdout.write(self.style.SUCCESS(f"Created {num_members} members.")) # create a members fixture file @@ -42,7 +74,7 @@ class Command(BaseCommand): "first_name": member.first_name, "last_name": member.last_name, "team": member.team_id, - "peg_number": member.peg_number + "peg_number": member.peg_number, } } members_fixture.append(member_fixture) diff --git a/src/mainapp/migrations/0001_initial.py b/src/mainapp/migrations/0001_initial.py index 6c3342c..54baf42 100644 --- a/src/mainapp/migrations/0001_initial.py +++ b/src/mainapp/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 4.1.5 on 2023-05-07 21:57 +# Generated by Django 4.1.5 on 2023-05-09 22:52 from django.db import migrations, models import django.db.models.deletion @@ -14,16 +14,16 @@ class Migration(migrations.Migration): operations = [ migrations.CreateModel( - name='Peg', + name='Section', fields=[ - ('peg_number', mainapp.models.ReusableAutoField(default=mainapp.models.ReusableAutoField.get_default, editable=False, primary_key=True, serialize=False)), + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(editable=False, max_length=3, unique=True)), ], ), migrations.CreateModel( name='Team', fields=[ ('team_number', mainapp.models.ReusableAutoField(default=mainapp.models.ReusableAutoField.get_default, editable=False, primary_key=True, serialize=False)), - ('section_letter', models.CharField(choices=[('A', 'A'), ('B', 'B'), ('C', 'C'), ('D', 'D'), ('E', 'E'), ('F', 'F'), ('G', 'G'), ('H', 'H'), ('I', 'I'), ('J', 'J'), ('K', 'K'), ('L', 'L'), ('M', 'M'), ('N', 'N'), ('O', 'O'), ('P', 'P'), ('Q', 'Q'), ('R', 'R'), ('S', 'S'), ('T', 'T'), ('U', 'U'), ('V', 'V'), ('W', 'W'), ('X', 'X'), ('Y', 'Y'), ('Z', 'Z')], max_length=1, unique=True)), ], ), migrations.CreateModel( @@ -33,6 +33,7 @@ class Migration(migrations.Migration): ('first_name', models.CharField(max_length=255)), ('last_name', models.CharField(max_length=255)), ('peg_number', models.PositiveIntegerField(null=True, unique=True)), + ('section', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='mainapp.section')), ('team', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='members', to='mainapp.team', validators=[mainapp.models.validate_team_size])), ], ), diff --git a/src/mainapp/migrations/0002_rename_team_number_team_name_alter_section_name.py b/src/mainapp/migrations/0002_rename_team_number_team_name_alter_section_name.py new file mode 100644 index 0000000..da157db --- /dev/null +++ b/src/mainapp/migrations/0002_rename_team_number_team_name_alter_section_name.py @@ -0,0 +1,23 @@ +# Generated by Django 4.1.5 on 2023-05-09 23:20 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('mainapp', '0001_initial'), + ] + + operations = [ + migrations.RenameField( + model_name='team', + old_name='team_number', + new_name='name', + ), + migrations.AlterField( + model_name='section', + name='name', + field=models.CharField(max_length=3, unique=True), + ), + ] diff --git a/src/mainapp/models.py b/src/mainapp/models.py index 89872aa..217dd03 100644 --- a/src/mainapp/models.py +++ b/src/mainapp/models.py @@ -31,13 +31,101 @@ class ReusableAutoField(models.PositiveIntegerField): return self.get_next_available_id(self.model) -class Peg(models.Model): - """Represents a person's peg""" +# class Peg(models.Model): +# """Represents a person's peg""" - peg_number = ReusableAutoField(primary_key=True, default=ReusableAutoField.get_default, editable=False) +# peg_number = ReusableAutoField(primary_key=True, default=ReusableAutoField.get_default, editable=False) - def __str__(self): - return f"Peg {self.peg_number}" +# def __str__(self): +# return f"Peg {self.peg_number}" + + +class SectionValidator: + """Validation class for the `section` field on the `member` model.""" + + def __init__(self, max_value="ZZZ"): + self.max_value = max_value.upper() + self.alphabet_size = ord("Z") - ord("A") + 1 + + def is_valid(self, section: str, team_sections: list[str]=None) -> bool: + """Returns boolean if the section passed is valid.""" + section = section.upper() + + if not self._is_alphanumeric(section): + return False + + if not self._is_in_alphabet(section[0]): + return False + + if not self._is_in_range(section): + return False + + if team_sections: + if not self._is_unique(section, team_sections): + return False + + if not self._is_not_adjacent(section, team_sections): + return False + + return True + + def _is_alphanumeric(self, section: str) -> bool: + """Returns boolean if all characters in the passed string are alphanumerical.""" + return all(c.isalnum() for c in section) + + def _is_in_alphabet(self, c) -> bool: + """Returns boolean if the passed character is alphabetical.""" + return "A" <= c <= "Z" + + def _is_in_range(self, section) -> bool: + """Returns boolean if the passed section less or equal to the max value.""" + section_value = self._section_value(section) + max_value = self._section_value(self.max_value) + + return section_value <= max_value + + def _is_unique(self, section, team_sections) -> bool: + """Returns boolean if the passed section is unique amongst `team_sections`.""" + return section not in team_sections + + def _is_not_adjacent(self, section, team_sections) -> bool: + """Returns boolean if the passed section is not adjacent to any `team_sections`.""" + for team_section in team_sections: + team_section_value = self._section_value(team_section) + section_value = self._section_value(section) + if abs(team_section_value - section_value) <= 1: + return False + + return True + + def _section_value(self, section): + """Returns the value of the passed section.""" + n = len(section) + value = sum((ord(c) - ord("A") + 1) * self.alphabet_size ** (n - i - 1) for i, c in enumerate(section)) + return value + + +class Section(models.Model): + """Represents a fishing area. Members can be assigned to a section, + but no 2 teammates can be in the same or adjacent section.""" + + name = models.CharField(max_length=3, unique=True, null=False) + + def clean(self): + super().clean() + + validator = SectionValidator(max_value="ZZZ") + if not validator.is_valid(self.name): + raise ValidationError("Invalid section value.") + + self.name = self.name.upper() + + def __str__(self) -> str: + return self.name + + @property + def members(self): + return Member.objects.filter(section=self) def validate_team_size(value): @@ -52,7 +140,7 @@ class Member(models.Model): last_name = models.CharField(max_length=255) team = models.ForeignKey("Team", on_delete=models.SET_NULL, null=True, blank=True, validators=(validate_team_size,), related_name='members') peg_number = models.PositiveIntegerField(null=True, editable=True, unique=True) - # peg = models.OneToOneField("Peg", on_delete=models.SET_NULL, null=True, blank=True) + section = models.ForeignKey(to=Section, on_delete=models.SET_NULL, null=True, swappable=True) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) @@ -65,6 +153,13 @@ class Member(models.Model): if peg_numbers: self.peg_number = min (peg_numbers) + # def clean(self): + # super().clean() + + # validator = SectionValidator(max_value="ZZZ") + # if not validator.is_valid(self.section): + # raise ValidationError("Invalid section value.") + def __str__(self): return f"{self.first_name} {self.last_name} (team {self.team.team_number}))" @@ -79,53 +174,25 @@ BLOCKED_SECTION_LETTERS = ["i"] # lowercase only, sections cannot be any of the class Team(models.Model): """Represents a team""" - team_number = ReusableAutoField(primary_key=True, default=ReusableAutoField.get_default, editable=False) - section_letter = models.CharField(max_length=1, unique=True, choices=[ - (char, char) for char in ascii_uppercase if char.lower() not in BLOCKED_SECTION_LETTERS - ]) + name = ReusableAutoField(primary_key=True, default=ReusableAutoField.get_default, editable=False) + # section_letter = models.CharField(max_length=1, unique=True, choices=[ + # (char, char) for char in ascii_uppercase if char.lower() not in BLOCKED_SECTION_LETTERS + # ]) def __str__(self): - return f"Team {self.team_number}" + return f"Team {self.name}" @property def members(self) -> list[Member]: - Member.objects.filter(team=self) + return Member.objects.filter(team=self) -def validate_section_character(value): - """Validates the section character""" +# def validate_section_character(value): +# """Validates the section character""" - value = value.upper() - banned_characters = ["I"] +# value = value.upper() +# banned_characters = ["I"] - if value in banned_characters: - raise ValidationError(f"The character <{value}> is a prohibited character.") +# if value in banned_characters: +# raise ValidationError(f"The character <{value}> is a prohibited character.") - -# class Section(models.Model): -# """Represents a section of the scoreboard""" - -# # character field stores a single character but doesnt allow for 'I' or 'i' -# character = models.CharField(primary_key=True, max_length=1, validators=(validate_section_character, )) - -# def clean(self): -# self.character = self.character.upper() - -# def __str__(self): -# return f"Section {self.character}" - - -#class Scoreboard(models.Model): -# class Status(models.IntegerChoices): -# ACTIVE = 1, "Active" -# INACTIVE = 2, "Inactive" -# ARCHIVED = 3, "Archived" -# -# name = models.CharField(max_length=255) -# category = models.CharField(max_length=255) -# price = models.DecimalField(max_digits=10, decimal_places=2) -# cost = models.DecimalField(max_digits=10, decimal_places=2) -# status = models.PositiveSmallIntegerField(choices=Status.choices) -# -# def __str__(self): -# return self.name \ No newline at end of file diff --git a/src/mainapp/templates/teams.html b/src/mainapp/templates/teams.html index f7cac51..ba0b33f 100644 --- a/src/mainapp/templates/teams.html +++ b/src/mainapp/templates/teams.html @@ -37,11 +37,11 @@