Paddle Tennis Hall of Fame is a web application designed for groups of friends who play paddle tennis together. It helps them manage their own "Hall of Fame" within their tennis club.
Registered users can track matches played, update match results, view player rankings, and access player statistics.
This web application is built using:
- Django and Django Rest Framework (DRF) for the RESTful API.
- Django templates, JavaScript, and Bootstrap for the frontend.
- π Overview
- β¨ Key Features & Implementation
- π οΈ Technologies Used
- ποΈ Project Structure
- π‘ API Endpoints
- π Frontend Endpoints & Templates
- π οΈ JavaScript Functionalities
- π§ͺ Testing
- π Future Enhancements
- π Installation
- π€ Contributing
- π License
- Displays a ranked list of paddle tennis players based on their number of wins.
- Publicly accessible (no authentication required).
- Implementation:
- The
PlayerViewSet
inviews.py
retrieves players, ordering them by thewins
field to create the ranking. - The
PlayerSerializer
usesSerializerMethodField
to dynamically calculatematches_played
,losses
, andwin_rate
.
- The
- Authenticated users can add and update match results.
- Each match consists of two teams, each with two players.
- When a new match is added, new players are created if they don't exist.
- Users can only add, update, or delete matches in which they are a participant.
- Implementation:
- The
MatchSerializer
handles player name input, creates new players if needed, and prevents duplicate player entries. perform_create()
in theMatchViewSet
updates player stats when a match is created.perform_update()
resets old match stats before applying new results to maintain data integrity.
- The
- Users can register, log in, and manage their profiles.
- During registration, users can link their account to an existing player or create a new one.
- When linking to an existing player, the user takes over the player's stats, and the player's name is changed to the user's username.
- Users can only update or delete their own profiles, unless they are an admin.
- Implementation:
- The
UserSerializer
includes aplayer_id
field for optional linking to an existing player. - The
UserViewSet
restricts profile modification to the user's own profile or admins.
- The
- Provides detailed profiles for each player, including their match history and stats such as wins, matches played, win rate, and losses.
- Only admins can update or delete player details.
- Implementation:
- The
PlayerSerializer
uses calculated fields:matches_played
,losses
, andwin_rate
. - The
PlayerViewSet
restricts player profile modification to admins.
- The
- Unauthenticated users can only:
- View the Hall of Fame.
- Register.
- Log in.
- Authenticated users can also:
- Add match results.
- Update or delete their own match results.
- View and update their profile.
- View player stats.
- Admins have full access, including creating, updating, and deleting matches, players, and users.
- Implementation:
- DRF's built-in session authentication is used.
- The
IsAuthenticatedOrReadOnly
permission allows unauthenticated users to view player rankings. - The
IsAuthenticated
permission restricts match-related actions to authenticated users.
- Session-based authentication for login and logout.
- Implementation:
- The
LoginView
andLogoutView
API endpoints handle user authentication and logout.
- The
- Backend: Django Rest Framework (DRF)
ModelViewSets
,ModelSerializers
withSerializerMethodField
, andRouters
for simplified API management.- Built-in session authentication from DRF.
- Frontend:
- Django Templates.
- JavaScript.
- Bootstrap 5.
- Database: SQLite for development and testing.
paddle/
βββ config/ # Project configuration and settings
βββ games/ # API app for players & matches
β βββ serializers.py
β βββ views.py
β βββ models.py
β βββ urls.py
β βββ tests/ # Tests for games API
βββ users/ # API app for user management
β βββ serializers.py
β βββ views.py
β βββ models.py
β βββ urls.py
β βββ tests/ # Tests for users API
βββ frontend/ # Frontend logic and templates
β βββ static/frontend/ # Static files for the frontend
β β βββ css/ # Stylesheets
β β β βββ styles.css # Custom styles for the frontend overriding Bootstrap styles
β β βββ js/ # JavaScript files
β β β βββ editUserProfile.js # Send a PATCH request for updating user details
β β β βββ matchDeleteHighlight.js # On deletion update match card background dynamically
β β β βββ matchEdit.js # Update match card and form dynamically
β β β βββ passwordValidation.js # Confirm password match
β β β βββ playerLabelUpdater.js # Update player labels dynamically on match form
β β β βββ winningTeamHighlight.js # Update winning team card dynamically on match form
β βββ templates/frontend/ # Django templates
β β βββ _match_card.html # Match history card to be included in match.html
β β βββ _user_form.html # Reusable user form for register.html and user.html
β β βββ base.html # Base template with common navigation bar & footer
β β βββ hall_of_fame.html # Template for Hall of Fame
β β βββ login.html # Template for user login
β β βββ match.html # Template for adding and reviewing match results
β β βββ register.html # Template for user registration
β β βββ user.html # Template for checking or editing user details
β β βββ images/ # Images
β βββ __init__.py
β βββ test_frontend.py # Tests for frontend
β βββ urls.py # URL routing for template views
β βββ views.py # Views to render the templates
βββ README.md # Project documentation
βββ requirements.txt # Dependencies for the project
βββ manage.py # Django entry point
All API endpoints follow the RESTful API design principles and use standard HTTP methods (GET, POST, PUT, PATCH, DELETE). The API uses standard HTTP status codes to indicate success or failure. Errors will be returned as a 400 Bad Request
or a 404 Not Found
with an error message in the response body.
The games
app manages both players and matches.
/api/games/players/
:
GET
: Provides access to the Hall of Fame with a ranked list of all players. Publicly accessible.POST
: Creates a new player. Admin-only.
/api/games/players/<id>/
:
GET
: Provides detailed information about a specific player. Only authenticated users can access it.PUT
&PATCH
: Updates a player's information. Admin-only.DELETE
: Deletes a player. Admin-only.
/api/games/matches/?player=<player_name>
:
GET
: Returns all matches, or filtering matches by a specific player. Allows authenticated users viewing match history and display the form for adding match results:- When there is no query parameter, all matches are shown ordered by date.
- When query parameter is specified, only matches played by the
player_name
are shown ordered by date.
/api/games/matches/
:
POST
: Allows authenticated users to add matches, creating new players if needed. The user must be one of the match participants.
/api/games/matches/<id>/
:
PUT
&PATCH
: Allows authenticated match participants to edit match details.DELETE
: Deletes a match. Restricted to authenticated match participants.
/api/games/players/player_names/
:
GET
: Returns a JSON dictionary with a list of registered users (players linked to a User account) and a list of non-registered players, both with their ID and name. Results are sorted alphabetically. Publicly accessible. Will be used:- During user registration: to provide a list of non-registered players to choose from;
- When introducing new match results: to differentiate between registered players and new players.
Manages user registration, login, logout, linking of existing non-registered players, and user profiles management.
/api/users/
:
POST
: Allows new users to register. Publicly accessible. Checks if the username already exists.
/api/users/<id>/
:
GET
: Returns the authenticated user's own profile. Only the authenticated user, owner of the profile or an admin can access it.PATCH
: Updates a user's profile. Only the authenticated user, owner of the profile or an admin can modify it.DELETE
: Deletes a user's profile. Only an admin can perform this action.
In development, the api-auth
app provides endpoints for login and logout for the browsable API.
/api-auth/login/
: Login endpoint for the browsable API.
/api-auth/logout/
: Logout endpoint for the browsable API.
All templates extend a base layout using {% extends "base.html" %}
where:
base.html
: Provides the site-wide layout, including the common navigation bar and standard footer. It serves as the foundation for all pages, ensuring a consistent look and feel across the site. The navigation bar is:- Collapsible on small screens.
- Sticky on scroll.
- Links accessible to unauthenticated users: Paddle HoF, Register, and Login.
- Links accessible to authenticated users: Paddle HoF, Matches, User Profile (displaying the current user's name), and Logout.
- Matches should display a badge with the number of pending matches for the current user in that session. By clicking on the badge the user is redirected to the
match.html
page. The badge is only displayed if there are any pending matches. The matches in the dropdown are ordered by date.
These are the full-page templates directly mapped to URLs:
URL | Purpose | Template Loaded | Specs |
---|---|---|---|
/ |
Hall of Fame β ranked list of players | hall_of_fame.html |
Table with wins, matches played, and rates for each player. |
/register/ |
User registration | register.html |
Dynamic checking of restrictions and load available players to choose from. |
/login/ |
User login | login.html |
User & password fields and login button. |
/logout/ |
User logout | N/A - View handled | Logout link with bootstrap icon. This action is a redirection. |
/users/<id>/ |
User details and editing | user.html |
User profile stats and editable fields. |
/matches/ |
Match results and editing | match.html |
Form for adding and editing matches and match history, both for the user and all matches. Displays the list of matches using _match_card.html . |
/matches/<id>/delete/ |
Delete match | N/A - View handled | Trash button with bootstrap icon. This action is a redirection. |
These partial templates are reusable components designed to be included in full templates using {% include %}
:
-
_match_card.html
: Displays a match card used in the tabs of the Match History section ofmatch.html
. With color indication for winning team in green background, date played with a badge indication for not yet reviewed matches by the user in that session, and delete and edit buttons for matches where the user is a participant. The edit button let the user edit his own matches. -
_user_form.html
: A dynamic form for creating and editing users. Reused in bothregister.html
(for new users) anduser.html
(for editing profiles).
passwordValidation.js
: Checks if the password and confirm password fields match, and dynamically displays an error message if they don't. Is used inregister.html
.playerLabelUpdater.js
: The label of the player input field updates dynamically as the user types, based on the input value to distinguish between registered players, existing players, and new players in the form fields ofmatch.html
.winningTeamHighlight.js
: Dynamically updates the background of the "Team 1" and "Team 2" cards in the form fields ofmatch.html
based on the selection of the "winning_team" radio button.matchDeleteHighlight.js
: Dynamically updates the background of the match card in the form fields ofmatch.html
to indicate deletion before sending the DELETE request.matchEdit.js
: Allows editing of match details inmatch.html
. The Edit button is only visible in matches of the match history section where the current user is a participant. By clicking on the edit button in a match card, the following happens:- The selected match card to be edited is highlighted.
- The form in
match.html
is pre-filled with the data of the selected match. - The html is focused on the form.
- The "Add Match" button is changed to "Edit Match". When the user clicks "Edit Match", the endpoint of the API is called by PUT.
- A "Cancel Edit" button is added to the form, which allows canceling the edit and reloads the default
match.html
.
editUserProfile.js
: Allows editing of allowed user details inuser.html
. Only the email field is editable. By changing the value on the email field in the user profile, "Cancel Changes" and "Save Changes" buttons are enabled:- When the user clicks "Save Changes", the endpoint of the API is called by PATCH.
- When the user clicks "Cancel Changes", the form is reset to the original values.
The project comes with a suite of tests for the games
, users
, and frontend
apps. The tests can be run using the pytest
command from the project's root directory. These tests cover authentication, authorization and model logic. Frontend template rendering tests are left for future development.
The test files follow the naming conventions:
games/tests/test_permissions.py
games/tests/test_players.py
games/tests/test_stats.py
users/tests/test_authentication.py
users/tests/test_permissions.py
users/tests/test_register.py
This application implements pagination to efficiently handle and display large datasets of players and matches. Pagination is applied to the Hall of Fame and Match History views, ensuring a smooth and responsive user experience, even with extensive data.
The backend utilizes Django REST Framework's (DRF) built-in pagination capabilities. This provides a standardized way to paginate API responses.
- How it Works: When requesting a paginated endpoint (e.g.,
/api/games/players/
or/api/games/matches/
), the API will return a subset of the data along with metadata about the pagination. - Query Parameter: To navigate through pages, use the
?page=<page_number>
query parameter in your request. For example,/api/games/players/?page=2
will retrieve the second page of players. - Response Structure: The API response for paginated endpoints includes:
count
: The total number of items available.next
: The URL for the next page of results (ornull
if there is no next page).previous
: The URL for the previous page of results (ornull
if there is no previous page).results
: An array containing the data for the current page.
- Page Size: The default page size is set to 12 items per page in the
settings.py
file (PAGE_SIZE = 12
). This specific size was chosen because the_match_card.html
template displays match cards in a grid layout with three columns on larger screens. Using a multiple of three ensures that rows are always filled completely.
The frontend leverages Bootstrap 5's pagination component to provide a user-friendly interface for navigating through paginated data.
- How it Works: The frontend dynamically generates pagination links based on the
next
andprevious
URLs provided in the API response. - Implementation: The pagination component is implemented in the
hall_of_fame.html
andmatch.html
templates. The same component is reused in both templates. - User Experience: The pagination component seamlessly integrates with the application's design, allowing users to easily navigate between pages of players or matches. It displays the current page number and provides links to the previous and next pages, if available.
- Dynamic Rendering: The pagination component is dynamically rendered based on the data received from the API, ensuring that the correct number of pages and navigation links are displayed.
This project is licensed under the MIT License. See the LICENSE file for details.