From c9aaf9511a280ee7fc4f8d476d1a9d8eea1aaa10 Mon Sep 17 00:00:00 2001 From: Corban-Lee <77944149+XordK@users.noreply.github.com> Date: Thu, 4 May 2023 21:10:56 +0100 Subject: [PATCH 01/39] removed ignore files from git cache --- .gitignore | 166 ++++++++++++++++++++++++++++++++++++++++++++++-- src/db.sqlite3 | Bin 188416 -> 0 bytes venv/pyvenv.cfg | 3 - 3 files changed, 159 insertions(+), 10 deletions(-) delete mode 100644 src/db.sqlite3 delete mode 100644 venv/pyvenv.cfg diff --git a/.gitignore b/.gitignore index af179e6..6769e21 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,160 @@ -/venv -venv +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/#use-with-ide +.pdm.toml + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ venv/ -pyvenv.cfg -*.pyc -venv/pyvenv.cfg -src/db.sqlite3 -*.sqlite3 +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ \ No newline at end of file diff --git a/src/db.sqlite3 b/src/db.sqlite3 deleted file mode 100644 index 3dd8573beffd308d1d6fbe8552a0b319bd8e8566..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 188416 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 f*Ch;#D#^mjJ(_VauhML2pmHdby-xmrn(H>G diff --git a/venv/pyvenv.cfg b/venv/pyvenv.cfg deleted file mode 100644 index 88e4dcd..0000000 --- a/venv/pyvenv.cfg +++ /dev/null @@ -1,3 +0,0 @@ -home = C:\Users\JamesParkin\AppData\Local\Programs\Python\Python310 -include-system-site-packages = false -version = 3.10.8 From 4d6bf1ff59770dd9151396ae700d452669c74938 Mon Sep 17 00:00:00 2001 From: Corban-Lee <77944149+XordK@users.noreply.github.com> Date: Thu, 4 May 2023 21:12:14 +0100 Subject: [PATCH 02/39] added launch file for debugging --- .vscode/launch.json | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 .vscode/launch.json diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..543a5ee --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,19 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Python: Django", + "type": "python", + "request": "launch", + "program": "${workspaceFolder}\\src\\manage.py", + "args": [ + "runserver" + ], + "django": true, + "justMyCode": true + } + ] +} \ No newline at end of file From 05efd3109ed5dc4bb6b3f5eca5fb157566dc24a1 Mon Sep 17 00:00:00 2001 From: Corban-Lee <77944149+XordK@users.noreply.github.com> Date: Thu, 4 May 2023 23:20:29 +0100 Subject: [PATCH 03/39] Rewrite for the templates + teams page demo Wrote a demo page as concept for the teams page. --- src/Results/settings.py | 2 +- src/mainapp/templates/index.html | 105 ++++++++++++-------------- src/mainapp/templates/results.html | 20 ++--- src/mainapp/templates/scoreboard.html | 56 +++----------- src/mainapp/templates/teams.html | 103 +++++++++++++++++++++++-- src/mainapp/urls.py | 7 +- src/mainapp/views.py | 18 ++++- src/static/css/custom.css | 12 +++ src/templates/base.html | 25 ++++++ 9 files changed, 223 insertions(+), 125 deletions(-) create mode 100644 src/static/css/custom.css create mode 100644 src/templates/base.html diff --git a/src/Results/settings.py b/src/Results/settings.py index 8f42a2e..744bb10 100644 --- a/src/Results/settings.py +++ b/src/Results/settings.py @@ -59,7 +59,7 @@ ROOT_URLCONF = 'Results.urls' TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': [BASE_DIR / 'mainapp/templates'], + 'DIRS': [BASE_DIR / 'templates'], 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ diff --git a/src/mainapp/templates/index.html b/src/mainapp/templates/index.html index f8ae29b..afeda4e 100644 --- a/src/mainapp/templates/index.html +++ b/src/mainapp/templates/index.html @@ -1,63 +1,56 @@ - - - - - - - - Home +{% extends "base.html" %} - - {% load static %} - - - - -
- -
-
-
-

