Welcome to Dball’s documentation!¶
Team: | ITUCSDB1515 |
---|---|
Members: |
|
DBall Database Application is prepared for baseball, a branch of sport especially popular in American culture with more than 300 hundred years of history. It can hold many of the statistical data that represents baseball as whole. It is easy to use, simple yet also give much more flexibility than any other application. In other terms, it directly responds to user. If user wants it complex it become like one. And more importantly it is multi functional and open source.
How to Install?¶
Just follow the following steps in order to install application.
- First go to the
www.python.org
and grab python (preferably version 3.4.3).- Then install
flask
,psycopg2
,passlib
andrequests
packages throughpip
.
- PS. You can use
pip install flask psycopg2 passlib requests
ifpip
is declared in your environment path.- Then install PostgreSQL through
www.postgresql.org
- Setup database, then import
init.sql
file into database through recovery.- Fire up
server.py
and you are ready to roll!
Contents:
User Guide¶
DBall Application is designed to become user friendly, simple and clean. Any type of user no matter what level of their computer skills is targeted for this application. Addition to its simple design, it is designed to be multi-functional. More of its functions such as altering and registering new record available through registration. Still all of the record can be accessible through front view. DBall also provides a abstract interface for developers. With its robust REST API, developers can use our services in their programs easily. For further information about this topic please advance to Developer Guide.
Parts Implemented by Oğuz Kerem Tural¶
Main Area¶
Upon entering the application, user faces with this screen. It contains a navigation bar on top, a search box and two columns. Search box is not yet active. Still user can search each table from their singular views. From top navigation bar user can move across table views and login if it is not yet logged in. Also from right side column, user can be able to see latest changes on records have done by registered users.
User System¶
User system in application is very basic and an abstract system that aims to prevent anonymous changes could have been done to database records. Every registered user has right to add, update or delete records where as unregistered users can only view, search and filter the records. Both user login and register operations are done using an Auth API service that has been provided by application itself. For further information about API please reference to Developer Guide.
Login Using Interface¶
To login using interface, user should click the button provided in navigation bar’s top right corner with the door symbol on it. After click, a modal window will be shown which provides user name and password fields to user for log in operation.
If user enters wrong credentials, an error message will appear and warns user about wrong credentials.
Management Area¶
Registered users have privileges to change the records that stored in database. After user logged in, it can redirect here using drop down user menu in navigation bar. In same way, it can go back to front area using drop down menu in navigation bar. In here user greeted with change history again. But difference between the main screen change log and manager screen change log is in manager screen user can be able to see all changes has been done from beginning of the application. User can move to the management areas for different tables from sidebar.
Sidebar¶
From this section, user can navigate through different tables easily. Active page will be highlighted.
People Records¶
In application each person stored in people table. From front view both unregistered and registered user can see the view front page.
User can search records that are listed in table. To search user should just type keywords into search box in right corner of the table. Also user can order tables by clicking the header of column whose elements would order the table accordingly. User can order table in ascending or descending order.
Also user can change number of elements that are shown in pages.
From top button right next to title user can advance into management area. If user not logged in it would give an error and asks user to login.
When user advances into management area, three button would appear in the bottom of the table. First of them is for adding operation, second of them is for update and the last one is for delete operation.
If operations are successful a success message will appear on top of the table, if not then an error message will appear.
Add Operation¶
User can add both person information and person type. Still be warned, person types cannot be deleted from database so add them wisely and only when its necessary.
From ‘’Add New Data’’ button, open drop down menu. After that user can select either to add new person or person type. When clicked the selected button, a modal which would provide inputs will appear.
User should fill all necessary inputs. If it skips any of them a warning will appear and prevent user to send data.
Update Operation¶
User can update records easily first selecting which record will be updated and then clicking ‘’Update Selected Row’’ button. Still, only one record can be updated at time. If user selects more record and hits the update button an error message different from other will be appear.
After selecting one record, user can hit update button. When user clicks the update button a modal which provides pre-filled inputs would appear. After that user can change any value as it would like.
Delete Operation¶
User can delete multiple records at one time. User only needs to select which records to be deleted and hit the delete button. If operation successful the success message will appear and page will reload.
Penalty Records¶
In penalty records most of the table functionality are the same as people table since all tables derived from a generic table design. Hence, user can search, filter and move across table pages in same way. For those operations please refer to People Records.
Add Operation¶
When user clicks the ‘’Add New Data’’ button a drop down similar in people records will appear. From there user can add either a new penalty record or penalty type record.
Update Operation¶
User can update one record at a time. If more rows selected, user will encounter with an error same as in people records. Again user should click ‘’Update Selected Row’’ button to reveal update modal which provides necessary inputs for operation.
Delete Operation¶
User can delete selected rows. First it should select every rows that need to be deleted then it should hit ‘’Delete Selected Row(s)’’ button. If operation successful, success message will appear and page will be reloaded.
Popularity Records¶
Again in same fashion, popularity records also uses generic table view for user end. User can do all operations that can be done in people record. For further information please refer to People Records.
Add Operation¶
When user clicks the ‘’Add New Data’’ button this time add modal directly appears and provides input for record. User should fill all necessary input or a warning will warn the user and prevent submitting info.
Update Operation¶
Again in here, user can update one record at a time. If more rows selected, user will encounter with an error same as in people records. Again user should click ‘’Update Selected Row’’ button to reveal update modal which provides necessary inputs for operation.
Delete Operation¶
User can delete selected rows. First it should select every rows that need to be deleted then it should hit ‘’Delete Selected Row(s)’’ button. If operation successful, success message will appear and page will be reloaded.
City Records¶
In city records, user again can do the same operations as described in people records section. For more information about that operations please refer to People Records. Additionally, user can see the location of city on map using ‘’Show Location’’ button. When user hits this button after selecting a city record, a extra modal which contains a map and a marker that show location will appear. Still, user can only see one location at a time. If it selects more an error will appear.
Add Operation¶
Again as it before, when user clicks ‘’Add New Data’’ button, a modal which provides necessary inputs for record will appear.
Update Operation¶
User can update one record at a time. If more rows selected, user will encounter with an error same as in people records. Again user should click ‘’Update Selected Row’’ button to reveal update modal which provides necessary inputs for operation.
Delete Operation¶
User can delete selected rows. First it should select every rows that need to be deleted then it should hit ‘’Delete Selected Row(s)’’ button. If operation successful, success message will appear and page will be reloaded.
Parts Implemented by Umut Can Ozyar¶
Sponsorships¶
The sponsorships data is stored in the database. Using the navigation bar located at the top of the front page sponsorships table can be accessed.
This table displays the sponsorships data in the database.
Several alterations can be made by the user to change the way the data is displayed on the table. The amount of entries desired to be shown can be changed from the drop down list located at the top left of the table. The selected number corresponds to the amount of rows displayed by the table. In case the selected number exceeds the amount of sponsorships data, only the existing data will be displayed with no empty rows.
There are also page control buttons located at the bottom right side of the table. These buttons are used to navigate through different table pages if perchance there are more data in the database than the amount selected to be shown.
The ordering of the data throughout the table can be changed by clicking on the sort buttons located at each table header. This feature allows user to sort the data depending on various attributes of the table in descending or ascending order.
If there is no data in the database about sponsorships, “No data available in table” message is displayed on the table to notify the user.
The manage button located on top of the table directs to user to the manager of the sponsorship table. This page is limited for registered users only. Guest users will be notified to login using the login button located at the top right side of the page.
Manager page allows user to add new data, update existing data or delete existing data.
Add Sponsorship¶
“Add New Data” button allows the user to add a new sponsorship for league, team and person entities in any combination. Then a modal for adding new data will appear. This modal contains several fields corresponding to different attributes of the table.
First input field is for the name of the sponsor. The second field brings out a calender for sponsorship start date selection. Third field is for selecting the sponsored league. Fourth field is for selecting the sponsored team and the last field is for the sponsored person. Some of the last three fields can be left blank as a sponsor doesn’t have to sponsor a league, a team and a person at the same time. After the necessary fields are filled submit button is used to add the data to the table.
Some of these fields like the name and the start date cannot be left blank and will warn the user if submit button is clicked without filling these fields.
Alerts will appear on top of the table to notify the user about the outcome of the add operation. This can either be a success message with a green background which means that data is added to the database successfully or it can be a failure message with a red background which means that a problem has occurred and the operation is unsuccessful.
Update Sponsorship¶
“Update Selected Row” button allows the user to update a sponsorship entity on the table. If a row is not selected or multiple rows are selected, an error message notifies the user to select a single row.
If a single row is selected a modal for updating data will appear. This modal contains several fields corresponding to different attributes of the table filled with the existing data.
Several attributes can be updated using this modal at the same time. Some fields like the name and start date will still be required to be filled. Submit button will update the data on the database.
Please refer to Add Sponsorship for more detail about the fields and all encountered alerts.
Delete Sponsorship¶
“Delete Selected Row(s)” button allows the user to delete sponsorship entities from the table. At least one row has to be selected to perform this operation.
Team Statistics¶
The team statistics data is stored in the database. Using the navigation bar located at the top of the front page team statistics table can be accessed. This table displays the sponsorships data in the database.
The manage button located on top of the table directs to user to the manager of the team statistics table. This page is limited for registered users only. Manager page allows user to add new data, update existing data or delete existing data.
Add Team Statistics¶
“Add New Data” button allows the user to add team statistics for an existing team. Then a modal for adding new data will appear. This modal contains several fields corresponding to different attributes of the table. Wins, draws and losses are automatically calculated according to the matches data.
First input field is a drop down menu for team selection. The rest of the fields are inputs for batting runs, batting hits, pitching saves respectively. After the necessary fields are filled submit button is used to add the data to the table.
Please refer to Add Sponsorship for instructions about validation or alerts, and Sponsorships for navigation.
Update Team Statistics¶
“Update Selected Row” button allows the user to update a team statistics entity on the table. If a row is not selected or multiple rows are selected, an error message notifies the user to select a single row.
If a single row is selected a modal for updating data will appear. This modal contains several fields corresponding to different attributes of the table filled with the existing data.
Several attributes can be updated using this modal at the same time. Some fields like hits, runs and saves date will still be required to be filled. Submit button will update the data on the database.
Please refer to Add Team Statistics for more detail about the fields and Add Sponsorship for all encountered alerts.
Delete Team Statistics¶
“Delete Selected Row(s)” button allows the user to delete team statistics entities from the table. At least one row has to be selected to perform this operation.
Stadiums¶
The stadium data is stored in the database. Using the navigation bar located at the top of the front page stadiums table can be accessed. This table displays the stadiums data in the database.
The manage button located on top of the table directs to user to the manager of the stadium table. This page is limited for registered users only. Manager page allows user to add new data, update existing data or delete existing data.
Add Stadium¶
“Add New Data” button allows the user to add a new stadium for an existing team. Then a modal for adding new data will appear. This modal contains several fields corresponding to different attributes of the table.
First input field is the name of the stadium. Second input field is a drop down menu for team selection. Third input field is another drop down menu for location selection which indicates the city the stadium is located in. The last field is a numerical value representing the capacity of the stadium. After the necessary fields are filled submit button is used to add the data to the table.
Please refer to Add Sponsorship for instructions about validation or alerts, and Sponsorships for navigation.
Update Stadium¶
“Update Selected Row” button allows the user to update a stadium entity on the table. If a row is not selected or multiple rows are selected, an error message notifies the user to select a single row.
If a single row is selected a modal for updating data will appear. This modal contains several fields corresponding to different attributes of the table filled with the existing data.
- Several attributes can be updated using this modal at the same time. None of the fields can be left blank. Submit button
- will update the data on the database.
Please refer to Add Stadium for more detail about the fields and Add Sponsorship for all encountered alerts.
Delete Stadium¶
“Delete Selected Row(s)” button allows the user to delete stadium entities from the table. At least one row has to be selected to perform this operation.
Parts Implemented by Mert Şeker¶
Teams¶
All team data is kept in database. A front page to change or represent this data is used. First page is on /teams route and it represents the data in the database in a simple and understandable way and provides some functionality.
As it can be seen in the above figure, data is divided into 2 columns; team name, team’s coach.
Second page is for both displaying and editing the data for teams and it is on the /manager/teams route and only users that have authority can access this page. In this manager page, all data is shown in data table structure. Even though the team id column is not shown on the front page, it is shown here.
On the top left side of the screen you can select how many entities are shown in a single page. You can search for a team by using the search bar on the top right side of the screen. You can sort all tuples by clicking on a column with respect to the clicked column.
The three buttons at the bottom of the page are buttons for add, update and delete operations.
Add Operation¶
By clicking the “Add New Data” button on the bottom of the page, a modal shows up prompting data for new record.
![]()
Team Add Screen
First box is a textbox for entering the team name. Second box is a drop down menu to choose a team coach; it is only possible to choose a person that have the person type as coach. None of these fields can be null. After entering the data to the fields and clicking the “Submit” button, if there are no problems in the back end, new team data will be added to the database and it can be seen in the front and manager pages.
Update Operation¶
Clicking on a row will select that team and clicking the “Update Selected Data” button will show up the update screen if only one row have been selected. If more than one row have been selected, an error message will be shown on the screen.
After user selects one row and clicks the update button a modal will show up for updating the team data.
![]()
Team Update Screen
After user enters the new data in the fields and submits the form , selected team will be updated accordingly. After the update operation is successful, all references to the previous data will also be changed by the new data.
Delete Operation¶
By clicking the “Delete Selected Row(s)” button user can can select one or more teams. After the user have selected the rows, clicking the button will delete all the chosen rows from the team table.
Players¶
All player data is kept in database. A front page to change or represent this data is used. First page is on /players route and it represents the data in the database in a simple and understandable way and provides some functionality.
As it can be seen in the above figure, data is divided into 3 columns; player name, player’s team and number of goals that the player have scored.
Second page is for both displaying and editing the data for players and it is on the /manager/players route and only users that have authority can access this page. In this manager page, all data is shown in data table structure. Even though the player id column is not shown on the front page, it is shown here.
On the top left side of the screen you can select how many entities are shown in a single page. You can search for a player by using the search bar on the top right side of the screen. You can sort all tuples by clicking on a column with respect to the clicked column.
The three buttons at the bottom of the page are buttons for add, update and delete operations.
Add Operation¶
By clicking the “Add New Data” button on the bottom of the page, a modal shows up prompting data for new record.
![]()
Player Add Screen
First box is a textbox for entering the player’s name. Second box is a drop down menu to choose the player’s team; it is only possible to choose a team from the teams table. Third box is for entering the number of goals that the player have scored and it is entered as integer. None of these fields can be null. After entering the data to the fields and clicking the “Submit” button, if there are no problems in the back end, new player data will be added to the database and it can be seen in the front and manager pages.
Update Operation¶
Clicking on a row will select that team and clicking the “Update Selected Data” button will show up the update screen if only one row have been selected. If more than one row have been selected, an error message will be shown on the screen.
After user selects one row and clicks the update button a modal will show up for updating the player data.
![]()
Player Update Screen
After user enters the new data in the fields and submits the form , selected player will be updated accordingly. After the update operation is successful, all references to the previous data will also be changed by the new data.
Delete Operation¶
By clicking the “Delete Selected Row(s)” button user can can select one or more players. After the user have selected the rows, clicking the button will delete all the chosen rows from the player table.
Tournaments¶
All tournament data is kept in database. A front page to change or represent this data is used. First page is on /tournaments route and it represents the data in the database in a simple and understandable way and provides some functionality.
As it can be seen in the above figure, data is divided into 6 columns; tournament name, number of matches, start date, end date, country and prize.
Second page is for both displaying and editing the data for tournaments and it is on the /manager/tournaments route and only users that have authority can access this page. In this manager page, all data is shown in data table structure. Even though the tournament id column is not shown on the front page, it is shown here.
On the top left side of the screen you can select how many entities are shown in a single page. You can search for a tournament by using the search bar on the top right side of the screen. You can sort all tuples by clicking on a column with respect to the clicked column.
The three buttons at the bottom of the page are buttons for add, update and delete operations.
Add Operation¶
By clicking the “Add New Data” button on the bottom of the page, a modal shows up prompting data for new record.
![]()
Tournament Add Screen
First box is a textbox for entering the tournament’s name. Second box is for entering the number of matches. Third box is for entering the start date. Fourth box is for entering the end date. Fifth box is for choosing a country from the countries table, it is also possible to see the country’s location on the map by clicking the pin icon next to it. Sixth box is for entering the prize that will be given to the winner.None of these fields can be null. After entering the data to the fields and clicking the “Submit” button, if there are no problems in the back end, new tournament data will be added to the database and it can be seen in the front and manager pages.
Update Operation¶
Clicking on a row will select that team and clicking the “Update Selected Data” button will show up the update screen if only one row have been selected. If more than one row have been selected, an error message will be shown on the screen.
After user selects one row and clicks the update button a modal will show up for updating the tournament data.
![]()
Tournament Update Screen
After user enters the new data in the fields and submits the form , selected tournament will be updated accordingly. After the update operation is successful, all references to the previous data will also be changed by the new data.
Delete Operation¶
By clicking the “Delete Selected Row(s)” button user can can select one or more tournaments. After the user have selected the rows, clicking the button will delete all the chosen rows from the tournament table.
Parts Implemented by Furkan Akgün¶
Change Log¶
When you first enter the site, you will realize that there is a column showing the last five operations done in the site. When an authenticated user perform an operation, last five operations always be showing up in main page. If that is the first time user entered the site, by checking both columns in the home page and examining last changes user can get an idea of the website. On the other hand if it is not user’s first time, then instead of checking all tables to see what changed; user can simply look on the last changes column.
Change Log serves two main ideas; to track down which operations are done and by whom, and by some chance if database operations fails as a means of debugging. In the home page we represent only the last five changes, but in manager screen all logs are stored.
As can seen in the above figure, logs are all divided into 3 different columns; first column to explain what is done, second to tell by whom and the third for date of the operation. In the main change log it is easy to differentiate users from the description because table structure make their positions clear. But in the home page in last changes column, in some cases it may not be easy to see user in first glance. So to emphasize some keywords in log like user, we used bold font for users.
Country¶
All country data are stored in database.So we have basically a front page to represent or change this data. First page is simply on /country route and its purpose to represent data we have in an elegant way and providing some functionality.
As can seen in the above figure, data simply divided into 3 columns; country name, country’s capital and the population. Also table is striped table meaning that if you have your cursor over a row, that row will be focused and will be easy to see. There are location markers next to city and country names, as you can guess by clicking those icons user can see location of clicked name on GoogleMaps Api.
In this example I have clicked on Paris and the results can be seen as in the figure above. Right after clicking the location marker, a modal with location map shows up by taking all the focus. Also at the top of the table you can see “Manage” button. By clicking this button, if user have sufficient permission, user will be directed to manager page for countries where he/she can change data.
Second page for both representing and changing data for countries is on the /manager/country route and only users with sufficient permissions can locate the page. In this page, all data represented in data table structure. Also any columns for country such as id are shown here while it was not showing in the front page.
On the top left side of the table you can select how many records to show in a single page. And on the top right side of the table you can search for any records. By clicking on the column name you can sort all records by the clicked column.
And finally the last three buttons in the bottom of the page are add, update and delete buttons respectively.
Add Operation¶
By clicking the “Add New Data” button on the bottom of the page, a modal shows up prompting data for new record.
![]()
Country Add Screen
First is country name which is simply a textbox and user can enter a country name in mind. Second is city name; users can only select cities currently on the database which are available in the selection. Third is population and users can enter an integer value. Right after completing the input and clicking the “Submit” button at the buttom of page. If there is no problem in backend new country data will be added to database and now can be seen in both front and manager pages.
Update Operation¶
By clicking the “Update Selected Data” button a modal will show up if the user have selected only one row. If selected row count exceeds one, then right after user clicked update button an error will show up on the top of table warning users about number of selected items.
After user selected only one row and clicked update button a modal for updating data will show up.
![]()
Country Update Screen
Right after user fill the inputs and submit the form ,if nothing prevents in the backend, selected row of country table will be updated. After update operation all links of previous data also be changed by the new data.
Delete Operation¶
By clicking the “Delete Selected Row(s)” button user can delete either one entry or multiple entries. After user selected the rows he/she wish to delete, clicking the button will delete all selected rows from the table.
Match¶
As like the country, match table also have two different pages on purpose. One again for to represent data in an elegant way, the other for changing the data. First page is to represent data and any user can locate this page on route /matches.
As can seen in the above figure, data is represented in a table structure and have several columns which are date, results, referee and stadium. Date, simply as the name says, shows the date when the match took place and formatted as D/M/Y. Results column shows teams and their scores with scores emphasized. And so stadium shows which stadium match took place and referee shows who was the referee in the match.
After user clicked “Manage Button” on the top of table, user will be directed to /manager/matches page if he/she have sufficient permission.
Second page is for both representation and modifying data and can be accessed only by authenticated users.
Add Operation¶
Just like in the country page, when clicking “Add New Data” a modal shows up and asks for data for entry to be added.
![]()
Add Screen for Matches
Here you can choose two teams registered in database in dropdown menus and set score values for each of them. Score value must be between 0 and 100. Next choose a stadium from database and assign it to this match. You can also select a referee and specify date of the match in this add screen.
Update Operation¶
After clicking “Update Data” Button after selection row to be updated, a modal shows up asks for user to enter new data. In every page, just like in country page, user should select only one row to update. If user, by any change, try to update two or more row at the same time, a warning message will be created.
![]()
Update Screen for Matches
You can simply change any value of the match without damaging integrity of database.
Delete Operation¶
Just like in country page, you can select one or multiple entries and then hit delete button to delete them from the database.
League¶
All league data are stored in database. League data just like the other tables have two pages with different purposes; one for representing the data in a way appropriate to content and the other for editing data.
In this page, user can see all the leagues registered in database. User can see a league’s country and start date. What’s more is that by clicking the “Leaderboard” button, user can access leaderboard for that league easily.
Manager page of leagues is also identical to the other class manager pages. All data are in datatable and ready to modify.
Add Operation¶
Just like previous classes, after clicking add button a modal for league shows up and prompts for entry. After submitting new entry will be added to the database.
![]()
Add Screen for League
Here user can name the league anything he wants and can select a registered country from the database in dropdown menu. Also user can specify start date of the league.
Update Operation¶
User first select one row to be updated by clicking on rows. However only one row at a time allowed to be updated, meaning if user ever try to update two or more selected items, a warning will appear in top of the table just like in country and match page.
![]()
Update Screen for League
Delete Operation¶
User must first select the rows he/she wish to delete. After selecting the one or multiple rows to be deleted just hitting delete button will delete all selected data from the database.
Developer Guide¶
Database Design¶
Our database relations has been designated to be use power of relations as much as possible. All possible repeated data amount has been reduced in order to reduce used storage amount. More detailed information has been explained by each group member.
Git Workflow¶
Git workflow thorough development process has been visualized with open source software called gource.
Code¶
For code structure, model-view-controller hierarchy has been used. Where model methods and control methods has been seperated. For each entity a class has been created. These classes used as models which have done the database operations. Routes has been connected to views and if user enters an input, entered data went through view to controller and then model. Also an API has been created to made possible the abstract operations which is free from user interface. In reality, models has been designed as API, thus it increases technical capabilities of our code. Each group member has been explained their parts in more detail.
Parts Implemented by Oğuz Kerem Tural¶
Front End Design¶
Application user interface uses Bootstrap framework for responsive UI, jQuery framework for much more dynamic design and DataTables framework for glorious tables. Main aim for the design was simplicity. Any type of user could easily use the application without losing its way. Thus, color scheme selection and content placement has been done accordingly. On top of the Bootstrap, a hand written CSS file has been added to extend both its responsivity and design.
Different enhancements has been applied on both front body and manager body classes. Pagination has been fixed, columns in front page has been hidden in smaller screens. Also navigation bar and sidebar has been changed in smaller screens.
.sidebar { display: none; } @media (min-width: 768px) { .sidebar { background-color: #f5f5f5; position: fixed; top: 31px; left: 0; bottom: 0; display: block; padding: 20px; } }
For show sidebar minimum screen width has been selected as 768px. If screen width is smaller than this, sidebar will be hidden and a navigation bar on top would be displayed. Both navigation bar and sidebar uses Jinja2‘s variable switching ability. Both front and manager layout contains a Jinja2 block that contains all menu items.
{% set navigation_bar = [ ('/manage', 'main', 'Main'), ('/manage/people', 'people', 'People'), ('/manage/penalties', 'penalties', 'Penalties'), ('/manage/popularity', 'popularity', 'Popularity'), ('/manage/cities', 'cities', 'Cities'), ('/manage/teams', 'teams', 'Teams'), ('/manage/team_stats', 'team_stats', 'Team Statistics'), ('/manage/players', 'players', 'Players'), ('/manage/sponsorships', 'sponsorships', 'Sponsorships'), ('/manage/stadiums', 'stadiums', 'Stadiums'), ('/manage/countries', 'countries', 'Countries'), ('/manage/tournaments', 'tournaments', 'Tournaments'), ('/manage/matches', 'matches', 'Matches'), ('/manage/leagues', 'leagues', 'Leagues')] -%} {% set active_page = active_page|default('main') -%}
This code block creates links, names, alternatives and also determines which page is active. Design also gives extreme importance to the dynamism. To create dynamic pages, design utilizes jQuery and JavaScript’s AJAX capabilities. All submit operations handled with an AJAX handler that written for operation-specific purposes. This will be discussed in later parts.
Configuration File¶
Configuration file hs been written in order to maintain simplicity when implementing other methods. All configuration methods has been stored in config.py file. It contains two methods one for parsing database parameters and another one is for creating a connection to database.
def db_connect(): # Connecting db by checking VCAP credentials. By courtesy of Turgut Hoca. # VCAP_SERVICES = os.getenv('VCAP_SERVICES') if VCAP_SERVICES is not None: dsn = get_elephantsql_dsn(VCAP_SERVICES) else: # Change this line according to your local db credentials # dsn = """user='postgres' password='password' host='localhost' port=5432 dbname='itucsdb1515'""" try: db_connection = connect(dsn) return db_connection except Error as error: print(error) return None
First this method checks for OS environment for environment variable called ‘’VCAP_SERVICES‘’. If this variable exists then it takes and parses the connection information from deployment server. If it is not exists then it works on localhost, thus it takes local information to connect the database.
REST API Skeleton¶
All operations have done through the REST API that has written from scratch. The power of REST API is flexibility. It
creates an abstract layer for all operations that needed to be done. By this way, without using any interface all operations
can be completed through API. Application’s user interface utilizes this ability and uses AJAX handlers for completing operations.
API can be accessible through /api
route. If user send request to the route http://localhost/api
the answer will be in
JSON format. All information in REST APIs are handled in JSON format. This makes it easier for AJAX handlers to understand data.
$ curl http://localhost:5000/api { "welcome_message": "Welcome to the DBall API v1.0" }Example API usage.
Even though application has user interface, it also serves as a REST server. User interface connects API through AJAX handlers which handles the data that came from inputs. It formats the data in JSON and passes data to API. Then API methods does operation from the data which has been taken from request and sends a respond. According to this respond AJAX handler either creates an error message or shows the changes.
$('#modal-submit-form').submit(function() { var user_data = { // User data in dictionary form }; $.ajax({ url: "/api/login", contentType: 'application/json', data: JSON.stringify(user_data), type: "POST", dataType : "json", success: function( json ) { if ( json.result ) { // Operation Success. } else { // Operation Failure } console.log( json ); }, error: function( ) { console.log( "TROUBLE!" ); } }); return false; });Skeleton for all AJAX handlers which has been used as a template on all AJAX handlers.
API can both pull and push information to the application. To pull information, users should use specific routes that has been designed for that record. Users can either pull information for specific ID or they can pull all the records that has been stored in database. All responses will be in JSON format. GET routes are only allows GET method. Thus if it encounters with a POST request it would give a 405 error.
$ curl http://localhost:5000/api/<record_name>/<id>
Example request for GET operation.
To complete add operation through API, user must be logged in. In other words, it should have a session in computer.
This prevents unauthorized users to alter records. After login operation user can add using /api/<record_name>/add
route to add new record to the system. It only accepts POST method.
$ curl -X POST -d "{...}" http://localhost:5000/api/<record_name>/addExample request for ADD operation.
Again to complete update operation user should be logged in. After logged in, user can use /api/<record_name>/update
route to update records that have been stored in database. It only accepts POST method.
$ curl -X POST -d "{...}" http://localhost:5000/api/<record_name>/updateExample request for UPDATE operation.
After login operation user can delete records on database from the route /api/<record_name>/delete
.
It only accepts POST method.
$ curl -X POST -d "{...}" http://localhost:5000/api/<record_name>/deleteExample request for DELETE operation.
User Login and Register System¶
Another ability of API is handling user operations for application. User system something that relies on Auth API a lot. It uses sessions in order to recognize user and store its data. Login operation can be done thorough either from user interface or through API. Further, add, delete and update operations need authorization to complete thorough API. On the other hand register operations only can be done through API.
class User(object): def __init__(self, user_alias=None, user_email=None, user_pass=None, is_admin=False, user_id=None): self.id = user_id self.alias = user_alias self.email = user_email if user_pass is not None: self.password_hash = bcrypt.encrypt(user_pass) else: self.password_hash = user_pass self.user_type = is_admin def get_user(self, email=None): pass def add_user_to_db(self): passClass hierarchy in User class.
User login is secure and critical process for users to alter records that have been stored in database. Since API is open, we had to require users to login before done any operation on records to prevent data persistence. When user tries to login through user interface data which user entered, gathered by AJAX and formatted into JSON notation. From here AJAX handler generates a request to the API. API gets JSON-formatted data and creates a respond again in JSON format. According to respond message AJAX handler either generates an error message or reloads the window.
def api_user_login(): # Get request header # json_user_data = request.get_json() # Get user object # user_info = user.User() user_info.get_user(json_user_data['user_email']) # Check user credentials # if user_info is not None and user_info.password_hash is not None: if bcrypt.verify(json_user_data['user_password'], user_info.password_hash) is True: # Create session for user # session['logged_in'] = True session['email'] = json_user_data['user_email'] session['alias'] = user_info.alias status = True else: status = False else: status = False return jsonify({'result': status})API method for user login.
API is heavily dependent on User class which has multiple methods for completing database operations. API method first creates an User class object. Then it gets data from database and compares entered password with stored salt. If they match it returns success message, otherwise error message.
$ curl -X POST -d '{"user_email":"test@test.com", "user_password":"ali"}' http://localhost:5000/api/loginExample request for user login operation through.
User registration has been only implemented in API level. From user interface there is not possible to register a new user.
When user creates and sends a request to API path, API generates a new User class object. Then it invokes add_user_to_db()
method to store record in database. Before it stores data to database, it encrypts user password with bcrypt key derivation
function to increase security.
def api_user_register(): # Get request header # json_user_info = request.json # Convert it into user # user_info = user.User( user_alias=json_user_info['alias'], user_email=json_user_info['user_email'], user_pass=json_user_info['user_password'] ) # Add user to database # status = user_info.add_user_to_db() return jsonify({'result': status})API method for user register.
"""INSERT INTO users (user_name, password_hash, user_email, is_admin) VALUES (%s, %s, %s, %s);"""SQL Query used to store user information to database.
$ curl -X POST -d '{"alias":"tester", "user_name":"test", "user_password":"ali"}' http://localhost:5000/api/registerExample request for user register operation through.
People Records¶
People records are again completed in the same way. Request generated by AJAX handler, comes into API. API parses request
gets data, and then it invokes add_to_db()
method to store record in database.
As in terms of database design, it has a foreign key in person_birth_place
column which is designated as city.
Also it has another foreign key to person_type
table. This table has only add operation and it makes possible user to
add and thus select an type of person such as players, coaches, sponsors etc.
class Person(object): def __init__(self, name=None, birth_date=None, birth_place=None, user_type=None, user_id=None): self.id = user_id self.name = name self.birth_date = birth_date self.birth_place = birth_place self.type = user_type def get_person_by_id(self, get_id=None): pass def add_to_db(self): pass def delete_from_db(self): pass def update_db(self): pass class PersonType(object): def __init__(self, type_name=None, type_id=None): self.id = type_id self.type = type_name def get_person_type(self, type_id=None): pass def add_to_db(self): passClass hierarchy for Person class.
Because of foreign keys, when getting person information JOIN
SQL operation has been used. Tables has been joined where
their keys has been intersect and data derived according to resulted table.
# Get person type # type_obj = people.PersonType() type_obj.get_person_type(type_id) # Create a dict # data = { 'id': type_obj.id, 'type': type_obj.type } return jsonify(data)API method for get operation
"""SELECT * FROM person JOIN city ON city.city_id = person.person_birth_location JOIN person_types ON person_types.id = person.person_type WHERE person_id = %s"""SQL query used for get operation.
Since person table has two foreign keys, thus before saving record into database it should have take foreign ids
from city_id
attribute from City table and id
attribute from person type table. After it got the city_id
and id
it can store data to database. It uses name attribute for both foreign keys as search point because it is unique.
def api_add_person(): # Prevent unauthorized access from API # if not session.get('logged_in'): return jsonify({"result": "Unauthorized Access. Please identify yourself"}) # Get json request from AJAX Handler # json_post_data = request.get_json() # print(json_post_data) # Create an person object # person_info = people.Person(json_post_data['person_name'], json_post_data['person_birth_date'], json_post_data['person_birth_place'], json_post_data['person_type']) # Add it to db and send result # result = person_info.add_to_db() if result: description = "Added " + json_post_data['person_name'] + " to Persons" log_info = log.Log(description, session['alias'], datetime.datetime.now()) log_status = log_info.add_to_db() return jsonify({'result': result})API method for person add operation.
"""SELECT id FROM person_types WHERE person_type_name = %s""" """SELECT city_id FROM city WHERE city_name = %s""" """INSERT INTO person(person_name, person_birth_date, person_birth_location, person_type) VALUES (%s, %s, %s, %s)"""SQL Queries used to store information to database.
Update operation is rather similar to add operation. After data passes from AJAX handler, API invokes update_db()
method.
def api_update_person(): # Get request from AJAX # json_data = request.get_json() # Get person from db # person_obj = people.Person() person_obj.get_person_by_id(json_data['person_id']) # Update person object's values # person_obj.name = json_data['person_name'] person_obj.birth_date = json_data['person_birth_date'] person_obj.birth_place = json_data['person_birth_place'] person_obj.type = json_data['person_type'] # Update db # result = person_obj.update_db() # Log operations # return jsonify({'result': result})API method for person update operation.
"""SELECT city_id FROM city WHERE city_name=%s""" """SELECT id FROM person_types WHERE person_type_name=%s""" """UPDATE person SET person_name=%s, person_birth_date=%s, person_birth_location=%s, person_type=%s WHERE person_id=%s"""SQL Queries used to update stored information on database.
Delete operation is relatively simple when comparing the other operations. API gets a list of ids that wanted to be deleted
from request and just invokes delete_from_db()
method for each.
def api_delete_person(): # Prevent unauthorized access # if not session.get('logged_in'): return jsonify({"result": "Unauthorized Access. Please identify yourself"}) status = False # Get request # person_id_json = request.get_json() # print(person_id_json) # Delete every requested id # for person_id in person_id_json: person_obj = people.Person() person_obj.get_person_by_id(person_id) # print(person_id) status = person_obj.delete_from_db() if status: description = "Deleted " + person_obj.name + " from Persons" log_info = log.Log(description, session['alias'], datetime.datetime.now()) log_status = log_info.add_to_db() return jsonify({'result': status})API method for person delete operation.
"""DELETE FROM person WHERE person_id = %s"""
SQL Query used to delete stored information from database.
Penalty Records¶
Penalty records table is relatively same as person table. It has again two foreign keys one for person and another for penalty type. Again user can add and select which types it wants but cannot delete or update it.
class Penalty(object): def __init__(self, given_person=None, given_date=None, penalty_type=None, penalty_id=None): self.id = penalty_id self.person = given_person self.given_date = given_date self.type = penalty_type def get_penalty_by_id(self, get_id=None): pass def add_to_db(self): pass def delete_from_db(self): pass def update_db(self): pass class PenaltyType(object): def __init__(self, type_name=None, type_id=None): self.id = type_id self.type = type_name def get_penalty_type(self, type_id=None): pass def add_to_db(self): passClass hierarchy for Penalty class.
Again JOIN
operation has been used for getting all data in same manner as people table.
def api_get_penalty(data_id): # Create empty penalty and fill it from db # penalty_obj = penalties.Penalty() penalty_obj.get_penalty_by_id(data_id) # Create a dict for jsonify # data = { 'id': penalty_obj.id, 'person': penalty_obj.person, 'given_date': penalty_obj.given_date.strftime('%d/%m/%Y'), 'penalty_type': penalty_obj.type } return jsonify(data)API method for get operation
"""SELECT * FROM penalty JOIN person ON penalty_given_person = person.person_id JOIN penalty_type ON penalty_type = penalty_type.id WHERE penalty_id = %s"""SQL query used for get operation.
Add operation also in same way as person table. But differently, this time it takes person id directly from user, thus no additional query is needed for penalty add operation.
def api_add_penalty(): # Prevent unauthorized access from API # if not session.get('logged_in'): return jsonify({"result": "Unauthorized Access. Please identify yourself"}) # Get json request from AJAX Handler # json_post_data = request.get_json() # print(json_post_data) # Create an penalty object # penalty_info = penalties.Penalty(json_post_data['person_name'], json_post_data['penalty_given_date'], json_post_data['penalty_type']) # Add it to db and send result # result = penalty_info.add_to_db() if result: log_person = people.Person().get_person_by_id(json_post_data['person_name']) description = "Added Penalty For " + log_person.name + " to Penalties" log_info = log.Log(description, session['alias'], datetime.datetime.now()) log_status = log_info.add_to_db() return jsonify({'result': result})API method for add operation.
"""SELECT id FROM penalty_type WHERE penalty_type_name = %s""" """INSERT INTO penalty(penalty_type, penalty_given_person, penalty_given_date) VALUES (%s, %s, %s)"""SQL Queries used to store information to database.
Again it is similar to add operation when updating record.
def api_update_penalty(): # Get request from AJAX # json_data = request.get_json() # Get penalty from db # penalty_obj = penalties.Penalty() penalty_obj.get_penalty_by_id(json_data['penalty_id']) # Update penalty object's values # penalty_obj.person = json_data['person_name'] penalty_obj.given_date = json_data['penalty_given_date'] penalty_obj.type = json_data['penalty_type'] # Update db # result = penalty_obj.update_db() if result: description = "Updated Element With id=" + json_data['penalty_id'] + " in Penalties" log_info = log.Log(description, session['alias'], datetime.datetime.now()) log_status = log_info.add_to_db() return jsonify({'result': result})API method for update operation.
"""SELECT id FROM penalty_type WHERE penalty_type_name=%s""" """UPDATE penalty SET penalty_given_date=%s, penalty_given_person=%s, penalty_type=%s WHERE penalty_id=%s"""SQL Queries used to update stored information on database.
As it was in person table, API invokes delete_from_db()
method to delete given ids.
def api_delete_penalty(): # Prevent unauthorized access # if not session.get('logged_in'): return jsonify({"result": "Unauthorized Access. Please identify yourself"}) status = False # Get request # penalty_id_json = request.get_json() # Delete every requested id # for penalty_id in penalty_id_json: penalty_obj = penalties.Penalty() penalty_obj.get_penalty_by_id(penalty_id) # print(penalty_id) status = penalty_obj.delete_from_db() if status: description = "Deleted Penalty For " + penalty_obj.person + " from Penalties" log_info = log.Log(description, session['alias'], datetime.datetime.now()) log_status = log_info.add_to_db() return jsonify({'result': status})API method for delete operation.
"""DELETE FROM penalty WHERE penalty_id = %s"""
SQL Query used to delete stored information from database.
Popularity Records¶
Popularity table one of the weakest relations in the database. It has three foreign keys to other tables for team, player and match and also an integer value for supporters.
class Popularity(object): def __init__(self, team=None, match=None, player=None, supporters=None, popularity_id=None): self.id = popularity_id self.team = team self.match = match self.player = player self.supporters = supporters def get_popularity_by_id(self, get_id=None): pass def add_to_db(self): pass def delete_from_db(self): pass def update_db(self): passClass hierarchy for Popularity class.
Again JOIN
operation has been used for getting all data in same manner as people table. But this time it as more joins.
def api_get_popularity(data_id): # Create empty popularity and fill it from db # popularity_obj = popularity.Popularity() popularity_obj.get_popularity_by_id(data_id) # Create a dict for jsonify # data = { 'id': popularity_obj.id, 'team': popularity_obj.team, 'match': popularity_obj.match, 'player': popularity_obj.player, 'supporters': popularity_obj.supporters } return jsonify(data)API method for get operation
"""SELECT * FROM popularity JOIN team AS team1 ON popularity.team_name = team1.team_id JOIN matches ON popularity.most_popular_match = matches.match_id JOIN team AS team2 ON matches.match_team_1 = team2.team_id JOIN team AS team3 ON matches.match_team_2 = team3.team_id JOIN person ON popularity.most_popular_player = person.person_id"""SQL query used for get operation.
In order to display multiple teams there has been multiple joins on teams used.
Add operation takes foreign key values directly from the user in order to optimize queries.
def api_add_popularity(): # Prevent unauthorized access from API # if not session.get('logged_in'): return jsonify({"result": "Unauthorized Access. Please identify yourself"}) # Get json request from AJAX Handler # json_post_data = request.get_json() # print(json_post_data) # Create an popularity object # popularity_info = popularity.Popularity(json_post_data['team'], json_post_data['match'], json_post_data['player'], json_post_data['supporters']) # Add it to db and send result # result = popularity_info.add_to_db() if result: description = "Added Popularity Info for " + json_post_data['team'] + " to Popularity" log_info = log.Log(description, session['alias'], datetime.datetime.now()) log_status = log_info.add_to_db() return jsonify({'result': result})API method for add operation.
"""INSERT INTO popularity(team_name, most_popular_match, most_popular_player, supporters) VALUES (%s, %s, %s, %s)"""SQL Queries used to store information to database.
Again it is similar to add operation when updating record.
def api_update_popularity(): # Get request from AJAX # json_data = request.get_json() # Get person from db # popularity_obj = popularity.Popularity() popularity_obj.get_popularity_by_id(json_data['popularity_id']) # Update person object's values # popularity_obj.team = json_data['team'] popularity_obj.match = json_data['match'] popularity_obj.player = json_data['player'] popularity_obj.supporters = json_data['supporters'] # Update db # result = popularity_obj.update_db() if result: description = "Updated Element With id=" + json_data['popularity_id'] + " in Popularity" log_info = log.Log(description, session['alias'], datetime.datetime.now()) log_status = log_info.add_to_db() return jsonify({'result': result})API method for update operation.
"""UPDATE popularity SET team_name=%s, most_popular_match=%s, most_popular_player=%s, supporters=%s WHERE popularity_id=%s"""SQL Query used to update stored information on database.
As it was in person table, API invokes delete_from_db()
method to delete given ids.
def api_delete_popularity(): # Prevent unauthorized access # if not session.get('logged_in'): return jsonify({"result": "Unauthorized Access. Please identify yourself"}) status = False # Get request # popularity_id_json = request.get_json() # Delete every requested id # for popularity_id in popularity_id_json: popularity_obj = popularity.Popularity() popularity_obj.get_popularity_by_id(popularity_id) # print(penalty_id) status = popularity_obj.delete_from_db() if status: description = "Deleted Popularity Info For " + popularity_obj.team + " from Penalties" log_info = log.Log(description, session['alias'], datetime.datetime.now()) log_status = log_info.add_to_db() return jsonify({'result': status})API method for delete operation.
"""DELETE FROM popularity WHERE popularity_id = %s"""
SQL Query used to delete stored information from database.
City Records¶
City table does not contain any foreign key. It uses Google Maps Geocode API in order to store location information.
class City(object): def __init__(self, city_name=None, city_population=None, city_coordinates=None, city_id=None): self.id = city_id self.name = city_name self.coordinates = city_coordinates self.population = city_population def get_city_by_id(self, get_id=None): pass def add_to_db(self): pass def delete_from_db(self): pass def update_db(self): passClass hierarchy for City class.
Get operation is simple for city table. There is no joins since it does not have any foreign key.
def api_get_city(city_id): # Create empty city and fill it from db # city_obj = cities.City() city_obj.get_city_by_id(city_id) # Create a dict for jsonify # data = { 'id': city_obj.id, 'city_name': city_obj.name, 'city_coordinates': city_obj.name, 'city_population': city_obj.name } return jsonify(data)API method for get operation
"""SELECT * FROM city WHERE city_id = %s"""
SQL Queries used for get operation
Add operation get city nme and population as input, then sends city name to Maps API and gets geolocation to store.
def api_add_city(): # Prevent unauthorized access # if not session.get('logged_in'): return jsonify({"result": "Unauthorized Access. Please identify yourself"}) # Get request # json_post_data = request.get_json() # print(json_post_data) city_info = cities.City(json_post_data['city_name'], json_post_data['city_population']) # Add it to db # result = city_info.add_to_db() if result: description = "Added " + json_post_data['city_name'] + " to Cities" log_info = log.Log(description, session['alias'], datetime.datetime.now()) log_status = log_info.add_to_db() return jsonify({'result': result})API method for add operation
"""INSERT INTO city (city_name, city_population, city_coordinates) VALUES (%s, %s, %s)"""SQL Queries used for add operation
- Again update operation also does same thing as ha been done in add operation.
def api_update_city(): # Get request from AJAX # json_data = request.get_json() # Get city from db # city_obj = cities.City() city_obj.get_city_by_id(json_data['city_id']) # Update city object's values # city_obj.name = json_data['city_name'] city_obj.population = json_data['city_population'] # Update db # result = city_obj.update_db() if result: description = "Updated Element With id=" + json_data['city_id'] + " in Cities" log_info = log.Log(description, session['alias'], datetime.datetime.now()) log_status = log_info.add_to_db() return jsonify({'result': result})
API method for update operation
"""UPDATE city SET city_name=%s, city_population=%s, city_coordinates=%s WHERE city_id=%s"""
SQL Queries used for update operation
Delete operation directly deletes data from database.
def api_delete_city(): # Prevent unauthorized access # if not session.get('logged_in'): return jsonify({"result": "Unauthorized Access. Please identify yourself"}) status = False # Get request # city_id_json = request.get_json() for city_id in city_id_json: city_obj = cities.City() city_obj.get_city_by_id(city_id) status = city_obj.delete_from_db() if status: description = "Deleted " + city_obj.name + " from Cities" log_info = log.Log(description, session['alias'], datetime.datetime.now()) log_status = log_info.add_to_db() return jsonify({'result': status})API method for delete operation
"""DELETE FROM city WHERE city_id = %s"""
SQL Queries used for delete operation
Parts Implemented by Umut Can Ozyar¶
Sponsorships¶
All the sponsorships data interaction with the database happens with queries send to the server from the objects created by the sponsorship class. This table has three foreign keys, sponsorship_league, sponsorship_team and sponsorship_person, which refers to leagues, teams and people table respectively. Id is in type serial, therefore it’s generated automatically, with each new entry. The rest of the fields requires new user input.
class Sponsorship(object):
def __init__(self, sponsorship_name=None, sponsorship_start_date=None, sponsorship_league=None,
sponsorship_team=None, sponsorship_person=None, sponsorship_id=None):
self.id = sponsorship_id
self.name = sponsorship_name
self.start_date = sponsorship_start_date
self.league = sponsorship_league
self.team = sponsorship_team
self.person = sponsorship_person
This operation is the most essential one as it’s used for several key actions. Either by sending an id to get a specific tuple or to get the whole table get_sponsorshop_by_id method is called by the API. Then the SELECT queries found below, will be called with the only difference of WHERE sponsorship_id = %s which indicates that a unique id is specified. Three different OUTER JOIN operations are made to get the league, team and person names by joining these tables over their ids.
@app.route('/api/sponsorship/<int:data_id>', methods=['GET'])
def api_get_sponsorship(data_id):
# Create empty sponsorship and fill it from db #
sponsorship_obj = sponsorships.Sponsorship()
sponsorship_obj.get_sponsorship_by_id(data_id)
# Create a dict for jsonify #
data = {
'id': sponsorship_obj.id,
'name': sponsorship_obj.name,
'start_date': sponsorship_obj.start_date.strftime('%d/%m/%Y'),
'league': sponsorship_obj.league,
'team': sponsorship_obj.team,
'person': sponsorship_obj.person
}
return jsonify(data)
def get_sponsorship_by_id(self, get_id=None):
connection = db_connect()
cursor = connection.cursor()
if get_id is not None:
statement = """SELECT sponsorship.sponsorship_id, sponsorship.sponsorship_name, sponsorship.sponsorship_start_date,
sponsorship.sponsorship_league, sponsorship.sponsorship_team, sponsorship.sponsorship_person,
person.person_name FROM sponsorship
LEFT OUTER JOIN league ON league.league_id = sponsorship.sponsorship_league
LEFT OUTER JOIN team ON team.team_id = sponsorship.sponsorship_team
LEFT OUTER JOIN person ON person.person_id = sponsorship.sponsorship_person
WHERE sponsorship_id = %s"""
try:
cursor.execute(statement, (get_id,))
connection.commit()
except connection.Error:
connection.rollback()
data = cursor.fetchone()
if data is not None:
self.id = data[0]
self.name = data[1]
self.start_date = data[2]
self.league = data[3]
self.team = data[4]
self.person = data[5]
cursor.close()
connection.close()
return self
else:
cursor.close()
connection.close()
return None
else:
statement = """SELECT sponsorship.sponsorship_id, sponsorship.sponsorship_name,
sponsorship.sponsorship_start_date, sponsorship.sponsorship_league,
sponsorship.sponsorship_team, sponsorship.sponsorship_person,
league.league_id, league.league_name,
team.team_id, team.team_name,
person.person_id, person.person_name FROM sponsorship
LEFT OUTER JOIN league ON league.league_id = sponsorship.sponsorship_league
LEFT OUTER JOIN team ON team.team_id = sponsorship.sponsorship_team
LEFT OUTER JOIN person ON person.person_id = sponsorship.sponsorship_person"""
try:
cursor.execute(statement, (get_id,))
connection.commit()
except connection.Error:
connection.rollback()
sponsorship_array = []
data = cursor.fetchall()
for sponsorship in data:
sponsorship_array.append(
{
'id': sponsorship[0],
'name': sponsorship[1],
'start_date': sponsorship[2].strftime('%d/%m/%Y'),
'league': sponsorship[7],
'team': sponsorship[9],
'person': sponsorship[11]
}
)
cursor.close()
connection.close()
return sponsorship_array
After the forms on the modal for adding sponsorship are submitted, first the authorization process is made for the user by the API. If the authorization is successful, the API gets the json request from the AJAX handler. This data is then used to create a sponsorship object by calling the sponsorship constructor. Then add_to_db function is called on this object to perform the insertion query for sponsorship that can be found below. Note that the INSERT query is called by using foreign keys to league, team and person tables ids. Thus their ids should be fetched by using provided names.
@app.route('/api/sponsorship/add', methods=['POST'])
def api_add_sponsorship():
# Prevent unauthorized access from API #
if not session.get('logged_in'):
return jsonify({"result": "Unauthorized Access. Please identify yourself"})
# Get json request from AJAX Handler #
json_post_data = request.get_json()
# print(json_post_data)
# Create a sponsor object #
sponsorship_info = sponsorships.Sponsorship(json_post_data['sponsorship_name'],
json_post_data['sponsorship_start_date'],
json_post_data['sponsorship_league'],
json_post_data['sponsorship_team'],
json_post_data['sponsorship_person'])
# Add it to db and send result #
result = sponsorship_info.add_to_db()
if result:
description = "Added " + json_post_data['sponsorship_name'] + " to Sponsorships"
log_info = log.Log(description, session['alias'], datetime.datetime.now())
log_status = log_info.add_to_db()
return jsonify({'result': result})
def add_to_db(self):
connection = db_connect()
cursor = connection.cursor()
new_league = None
new_team = None
new_person = None
select_league = """SELECT league_id FROM league WHERE league_name = %s"""
select_team = """SELECT team_id FROM team WHERE team_name = %s"""
select_person = """SELECT person_id FROM person WHERE person_name = %s"""
statement = """INSERT INTO sponsorship (sponsorship_name, sponsorship_start_date,
sponsorship_league, sponsorship_team, sponsorship_person )
VALUES (%s, %s, %s, %s, %s)"""
try:
cursor.execute(select_league, (self.league,))
connection.commit()
new_league = cursor.fetchone()
cursor.execute(select_team, (self.team,))
connection.commit()
new_team = cursor.fetchone()
cursor.execute(select_person, (self.person,))
connection.commit()
new_person = cursor.fetchone()
cursor.execute(statement, (self.name, self.start_date, new_league, new_team, new_person))
connection.commit()
status = True
except connection.Error:
connection.rollback()
status = False
cursor.close()
connection.close()
return status
Delete operation is a single DELETE query. delete_from_db function is called after the id of the selected rows’ data is fetched and corresponding objects are found.
@app.route('/api/sponsorship/delete', methods=['POST'])
def api_delete_sponsorship():
# Prevent unauthorized access #
if not session.get('logged_in'):
return jsonify({"result": "Unauthorized Access. Please identify yourself"})
status = False
# Get request #
sponsorship_id_json = request.get_json()
# print(sponsorship_id_json)
# Delete every requested id #
for sponsorship_id in sponsorship_id_json:
sponsorship_obj = sponsorships.Sponsorship()
sponsorship_obj.get_sponsorship_by_id(sponsorship_id)
status = sponsorship_obj.delete_from_db()
if status:
description = "Deleted " + sponsorship_obj.name + " from Sponsorships"
log_info = log.Log(description, session['alias'], datetime.datetime.now())
log_status = log_info.add_to_db()
return jsonify({'result': status})
def delete_from_db(self):
connection = db_connect()
cursor = connection.cursor()
statement = """DELETE FROM sponsorship WHERE sponsorship_id = %s"""
try:
cursor.execute(statement, (self.id,))
connection.commit()
status = True
except connection.Error:
connection.rollback()
status = False
cursor.close()
connection.close()
return status
Update operation works similar to the add operation except the fact that there is existing data. The AJAX handler provides the data to the API which assigns them to corresponding data members. Finally the UPDATE query is executed to apply the changes to the database
@app.route('/api/sponsorship/update', methods=['POST'])
def api_update_sponsorship():
# Get request from AJAX #
json_data = request.get_json()
# Get sponsorship from db #
sponsorship_obj = sponsorships.Sponsorship()
sponsorship_obj.get_sponsorship_by_id(json_data['sponsorship_id'])
# Update sponsorship object's values #
sponsorship_obj.name = json_data['sponsorship_name']
sponsorship_obj.start_date = json_data['sponsorship_start_date']
sponsorship_obj.league = json_data['sponsorship_league']
sponsorship_obj.team = json_data['sponsorship_team']
sponsorship_obj.person = json_data['sponsorship_person']
# Update db #
result = sponsorship_obj.update_db()
if result:
description = "Updated element with id=" + json_data['sponsorship_id'] + " in Sponsorships"
log_info = log.Log(description, session['alias'], datetime.datetime.now())
log_status = log_info.add_to_db()
return jsonify({'result': result})
def update_db(self):
connection = db_connect()
cursor = connection.cursor()
status = False
new_league = None
new_team = None
new_person = None
select_league = """SELECT league_id FROM league WHERE league_name = %s"""
select_team = """SELECT team_id FROM team WHERE team_name = %s"""
select_person = """SELECT person_id FROM person WHERE person_name = %s"""
statement = """UPDATE sponsorship
SET sponsorship_name=%s, sponsorship_start_date=%s, sponsorship_league=%s,
sponsorship_team=%s, sponsorship_person=%s
WHERE sponsorship_id=%s"""
try:
cursor.execute(select_league, (self.league,))
connection.commit()
new_league = cursor.fetchone()
cursor.execute(select_team, (self.team,))
connection.commit()
new_team = cursor.fetchone()
cursor.execute(select_person, (self.person,))
connection.commit()
new_person = cursor.fetchone()
cursor.execute(statement, (self.name, self.start_date, new_league, new_team, new_person, self.id))
connection.commit()
status = True
except connection.Error:
connection.rollback()
status = False
cursor.close()
connection.close()
return status
Team Statistics¶
Team statistics class functions are mostly given as prototypes except for their queries and class data members as they are constructed in a relatively simple manner. The API functions are also omitted for the sake of simplicity since the only meaningful difference is the table names.
Team_stat table also has an id as its primary key. The rest of the data members are all in integer type and required to be provided by the user.
class Team_stat(object):
def __init__(self, team_stat_name=None, team_stat_run=None, team_stat_hit=None,
team_stat_save=None, team_stat_win=None, team_stat_draw=None,
team_stat_loss=None, team_stat_id=None):
self.id = team_stat_id
self.name = team_stat_name
self.run = team_stat_run
self.hit = team_stat_hit
self.save = team_stat_save
self.win = team_stat_win
self.draw = team_stat_draw
self.loss = team_stat_loss
def get_team_stat_by_id():
def add_to_db():
def delete_from_db():
def update_db():
Please refer to Sponsorships for examples of the omitted parts of the team statistics class and API functions.
Fetching a team’s statistics is done when def get_team_stat_by_id function is called by the API which executes the following query. It’s a select query that gets the only tuple from the database for the provided id since all ids are unique.
statement = """SELECT team_stat.team_stat_id, team_stat.team_stat_name, team_stat.team_stat_run,
team_stat.team_stat_hit, team_stat.team_stat_save, team_stat.team_stat_win,
team_stat.team_stat_draw, team_stat.team_stat_loss
FROM team_stat
WHERE team_stat_id = %s"""
Adding team statistics can be cumbersome since the matches data is not structured taking total wins, draws and losses into consideration. Therefore a few SELECT queries should be executed prior to the main insertion query. Extra queries for draws and losses as well as the foreign key related queries are omitted for the sake of simplicity. The different tables are counted to get home and away wins. These values are then summed before inserted into the table. Draws and losses are calculated in the same manner. Each team’s total matches are also counted with a simple SELECT count query.
count_win1 = """SELECT COUNT(*) FROM matches
LEFT OUTER JOIN team ON team.team_id = matches.match_team_1
WHERE (matches.match_team1_score > matches.match_team2_score AND team.team_name = %s)
GROUP BY team.team_name"""
count_win2 = """SELECT COUNT(*) FROM matches
LEFT OUTER JOIN team ON team.team_id = matches.match_team_2
WHERE (matches.match_team1_score < matches.match_team2_score AND team.team_name = %s)
GROUP BY team.team_name"""
total_wins = count_win1 + count_win2
statement = """INSERT INTO team_stat (team_stat_name, team_stat_run,
team_stat_hit, team_stat_save, team_stat_win,
team_stat_draw, team_stat_loss )
VALUES (%s, %s, %s, %s, %s, %s, %s)"""
count_matches = """SELECT count(match_id) FROM matches"""
Deletion is a simple operation which is executed after getting the ids of the selected rows from the table.
statement = """DELETE FROM team_stat WHERE team_stat_id = %s"""
Update also has several extra queries like the add function which calculates total wins, draws and losses. Runs, hits and saves fields can also be updated when provided with new data.
statement = """UPDATE team_stat
SET team_stat_name=%s, team_stat_run=%s, team_stat_hit=%s, team_stat_save=%s,
team_stat_win=%s, team_stat_draw=%s, team_stat_loss=%s
WHERE team_stat_id=%s"""
Stadiums¶
Stadiums class functions are mostly given as prototypes except for their queries and class data members as they are constructed in a relatively simple manner with the sponsorship class. The API functions are also omitted for the sake of simplicity since the only meaningful difference is the table names.
Stadium table also has an id as its primary key. The rest of the data members are all in integer type and required to be provided by the user. Location is a foreign key to the city_id column of the city table. Another foreign key is stadium_team which points to the team table.
class Stadium(object):
def __init__(self, stadium_name=None, stadium_team=None, stadium_location=None,
stadium_capacity=None, stadium_id=None):
self.id = stadium_id
self.name = stadium_name
self.team = stadium_team
self.location = stadium_location
self.capacity = stadium_capacity
def get_team_stat_by_id():
def add_to_db():
def delete_from_db():
def update_db():
Please refer to Sponsorships for examples of the omitted parts of the stadium class and API functions.
Fetching a team’s stadium is done when def get_stadium_by_id function is called by the API which executes the following query. It’s a select query that gets the only tuple from the database for the provided id since all ids are unique.
statement = """SELECT stadium.stadium_id, stadium.stadium_name, stadium.stadium_team,
stadium.stadium_location, stadium.stadium_capacity,
team.team_id, team.team_name,
city.city_id, city.city_name
FROM stadium
LEFT OUTER JOIN team ON team.team_id = stadium.stadium_team
LEFT OUTER JOIN city ON city.city_id = stadium.stadium_location
WHERE stadium_id = %s"""
There are only two foreign keys for stadium table which are teams and locations. Id is automatically generated for each new entry therefore the rest of the fields like name and capacity should be provided by the user. After the API gets the data from the AJAX handler add_to_db function of the stadium is called which executes the following query to add the new stadium to the database.
statement = """INSERT INTO stadium (stadium_name, stadium_team,
stadium_location, stadium_capacity )
VALUES (%s, %s, %s, %s)"""
Deletion is just a single query which is executed after getting the ids of the selected rows from the table.
statement = """DELETE FROM stadium WHERE stadium_id = %s"""
After selecting the correct team_id for the chosen team and city_id for the chosen city name, all the inputs are passed to the UPDATE query which applies the changes to the database.
statement = """UPDATE stadium
SET stadium_name=%s, stadium_team=%s, stadium_location=%s, stadium_capacity=%s
WHERE stadium_id=%s"""
Parts Implemented by Mert Şeker¶
Database Operations for Each Entity¶
For each database operations of entities, appropriate SQL queries are written and they are executed within the functions in the .py class files.
Team tuples have three columns; id, name and coach. Coach is a foreign key to the person table.
Get Team By Id¶
In order to get teams and use them in functions, the primary key(team_id) is used. A dictionary is created with the chosen team’s data and it is returned. You can see how this operation is done in the code below:
def get_team_by_id(self, get_id=None): connection = db_connect() cursor = connection.cursor() if get_id is not None: query = """SELECT t.team_id, t.team_name, t.team_couch,person.person_name FROM team AS t LEFT OUTER JOIN person ON person.person_id = t.team_couch WHERE team_id = %s""" try: cursor.execute(query, (get_id,)) connection.commit() data = cursor.fetchone() if data is not None: self.id = data[0] self.name = data[1] self.couch = data[2] cursor.close() connection.close() return self else: cursor.close() connection.close() return None except connection.Error as error: print(error) connection.rollback() else: query = """SELECT team.team_id, team.team_name,team.team_couch,person.person_id,person.person_name FROM team LEFT OUTER JOIN person ON person.person_id = team.team_couch""" try: cursor.execute(query, (get_id,)) connection.commit() array = [] data = cursor.fetchall() for team in data: array.append( { 'id': team[0], 'name': team[1], 'couch': team[4] } ) cursor.close() connection.close() return array except connection.Error as error: print(error) connection.rollback()
Add Team To Database¶
In order to add team tuples to the database, INSERT INTO queries are used and executed. The foreign keys are selected from the referenced tables by id.You can see it in the code below:
def add_to_db(self): connection = db_connect() cursor = connection.cursor() select_person = """SELECT person_id FROM person WHERE person_name = %s""" # query to add given team tuple to database query = """INSERT INTO team (team_name, team_couch) VALUES (%s, %s)""" try: cursor.execute(select_person, (self.couch,)) connection.commit() new_person = cursor.fetchone() cursor.execute(query, (self.name, new_person)) connection.commit() status = True except connection.Error as error: print(error) connection.rollback() status = False cursor.close() connection.close() return status
Delete Team From Database¶
The team to be deleted is selected by id and deleted by using DELETE FROM query. You can see it in the code below:
def delete_from_db(self): connection = db_connect() cursor = connection.cursor() query = """DELETE FROM team WHERE team_id = %s""" try: cursor.execute(query, (self.id,)) connection.commit() status = True except connection.Error as error: print(error) connection.rollback() status = False cursor.close() connection.close() return status
Update Team¶
The team to be updated is selected by id and updated by the UPDATE query. Just like in add operation,the foreign keys are selected from the referenced table by id. You can see it in the code below:
def update_db(self): connection = db_connect() cursor = connection.cursor() select_person = """SELECT person_id FROM person WHERE person_name = %s""" query = """UPDATE team SET team_name=%s, team_couch=%s WHERE team_id=%s""" try: cursor.execute(select_person, (self.couch,)) connection.commit() person_id = cursor.fetchone() cursor.execute(query, (self.name, person_id, self.id)) connection.commit() status = True except connection.Error as error: print(error) connection.rollback() status = False cursor.close() connection.close() return status
Player tuples have four columns; id,name, team and number of goals. Team is a foreign key to the teams table.
Get Player By Id¶
In order to get players and use them in functions, the primary key(player_id) is used. A dictionary is created with the chosen player’s data and it is returned. You can see how this operation is done in the code below:
def get_player_by_id(self, get_id=None): connection = db_connect() cursor = connection.cursor() if get_id is not None: query = """SELECT * FROM player JOIN team ON team.team_id = player.player_team WHERE player_id = %s""" try: cursor.execute(query, (get_id,)) connection.commit() data = cursor.fetchone() if data is not None: self.id = data[0] self.name = data[1] self.goals = data[3] self.team = data[5] cursor.close() connection.close() return self else: cursor.close() connection.close() return None except connection.Error as error: print(error) connection.rollback() else: query = """SELECT * FROM player JOIN team ON team.team_id = player.player_team""" try: cursor.execute(query) connection.commit() except connection.Error as error: print(error) connection.rollback() array = [] data = cursor.fetchall() for player in data: array.append( { 'id': player[0], 'name': player[1], 'goals': player[3], 'team': player[5] } ) print(array) cursor.close() connection.close() return array
Add Player To Database¶
In order to add player tuples to the database, INSERT INTO queries are used and executed. The foreign keys are selected from the referenced tables by id.You can see it in the code below:
def add_to_db(self): connection = db_connect() cursor = connection.cursor() # query to get referenced team by its id query_team = """SELECT team_id FROM team WHERE team_name = %s""" # query to add given player tuple to database query = """INSERT INTO player (player_name, player_team, player_goals) VALUES (%s, %s, %s)""" try: cursor.execute(query_team, (self.team,)) connection.commit() team_id = cursor.fetchone() cursor.execute(query, (self.name, team_id, self.goals,)) connection.commit() status = True except connection.Error as error: print(error) connection.rollback() status = False cursor.close() connection.close() return status
Delete Player From Database¶
The player to be deleted is selected by id and deleted by using DELETE FROM query. You can see it in the code below:
def delete_from_db(self): connection = db_connect() cursor = connection.cursor() query = """DELETE FROM player WHERE player_id = %s""" try: cursor.execute(query, (self.id, )) connection.commit() status = True except connection.Error as error: print(error) connection.rollback() status = False cursor.close() connection.close() return status
Update Player¶
The player to be updated is selected by id and updated by the UPDATE query. Just like in add operation,the foreign keys are selected from the referenced table by id. You can see it in the code below:
def update_db(self): connection = db_connect() cursor = connection.cursor() query_team = """SELECT team_id FROM team WHERE team_name=%s""" query = """UPDATE player SET player_name=%s, player_team=%s, player_goals=%s WHERE player_id=%s""" try: cursor.execute(query_team, (self.team, )) connection.commit() team_id = cursor.fetchone() cursor.execute(query, (self.name, team_id, self.goals, self.id,)) connection.commit() status = True except connection.Error as error: print(error) connection.rollback() status = False finally: cursor.close() connection.close() return status
Tournament tuples have seven columns; id,name,number of matches,start date,end date,country and prize. Country is a foreign key to the countries table.
Get Tournament By Id¶
In order to get tournaments and use them in functions, the primary key(tournament_id) is used. A dictionary is created with the chosen tournament’s data and it is returned. You can see how this operation is done in the code below:
def get_tournament_by_id(self, get_id=None): connection = db_connect() cursor = connection.cursor() if get_id is not None: query = """SELECT * FROM tournament JOIN country ON country.country_id = tournament.tournament_country WHERE tournament_id = %s""" try: cursor.execute(query, (get_id,)) connection.commit() data = cursor.fetchone() if data is not None: self.id = data[0] self.name = data[1] self.matches = data[2] self.start_date = data[3] self.end_date = data[4] self.country = data[8] self.prize = data[6] cursor.close() connection.close() return self else: cursor.close() connection.close() return None except connection.Error as error: print(error) connection.rollback() else: query = """SELECT * FROM tournament JOIN country ON country.country_id = tournament.tournament_country""" try: cursor.execute(query) connection.commit() except connection.Error as error: print(error) connection.rollback() array = [] data = cursor.fetchall() for tournament in data: array.append( { 'id': tournament[0], 'name': tournament[1], 'matches': tournament[2], 'start_date': tournament[3].strftime('%d/%m/%Y'), 'end_date': tournament[4].strftime('%d/%m/%Y'), 'country': tournament[8], 'prize': tournament[6] } ) cursor.close() connection.close() return array
Add Tournament To Database¶
In order to add tournament tuples to the database, INSERT INTO queries are used and executed. The foreign keys are selected from the referenced tables by id.You can see it in the code below:
def add_to_db(self): connection = db_connect() cursor = connection.cursor() # query to get referenced country by its id query_country = """SELECT country_id FROM country WHERE country_name = %s""" # query to add given tournament tuple to database query = """INSERT INTO tournament (tournament_name, tournament_matches, tournament_start_date, tournament_end_date, tournament_country, tournament_prize) VALUES (%s, %s, %s, %s, %s, %s)""" try: cursor.execute(query_country, (self.country,)) connection.commit() country_id = cursor.fetchone() cursor.execute(query, (self.name, self.matches, self.start_date, self.end_date, country_id, self.prize)) connection.commit() status = True except connection.Error as error: print(error) connection.rollback() status = False cursor.close() connection.close() return status
Delete Tournament From Database¶
The tournament to be deleted is selected by id and deleted by using DELETE FROM query. You can see it in the code below:
def delete_from_db(self): connection = db_connect() cursor = connection.cursor() query = """DELETE FROM tournament WHERE tournament_id = %s""" try: cursor.execute(query, (self.id, )) connection.commit() status = True except connection.Error as error: print(error) connection.rollback() status = False cursor.close() connection.close() return status
Update Tournament¶
The tournament to be updated is selected by id and updated by the UPDATE query. Just like in add operation,the foreign keys are selected from the referenced table by id. You can see it in the code below:
def update_db(self): connection = db_connect() cursor = connection.cursor() query_country = """SELECT country_id FROM country WHERE country_name=%s""" query = """UPDATE tournament SET tournament_name=%s, tournament_matches=%s, tournament_start_date=%s, tournament_end_date=%s, tournament_country=%s, tournament_prize=%s WHERE tournament_id=%s""" try: cursor.execute(query_country, (self.country, )) connection.commit() country_id = cursor.fetchone() cursor.execute(query, (self.name, self.matches, self.start_date, self.end_date, country_id, self.prize, self.id,)) connection.commit() status = True except connection.Error as error: print(error) connection.rollback() status = False finally: cursor.close() connection.close() return status
Parts Implemented by Furkan Akgün¶
Change Log¶
We created log class to be able to track user activities and also debug the site when a problem occurs. Log class simply consists of three major columns excluding id; first is the description and generated right after an operation is performed, second is the user logged in when given operation performed , this way we are able to track any user activites, and finally third one is the date of operation.
![]()
Log Properties
Inside log class, we have three functions; retrieve a log by passing an id or retrieve all without passing an id, adding log data to database and deleting log data from the database. Now we will cover these three functions respectively.
To be able to show logs in home screen or manager main screen we needed to add them to the database. To add log data to the database, we simply created an object and then set its properties. After an instance of object have all properties set, we simply call add_to_db() function. This function basically use insert query, the variables in query are the properties of this log instance.
![]()
Function to Add Logs to Database
In log class, one of the properties was user or author and it is a foreign key to the user table. But we were setting author or user by its name, so to get user’s id with that name we needed to run a query first to find user id.
If instance of log class have all properties set to appropriate values then the function will add log to the database.
To show all logs or some logs in the front view, we needed a function to return all log data or just a single one with given id. get_log_by_id(get_id) function simply takes an id parameter; if the id is none (or no parameter entered), the query will be executed with no specific id parameter and all logs will be returned from query and all will be stored in an array. Thne the function will just simply return that array.
![]()
Function to Retrieve All Logs
On the other hand if an id value is entered as a parameter, then the query will be executed with “WHERE id=get_id” and only the log with specific id will be returned.
![]()
Function to Retrieve A Log
Deleting a log is not implemented in front view, but is ready in class as a function. Simply we get referenced instance of log and then call delete_from_db() function.
![]()
Function to Delete a Log From the Database
Logs are instantly created when user performs an operation in the database. It is generic in all parts of operations, a description is created right after the operation and a log instance is created with this description, user and date. After that add_to_db() function on that log instance is called and log is added to the database.
![]()
Generating a Log After an Operation
As you can see right before function is completed a description is created given the operation. Simply “Added”, “Updated” or “Deleted” expressions are used for all operations. Here user is passed to the object constructor as session[‘alias’].
After we have a function to get all logs, it was too easy to select only last five of logs sorted by date. In query of selecting all logs we did already sorted logs in descended by date column. So it is now reduced only to chose first five rows returned from SELECT statement.
![]()
Choosing Last Five Changes
Only five log data are stored in array, and then array is sent to the home page. In home page we can now simply display them with a for loop.
![]()
Displaying Last Five Changes
Just like displaying last five logs, but now there is no need to use a constraint. We simply retrieve all data and store them in an array. Then send the array to manager main page as data.
![]()
Choose All Logs
Then simply display each of them by a for loop.
![]()
Displaying All Logs
All classes have same function bodies. They differ with only the queries they have. So to reduce explanation for each of them, I will show generic function bodies.
First is add_to_db() Function,
![]()
Generic Add Function
All classes share these bodies, only difference is queries. Another thing is just like in the above example some class properties are set with name values but we instead use id values for them. So first we must call another queries to get their ids. Then simply execute operational query.
update_db() Function,
![]()
Generic Update Function
delete_from_db() Function,
![]()
Generic Delete Function
get_(classname)_by_id() Function,
![]()
Generic Retrieve
Functions up to now were only class operations. Each class have four functions above. Next functions are for add, delete, and update operations done in website. These operation are again same for other classes except some extra operations for getting referenced objects.
Add Operation,
![]()
Generic Add Operation
As can be seen above, add operation creates an instance of class with json data provided by forms. After an instance is created that objects is added to the database. After a log will created for this given operation and the operation ends.
Delete Operation,
![]()
Generic Delete Operation
In delete operation we get all selected item ids in an array, then in a for loop we delete all selected items.
Update Operation,
![]()
Generic Update Operation
Just like in the add operation we get json data from forms and instead creating a new entry, we set properties of this instance to what we get from the forms and then update the item.
Country¶
Country object has four properties; id, name, capital and population. Capital is a foreign key to the cities table.
We have already provided bodies of all the functions. Those bodies were all same for all classes. What makes each class different are their unique queries for operations. These queries are executed in those functions and we complete what we try to accomplish.
![]()
Country Insert Into Query
In above queries, first is used to get id of the referenced capital, and then all properties of class are used as parameters to add this instance to the database.
![]()
Country Select Query
In case we pass no parameter to get_country_by_id() function, the query with no “WHERE” clause will be used. Above query is used when we pass an id parameter.
![]()
Country Update Query
Just like in the add operation queries excluding update query gets referenced item ids and then use them as parameter in the update query.
Matches¶
Match object has nine properties; id, home team, score of home team, away team, score of away team, stadium, referee, league and match date. Team, stadium, referee and league are all foreign keys.
We have already provided bodies of all the functions. Those bodies were all same for all classes. What makes each class different are their unique queries for operations. These queries are executed in those functions and we complete what we try to accomplish.
![]()
Match Insert Into Query
In above queries, queries except the last one are used to get ids of the referenced items, and then all properties of class are used as parameters to add this instance to the database.
![]()
Match Select Query
In case we pass no parameter to get_match_by_id() function, the query with no “WHERE” clause will be used. Above query is used when we pass an id parameter.
![]()
Match Update Query
Just like in the add operation queries excluding update query gets referenced item ids and then use them as parameter in the update query.
League¶
League object has four properties; id, name, country and start date. Country is a foreign key to the country table.
We have already provided bodies of all the functions. Those bodies were all same for all classes. What makes each class different are their unique queries for operations. These queries are executed in those functions and we complete what we try to accomplish.
![]()
League Insert Into Query
In above queries, first is used to get id of the referenced country, and then all properties of class are used as parameters to add this instance to the database.
![]()
League Select Query
In case we pass no parameter to get_league_by_id() function, the query with no “WHERE” clause will be used. Above query is used when we pass an id parameter.
![]()
League Update Query
Just like in the add operation queries excluding update query gets referenced item ids and then use them as parameter in the update query.