Results System

-

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi faucibus elementum diam nec semper. Nullam vestibulum enim eu nisi condimentum, vitae suscipit risus imperdiet.

-
-
-
- -
-
-
-
- +{% block content %} +
+
+
+

Results System

+

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi faucibus elementum diam nec semper. Nullam vestibulum enim eu nisi condimentum, vitae suscipit risus imperdiet.

+
+
-
-
- - PlaceholderThumbnail -
-

Scoreboard

+
+{% endblock content %} diff --git a/src/mainapp/templates/results.html b/src/mainapp/templates/results.html index df6b355..4930318 100644 --- a/src/mainapp/templates/results.html +++ b/src/mainapp/templates/results.html @@ -1,9 +1,11 @@ - - - - - - - - Results - \ No newline at end of file +{% extends "base.html" %} + +{% block title %} + Results | +{% endblock title %} + +{% block content %} +
+ Back +
+{% endblock content %} \ No newline at end of file diff --git a/src/mainapp/templates/scoreboard.html b/src/mainapp/templates/scoreboard.html index b42968a..1979f8a 100644 --- a/src/mainapp/templates/scoreboard.html +++ b/src/mainapp/templates/scoreboard.html @@ -1,49 +1,11 @@ - - - - - - - - Scoreboard - +{% extends "base.html" %} - -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#FirstLastHandle
1MarkOtto@mdo
2JacobThornton@fat
3Larry the Bird@twitter
+{% block title %} + Scoreboard | +{% endblock title %} + +{% block content %} +
+ Back
-
- \ No newline at end of file +{% endblock content %} \ No newline at end of file diff --git a/src/mainapp/templates/teams.html b/src/mainapp/templates/teams.html index 3829af6..2bcfb1b 100644 --- a/src/mainapp/templates/teams.html +++ b/src/mainapp/templates/teams.html @@ -1,8 +1,95 @@ - - - - - - - - Teams \ No newline at end of file +{% extends "base.html" %} + +{% block title %} + Teams & Members | +{% endblock title %} + +{% block content %} +
+ Back +
+ +
+
+
+

Teams & their Members

+
+
+
+ + +
+
+
+ +
+ + {% for team in teams %} +
+
+

{{team.identifier}}

+
    + {% for member in team.members %} +
  • + + {{member.name}} + +
  • + {% endfor %} +
+
+
+ {% endfor %} + +
+
+ + + +{% endblock content %} + +{% block scripts %} + +{% endblock scripts %} \ No newline at end of file diff --git a/src/mainapp/urls.py b/src/mainapp/urls.py index 740b31d..050211d 100644 --- a/src/mainapp/urls.py +++ b/src/mainapp/urls.py @@ -3,8 +3,9 @@ from . import views urlpatterns = [ path('', views.index, name='index'), - path('results.html', views.results, name='results'), - path('scoreboard.html', views.scoreboard, name='scoreboard'), - path('teams.html', views.teams, name='teams'), + path('results/', views.results, name='results'), + path('scoreboard/', views.scoreboard, name='scoreboard'), + path('teams/', views.teams, name='teams'), + path('bulk-peg/', views.bulk_create_pegs, name='bulk-peg') ] \ No newline at end of file diff --git a/src/mainapp/views.py b/src/mainapp/views.py index b474308..843744d 100644 --- a/src/mainapp/views.py +++ b/src/mainapp/views.py @@ -1,3 +1,8 @@ +"""Views for the main app.""" + +from string import ascii_lowercase + +import names from django.shortcuts import render, redirect from .models import Peg @@ -12,7 +17,18 @@ def scoreboard(request): return render(request, 'scoreboard.html') def teams(request): - return render(request, 'teams.html') + + teams = [] + for char in ascii_lowercase: + teams.append({ + "identifier": char.upper(), + "members": [{ + "name": names.get_full_name() + } for i in range(9)] + }) + + context = {"teams": teams} + return render(request, 'teams.html', context=context) def bulk_create_pegs(request): """Bulk create pegs""" diff --git a/src/static/css/custom.css b/src/static/css/custom.css new file mode 100644 index 0000000..ad297c4 --- /dev/null +++ b/src/static/css/custom.css @@ -0,0 +1,12 @@ + +.ul-cols-2 { + column-count: 2; + column-gap: 20px; +} + +.ul-cols-2 li { + display: inline-block; + width: 100%; + box-sizing: border-box; + padding: 5px; +} diff --git a/src/templates/base.html b/src/templates/base.html new file mode 100644 index 0000000..be6504b --- /dev/null +++ b/src/templates/base.html @@ -0,0 +1,25 @@ + + + + + + {% block title %}{% endblock title %}AT Results + + {% load static %} + + + + + {% block style %} + {% endblock style %} + + + {% block content %} + {% endblock content %} + + + + {% block scripts %} + {% endblock scripts %} + + \ No newline at end of file From 0f1c839daa92be4e2f691a9831ea193e2a4061ea Mon Sep 17 00:00:00 2001 From: Corban-Lee <77944149+XordK@users.noreply.github.com> Date: Fri, 5 May 2023 00:24:10 +0100 Subject: [PATCH 04/39] Added live search to teams demo page Live search using ajax --- src/mainapp/teams_demo_test.py | 11 +++++ src/mainapp/templates/teams.html | 75 +++++++++++++++++++++++--------- src/mainapp/urls.py | 3 +- src/mainapp/views.py | 34 +++++++++------ 4 files changed, 88 insertions(+), 35 deletions(-) create mode 100644 src/mainapp/teams_demo_test.py diff --git a/src/mainapp/teams_demo_test.py b/src/mainapp/teams_demo_test.py new file mode 100644 index 0000000..0f95ba5 --- /dev/null +++ b/src/mainapp/teams_demo_test.py @@ -0,0 +1,11 @@ +import names +from string import ascii_lowercase + +created_teams = [] +for char in ascii_lowercase: + created_teams.append({ + "identifier": char.upper(), + "members": [{ + "name": names.get_full_name() + } for i in range(9)] + }) diff --git a/src/mainapp/templates/teams.html b/src/mainapp/templates/teams.html index 2bcfb1b..97ce908 100644 --- a/src/mainapp/templates/teams.html +++ b/src/mainapp/templates/teams.html @@ -16,32 +16,13 @@
- +
-
- - {% for team in teams %} -
-
-

{{team.identifier}}

-
    - {% for member in team.members %} -
  • - - {{member.name}} - -
  • - {% endfor %} -
-
-
- {% endfor %} - -
+
@@ -79,6 +60,58 @@ {% block scripts %} {% endblock scripts %} \ No newline at end of file diff --git a/src/mainapp/urls.py b/src/mainapp/urls.py index 9be72d3..5cef79f 100644 --- a/src/mainapp/urls.py +++ b/src/mainapp/urls.py @@ -9,4 +9,5 @@ urlpatterns = [ path('bulk-peg/', views.bulk_create_pegs, name='bulk-peg'), path('get-teams/', views.get_teams, name='get-teams'), + path('update-member/', views.update_member, name='update-member') ] \ No newline at end of file diff --git a/src/mainapp/views.py b/src/mainapp/views.py index a949dd7..04fe6a3 100644 --- a/src/mainapp/views.py +++ b/src/mainapp/views.py @@ -1,11 +1,13 @@ """Views for the main app.""" -from string import ascii_lowercase +from functools import reduce from django.shortcuts import render, redirect from django.http import JsonResponse +from django.db.models import Q + +from .models import Peg, Team, Member -from .models import Peg def index(request): return render(request, 'index.html') @@ -30,39 +32,69 @@ def bulk_create_pegs(request): return redirect(request.META.get('HTTP_REFERER')) def get_teams(request): - """Returns list of teams.""" + """Returns a JsonResponse containing a dictionary with a k/v pair for a list of teams. + + Args: + request: the web request object. + Returns: + JsonResponse: dictionary of teams like so {'teams': [{}, {}, {}]}. + """ if not request.POST: return search = request.POST.get("search") + teams = Team.objects.order_by("team_number").all() - from .teams_demo_test import created_teams - + # Filter out teams that don't contain members being searched for if search: - unfiltered_teams = created_teams.copy() - created_teams = [ - team for team in unfiltered_teams - if any( - search.lower() in name for name in - [member["name"].lower() for member in team["members"]] + search_terms = search.split() + members = Member.objects.filter( + reduce( + lambda x, y: x | y, + [ + Q(first_name__icontains=term) | Q(last_name__icontains=term) + for term in search_terms + ] ) - ] + ) + teams = teams.filter(members__in=members) - created_teams.sort(reverse=False, key=lambda team: team["identifier"]) - return JsonResponse({"teams": created_teams}) + # Create a dictionary for the data that is JSON safe + response_data = {"teams": []} + for team in teams: + team_data = { + "team_number": team.team_number, + "section": team.section.name if team.section else None, + "members": [ + {"first": member.first_name, "last": member.last_name, "id": member.id, "team": team.team_number} + for member in team.members.all() + ] + } + response_data["teams"].append(team_data) - # if not search: - # created_teams.sort(reverse=False, key=lambda team: team["identifier"]) - # return JsonResponse({"teams": created_teams}) + return JsonResponse(response_data) - # # Create a new list only containing teams that meet the search criteria - # filtered_teams = [] - # for team in created_teams: - # member_names = [member["name"].lower() for member in team["members"]] - # if any(search.lower() in name for name in member_names): - # filtered_teams.append(team) +def update_member(request): + """Update a member. Returns a JsonResponse with the updated teams.""" - # filtered_teams.sort(reverse=False, key=lambda team: team["identifier"]) + if not request.POST: + return - # return JsonResponse({"teams": filtered_teams}) + # Get the updated values + member_id = request.POST.get("memberId") + first = request.POST.get("first") + last = request.POST.get("last") + team_number = request.POST.get("teamNumber") + + # Get the member and team + member = Member.objects.get(id=member_id) + team = Team.objects.get(team_number=team_number) + + # Update the member + member.first_name = first + member.last_name = last + member.team = team + member.save() + + return get_teams(request) From 77b8c2fc2d3f67ec154e9706174760c987215d0d Mon Sep 17 00:00:00 2001 From: Corban-Lee <77944149+XordK@users.noreply.github.com> Date: Sun, 7 May 2023 23:20:34 +0100 Subject: [PATCH 08/39] Finalisation of teams/member model. Added testing script. --- create_dummy_data.bat | 23 ++ src/mainapp/admin.py | 12 +- src/mainapp/fixtures/members_fixture.json | 302 ++++++++++++++++++ src/mainapp/fixtures/teams_fixture.json | 72 +++++ .../commands/create_members_fixture.py | 22 +- .../commands/create_teams_fixture.py | 66 ++-- src/mainapp/migrations/0001_initial.py | 13 +- src/mainapp/models.py | 40 ++- src/mainapp/templates/teams.html | 181 +---------- src/mainapp/views.py | 16 +- src/static/js/teams.js | 193 +++++++++++ 11 files changed, 696 insertions(+), 244 deletions(-) create mode 100644 create_dummy_data.bat create mode 100644 src/mainapp/fixtures/members_fixture.json create mode 100644 src/mainapp/fixtures/teams_fixture.json create mode 100644 src/static/js/teams.js diff --git a/create_dummy_data.bat b/create_dummy_data.bat new file mode 100644 index 0000000..707f121 --- /dev/null +++ b/create_dummy_data.bat @@ -0,0 +1,23 @@ +@echo off +echo The purpose of this file is to populate the database with dummy data for testing. +set /p confirm=Do you want to continue? [y/n] + +if /i "%confirm%"=="y" ( + cd /d %~dp0 + + if exist src\db.sqlite3 ( + del src\db.sqlite3 + ) + + call venv\Scripts\activate.bat + + python src/manage.py migrate + python src/manage.py create_teams_fixture 10 + python src/manage.py loaddata teams_fixture + python src/manage.py create_members_fixture 3 + python src/manage.py loaddata members_fixture + + deactivate +) else ( + echo Exiting script... +) diff --git a/src/mainapp/admin.py b/src/mainapp/admin.py index 7a9093b..045e89c 100644 --- a/src/mainapp/admin.py +++ b/src/mainapp/admin.py @@ -2,7 +2,7 @@ from django.contrib import admin -from .models import Peg, Member, Team, Section +from .models import Peg, Member, Team @admin.register(Peg) @@ -33,9 +33,9 @@ class TeamAdmin(admin.ModelAdmin): search_fields = ("team_number",) -@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 = ("character",) +# search_fields = ("character",) diff --git a/src/mainapp/fixtures/members_fixture.json b/src/mainapp/fixtures/members_fixture.json new file mode 100644 index 0000000..776e9a9 --- /dev/null +++ b/src/mainapp/fixtures/members_fixture.json @@ -0,0 +1,302 @@ +[ + { + "model": "mainapp.member", + "pk": 1, + "fields": { + "first_name": "Michael", + "last_name": "Jewett", + "team": 1, + "peg_number": null + } + }, + { + "model": "mainapp.member", + "pk": 2, + "fields": { + "first_name": "Robert", + "last_name": "Kearns", + "team": 1, + "peg_number": null + } + }, + { + "model": "mainapp.member", + "pk": 3, + "fields": { + "first_name": "Jack", + "last_name": "Colon", + "team": 1, + "peg_number": null + } + }, + { + "model": "mainapp.member", + "pk": 4, + "fields": { + "first_name": "Nina", + "last_name": "Freeman", + "team": 2, + "peg_number": null + } + }, + { + "model": "mainapp.member", + "pk": 5, + "fields": { + "first_name": "Josephine", + "last_name": "Mcdonald", + "team": 2, + "peg_number": null + } + }, + { + "model": "mainapp.member", + "pk": 6, + "fields": { + "first_name": "Don", + "last_name": "Wrape", + "team": 2, + "peg_number": null + } + }, + { + "model": "mainapp.member", + "pk": 7, + "fields": { + "first_name": "Audrey", + "last_name": "Mcguire", + "team": 3, + "peg_number": null + } + }, + { + "model": "mainapp.member", + "pk": 8, + "fields": { + "first_name": "Morris", + "last_name": "Delker", + "team": 3, + "peg_number": null + } + }, + { + "model": "mainapp.member", + "pk": 9, + "fields": { + "first_name": "Keith", + "last_name": "Cline", + "team": 3, + "peg_number": null + } + }, + { + "model": "mainapp.member", + "pk": 10, + "fields": { + "first_name": "Vincent", + "last_name": "Alconcel", + "team": 4, + "peg_number": null + } + }, + { + "model": "mainapp.member", + "pk": 11, + "fields": { + "first_name": "Leroy", + "last_name": "Gibson", + "team": 4, + "peg_number": null + } + }, + { + "model": "mainapp.member", + "pk": 12, + "fields": { + "first_name": "Ronald", + "last_name": "Ross", + "team": 4, + "peg_number": null + } + }, + { + "model": "mainapp.member", + "pk": 13, + "fields": { + "first_name": "Dennis", + "last_name": "Thompson", + "team": 5, + "peg_number": null + } + }, + { + "model": "mainapp.member", + "pk": 14, + "fields": { + "first_name": "Clarence", + "last_name": "Nieto", + "team": 5, + "peg_number": null + } + }, + { + "model": "mainapp.member", + "pk": 15, + "fields": { + "first_name": "Trena", + "last_name": "Robbins", + "team": 5, + "peg_number": null + } + }, + { + "model": "mainapp.member", + "pk": 16, + "fields": { + "first_name": "Karen", + "last_name": "Vessell", + "team": 6, + "peg_number": null + } + }, + { + "model": "mainapp.member", + "pk": 17, + "fields": { + "first_name": "Herb", + "last_name": "Mcgowan", + "team": 6, + "peg_number": null + } + }, + { + "model": "mainapp.member", + "pk": 18, + "fields": { + "first_name": "Jimmie", + "last_name": "Rittenhouse", + "team": 6, + "peg_number": null + } + }, + { + "model": "mainapp.member", + "pk": 19, + "fields": { + "first_name": "Lewis", + "last_name": "Queener", + "team": 7, + "peg_number": null + } + }, + { + "model": "mainapp.member", + "pk": 20, + "fields": { + "first_name": "Nancy", + "last_name": "Merritt", + "team": 7, + "peg_number": null + } + }, + { + "model": "mainapp.member", + "pk": 21, + "fields": { + "first_name": "Elaine", + "last_name": "Foss", + "team": 7, + "peg_number": null + } + }, + { + "model": "mainapp.member", + "pk": 22, + "fields": { + "first_name": "Natasha", + "last_name": "Perkins", + "team": 8, + "peg_number": null + } + }, + { + "model": "mainapp.member", + "pk": 23, + "fields": { + "first_name": "Dean", + "last_name": "Carroll", + "team": 8, + "peg_number": null + } + }, + { + "model": "mainapp.member", + "pk": 24, + "fields": { + "first_name": "Lauren", + "last_name": "Carter", + "team": 8, + "peg_number": null + } + }, + { + "model": "mainapp.member", + "pk": 25, + "fields": { + "first_name": "Robert", + "last_name": "Orr", + "team": 9, + "peg_number": null + } + }, + { + "model": "mainapp.member", + "pk": 26, + "fields": { + "first_name": "Deborah", + "last_name": "Johnson", + "team": 9, + "peg_number": null + } + }, + { + "model": "mainapp.member", + "pk": 27, + "fields": { + "first_name": "Helen", + "last_name": "Henry", + "team": 9, + "peg_number": null + } + }, + { + "model": "mainapp.member", + "pk": 28, + "fields": { + "first_name": "Linda", + "last_name": "Armstrong", + "team": 10, + "peg_number": null + } + }, + { + "model": "mainapp.member", + "pk": 29, + "fields": { + "first_name": "Tricia", + "last_name": "Charles", + "team": 10, + "peg_number": null + } + }, + { + "model": "mainapp.member", + "pk": 30, + "fields": { + "first_name": "Cortney", + "last_name": "Hogan", + "team": 10, + "peg_number": null + } + } +] \ No newline at end of file diff --git a/src/mainapp/fixtures/teams_fixture.json b/src/mainapp/fixtures/teams_fixture.json new file mode 100644 index 0000000..f2de973 --- /dev/null +++ b/src/mainapp/fixtures/teams_fixture.json @@ -0,0 +1,72 @@ +[ + { + "model": "mainapp.team", + "pk": 1, + "fields": { + "section_letter": "A" + } + }, + { + "model": "mainapp.team", + "pk": 2, + "fields": { + "section_letter": "B" + } + }, + { + "model": "mainapp.team", + "pk": 3, + "fields": { + "section_letter": "C" + } + }, + { + "model": "mainapp.team", + "pk": 4, + "fields": { + "section_letter": "D" + } + }, + { + "model": "mainapp.team", + "pk": 5, + "fields": { + "section_letter": "E" + } + }, + { + "model": "mainapp.team", + "pk": 6, + "fields": { + "section_letter": "F" + } + }, + { + "model": "mainapp.team", + "pk": 7, + "fields": { + "section_letter": "G" + } + }, + { + "model": "mainapp.team", + "pk": 8, + "fields": { + "section_letter": "H" + } + }, + { + "model": "mainapp.team", + "pk": 9, + "fields": { + "section_letter": "J" + } + }, + { + "model": "mainapp.team", + "pk": 10, + "fields": { + "section_letter": "K" + } + } +] \ 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 351cdf1..39c9812 100644 --- a/src/mainapp/management/commands/create_members_fixture.py +++ b/src/mainapp/management/commands/create_members_fixture.py @@ -30,25 +30,6 @@ class Command(BaseCommand): self.stdout.write(self.style.SUCCESS(f"Created {num_members} members.")) - - # create a team fixture file - teams_fixture = [] - for team in teams: - team_fixture = { - "model": "mainapp.team", - "pk": team.pk, - "fields": { - "team_number": team.team_number, - "section": team.section_id - } - } - teams_fixture.append(team_fixture) - - with open("src/mainapp/fixtures/teams_fixture.json", "w") as f: - f.write(json.dumps(teams_fixture, indent=2)) - self.stdout.write(self.style.SUCCESS("Created teams_fixture.json.")) - - # create a members fixture file members_fixture = [] for member in members: @@ -58,7 +39,8 @@ class Command(BaseCommand): "fields": { "first_name": member.first_name, "last_name": member.last_name, - "team": member.team_id + "team": member.team_id, + "peg_number": member.peg_number } } members_fixture.append(member_fixture) diff --git a/src/mainapp/management/commands/create_teams_fixture.py b/src/mainapp/management/commands/create_teams_fixture.py index 1211396..64da24b 100644 --- a/src/mainapp/management/commands/create_teams_fixture.py +++ b/src/mainapp/management/commands/create_teams_fixture.py @@ -1,6 +1,13 @@ +import json +from string import ascii_uppercase + from django.core.management.base import BaseCommand -from mainapp.models import Team -import random +from django.db.utils import IntegrityError +from mainapp.models import Team, BLOCKED_SECTION_LETTERS + +for char in BLOCKED_SECTION_LETTERS: + ascii_uppercase = ascii_uppercase.replace(char.upper(), "") + class Command(BaseCommand): help = "Creates a fixture file for Team objects" @@ -10,28 +17,49 @@ class Command(BaseCommand): def handle(self, *args, **options): num_teams = options["num_teams"] + limit = len(ascii_uppercase) + if num_teams > limit: + self.stdout.write(self.style.ERROR(f"Number of teams is too large [{num_teams}/{limit}].")) + return + + # this code is so shit + # reminder to please rewrite this please teams = [] - for i in range(num_teams): - team = Team.objects.create() + iteration = 0 + errors = 0 + while iteration < num_teams: + try: + team = Team.objects.create(section_letter=ascii_uppercase[iteration]) + except IntegrityError as err: + self.stdout.write(self.style.ERROR(err)) + errors += 1 + if errors > limit: + break # heavy nesting: not good + + iteration += 1 teams.append(team) + if not teams: # TODO: error message + self.stdout.write(self.style.ERROR(f"Couldn't make teams -> ask corban because im too lazy to write an error message right now.")) + return + for team in teams: self.stdout.write(self.style.SUCCESS(f"Created team {team.team_number}")) - filename = f"src/mainapp/fixtures/teams_{num_teams}.json" - with open(filename, "w") as f: - self.stdout.write(f"Writing fixture to {filename}") - f.write("[\n") - for i, team in enumerate(teams): - f.write(" {\n") - f.write(f' "model": "mainapp.team",\n') - f.write(f' "pk": {team.team_number},\n') - f.write(' "fields": {}\n') - f.write(" }") - if i < len(teams) - 1: - f.write(",") - f.write("\n") - f.write("]\n") + filename = f"src/mainapp/fixtures/teams_fixture.json" - self.stdout.write(self.style.SUCCESS("Fixture created successfully")) + teams_fixture = [] + for team in teams: + team_fixture = { + "model": "mainapp.team", + "pk": team.pk, + "fields": { + "section_letter": team.section_letter + } + } + teams_fixture.append(team_fixture) + + with open(filename, "w") as f: + f.write(json.dumps(teams_fixture, indent=2)) + self.stdout.write(self.style.SUCCESS("Created teams_fixture.json.")) diff --git a/src/mainapp/migrations/0001_initial.py b/src/mainapp/migrations/0001_initial.py index e2e00e4..6c3342c 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-06 15:53 +# Generated by Django 4.1.5 on 2023-05-07 21:57 from django.db import migrations, models import django.db.models.deletion @@ -19,17 +19,11 @@ class Migration(migrations.Migration): ('peg_number', mainapp.models.ReusableAutoField(default=mainapp.models.ReusableAutoField.get_default, editable=False, primary_key=True, serialize=False)), ], ), - migrations.CreateModel( - name='Section', - fields=[ - ('character', models.CharField(max_length=1, primary_key=True, serialize=False, validators=[mainapp.models.validate_section_character])), - ], - ), migrations.CreateModel( name='Team', fields=[ ('team_number', mainapp.models.ReusableAutoField(default=mainapp.models.ReusableAutoField.get_default, editable=False, primary_key=True, serialize=False)), - ('section', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='mainapp.section')), + ('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( @@ -38,7 +32,8 @@ class Migration(migrations.Migration): ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('first_name', models.CharField(max_length=255)), ('last_name', models.CharField(max_length=255)), - ('team', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='mainapp.team', validators=[mainapp.models.validate_team_size])), + ('peg_number', models.PositiveIntegerField(null=True, unique=True)), + ('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/models.py b/src/mainapp/models.py index 7ae25cb..89872aa 100644 --- a/src/mainapp/models.py +++ b/src/mainapp/models.py @@ -1,13 +1,14 @@ +from string import ascii_uppercase + from django.db import models from django.core.exceptions import ValidationError -# products/models.py from django.db import models class ReusableAutoField(models.PositiveIntegerField): """A django auto field that can reuse deleted primary keys""" - + def get_next_available_id(self, model_cls, using=None): """ Returns the next available id for the given model class. @@ -50,8 +51,20 @@ class Member(models.Model): first_name = models.CharField(max_length=255) 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) + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + # If the peg_number field is not set, we assign it the smallest + # available positive integer, excluding any used values. + if not self.peg_number: + used_peg_numbers = Member.objects.exclude(id=self.id).exclude(peg_number=None).values_list("peg_number", flat=True) + peg_numbers = set(range(1, Member.objects.count() + 1)) - set(used_peg_numbers) + if peg_numbers: + self.peg_number = min (peg_numbers) + def __str__(self): return f"{self.first_name} {self.last_name} (team {self.team.team_number}))" @@ -60,11 +73,16 @@ class Member(models.Model): return f"{self.first_name} {self.last_name}" +BLOCKED_SECTION_LETTERS = ["i"] # lowercase only, sections cannot be any of these letters# + + class Team(models.Model): """Represents a team""" team_number = ReusableAutoField(primary_key=True, default=ReusableAutoField.get_default, editable=False) - section = models.OneToOneField("Section", on_delete=models.SET_NULL, null=True, blank=True) + 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}" @@ -84,17 +102,17 @@ def validate_section_character(value): raise ValidationError(f"The character <{value}> is a prohibited character.") -class Section(models.Model): - """Represents a section of the scoreboard""" +# 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, )) +# # 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 clean(self): +# self.character = self.character.upper() - def __str__(self): - return f"Section {self.character}" +# def __str__(self): +# return f"Section {self.character}" #class Scoreboard(models.Model): diff --git a/src/mainapp/templates/teams.html b/src/mainapp/templates/teams.html index eba6989..8571e34 100644 --- a/src/mainapp/templates/teams.html +++ b/src/mainapp/templates/teams.html @@ -12,7 +12,7 @@
-

Teams & Members

+

Teams & Members

@@ -38,7 +38,7 @@