NBA player recommendation system based on Flask

Function screenshot

register

Log in

Home page

Search players

Compare players

Player data


Part of the code

forms.py

from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, BooleanField, SubmitField, SelectMultipleField
from wtforms.validators import DataRequired, Length, Email, EqualTo


class LoginForm(FlaskForm):
    username = StringField('Username', validators=[DataRequired(), Length(8, 16)])
    password = PasswordField('Password', validators=[DataRequired(), Length(8, 16)])
    submit = SubmitField('Log in')


class RegisterForm(FlaskForm):
    username = StringField("username", validators=[Length(min=7, max=20), DataRequired()])
    email = StringField("email", validators=[Email()])
    password = PasswordField("password", validators=[DataRequired(), EqualTo(fieldname="confirm", message="Passwords are inconsistent!")])
    confirm = PasswordField("confirm password", validators=[DataRequired()])
    submit = SubmitField('register')

class RecommendForm(FlaskForm):
    tags = SelectMultipleField(
        label='label', choices=[('Potential to be tapped', 'Potential to be tapped'), ('Super scorer', 'Super scorer'), ('Offensive kaleidoscope', 'Offensive kaleidoscope'),
                               ('basket scorer', 'basket scorer'), ('offensive organizer', 'offensive organizer'), ('outside blocker', 'outside blocker'),
                               ('rebound elite', 'rebound elite'), ('standard guard', 'standard guard'), ('two-way player', 'two-way player'),
                               ('Guardian of the box', 'Guardian of the box'), ('All-round player', 'All-round player')])
    submit = SubmitField(label='submit')

models.py

from wtforms import StringField, validators, PasswordField

from NBADataSystem import db


class User(db.Model):
    __abstract__ = True
    __tablename__ = "user"
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.Text)
    password = db.Column(db.Text)
    email = db.Column(db.Text)


class Userdata(db.Model):
    __abstract__ = True
    __tablename__ = "userdata"
    id = db.Column(db.Integer, primary_key=True)
    score = db.Column(db.Integer)
    backboard = db.Column(db.Integer)
    assist = db.Column(db.Integer)


class Players(db.Model):
    __abstract__ = True
    __tablename__ = "players"
    name = db.Column(db.Text)
    firstname = db.Column(db.Text)
    lastname = db.Column(db.Text)
    born = db.Column(db.Text)
    position = db.Column(db.Text)
    team_name = db.Column(db.Text)
    player_img = db.Column(db.Text)
    avg_score = db.Column(db.Integer)
    avg_backboard = db.Column(db.Integer)
    avg_assist = db.Column(db.Integer)
    penalty_kick = db.Column(db.Integer)
    pointer = db.Column(db.Integer)
    season_time = db.Column(db.Integer)
    defend = db.Column(db.Integer)
    last_time0 = db.Column(db.Text)
    last_time1 = db.Column(db.Text)
    last_time2 = db.Column(db.Text)
    last_time3 = db.Column(db.Text)
    last_time4 = db.Column(db.Text)
    last_score0 = db.Column(db.Integer)
    last_score1 = db.Column(db.Integer)
    last_score2 = db.Column(db.Integer)
    last_score3 = db.Column(db.Integer)
    last_score4 = db.Column(db.Integer)
    player_index = db.Column(db.Integer, primary_key=True)
    similarity = db.Column(db.Integer)


class Tags(db.Model):
    __abstract__ = True
    __tablename__ = "tags"
    player_index = db.Column(db.Integer, primary_key=True)
    player_tag = db.Column(db.Text)

views.py

from flask import render_template, redirect, url_for, request, session, flash
from werkzeug.security import check_password_hash, generate_password_hash
from scipy.spatial.distance import cosine

from NBADataSystem import app, db
from NBADataSystem.forms import LoginForm, RecommendForm, RegisterForm
from NBADataSystem.models import Players, Tags, User, Userdata


def get_team_avg(team_data):
    n = 0
    team_sum = [0, 0, 0, 0, 0]
    for p in team_data:
        team_sum[0] + = float(p.avg_score)
        team_sum[1] + = float(p.avg_backboard)
        team_sum[2] + = float(p.avg_assist)
        team_sum[3] + = float(p.penalty_kick)
        team_sum[4] + = float(p.pointer)
        n + = 1
    for i in range(len(team_sum)):
        team_sum[i] = round(team_sum[i] / n, 4)
    return team_sum


def data_recommend(data, userdata):
    if userdata is None:
        return data
    user_vec = [userdata.score, userdata.backboard, userdata.assist]
    recommend_list = data
    for i in data:
        player_vec = [i.avg_score, i.avg_backboard, i.avg_assist]
        i.similarity = cosine(user_vec, player_vec)
    recommend_list.sort(key=lambda k: k.similarity)
    return recommend_list


@app.errorhandler(404)
def page_not_found(e):
    return render_template('errors/404.html'), 404


@app.route('/', methods=['GET', 'POST'])
def login():
    form = LoginForm()
    if form.validate_on_submit():
        username = form.username.data
        user = User.query.filter_by(username=username).first()
        if user:
            password = user.password
            if password == form.password.data:
                session['logged_in'] = True
                session['username'] = username
                session['id'] = user.id
                return redirect(url_for('index'))
        else:
            flash("Username or password is incorrect")
    return render_template('login.html', form=form)


@app.route('/register/', methods=['GET', 'POST'])
def register():
    form = RegisterForm()
    if form.validate_on_submit():
        id = User.query.count() + 1
        new_user = User(id=id, username=form.username.data, password=form.password.data, email=form.email.data)
        db.session.add(new_user)
        db.session.commit()
        return redirect(url_for('login'))
    else:
        return render_template('register.html', form=form)

@app.route('/index', methods=['GET'])
def index():
    page = request.args.get('page', 1, type=int)
    per_page = 8
    pagination = Players.query.paginate(page=page, per_page=per_page, error_out=False)
    posts = pagination.items
    return render_template("index.html", pagination=pagination, posts=posts)


@app.route('/player<int:player_index>', methods=['GET', 'POST'])
def to_player(player_index):
    data = Players.query.get(player_index)
    team_data = Players.query.filter(Players.team_name.like('%%%s%%' % data.team_name))
    team_avg = get_team_avg(team_data)
    tag = Tags.query.get(player_index)
    return render_template("player.html", player_data=data, player_tag=tag, team_data=team_data, team_avg=team_avg)


@app.route('/player', defaults={<!-- -->'player_index': 0}, methods=['GET', 'POST'])
def player(player_index):
    tag = Tags.query.get(player_index)
    data = Players.query.get(player_index)
    team_data = Players.query.filter(Players.team_name.like('%%%s%%' % data.team_name))
    team_avg = get_team_avg(team_data)
    return render_template("player.html", player_data=data, player_tag=tag, team_data=team_data, team_avg=team_avg)


@app.route('/search')
def search():
    q = request.args.get('q', '')
    data = Players.query.filter(Players.name.like('%%%s%%' % q))
    return render_template("search.html", player_data_list=data)


@app.route('/compare', methods=['GET', 'POST'])
def compare():
    user_data = None
    index1 = request.args.get('player_index1', type=int)
    if index1 is None:
        index1 = 0
    else:
        user_data = index1
    data1 = Players.query.get(index1)

    if user_data is not None:
        store_data = Userdata.query.get(session['id'])
        if store_data:
            score = (data1.avg_score + store_data.score) / 2.0
            backboard = (data1.avg_backboard + store_data.backboard) / 2.0
            assist = (data1.avg_assist + store_data.assist) / 2.0
            store_data.assist = assist
            store_data.backboard = backboard
            store_data.score = score
            db.session.add(store_data)
            db.session.commit()

        else:
            new_data = Userdata(id=session['id'], score=data1.avg_score,
                                backboard=data1.avg_backboard, assist=data1.avg_assist)
            db.session.add(new_data)
            db.session.commit()
    index2 = request.args.get('player_index2', 10, type=int)
    data2 = Players.query.get(index2)
    data = Players.query.all()
    return render_template("compare.html", player_data=data, player_data1=data1, player_data2=data2)


@app.route('/recommend', methods=['POST', 'GET'])
def recommend():
    form = RecommendForm()
    data = []
    if form.validate_on_submit():
        tags = form.tags
        player_tag = Tags.query.filter(Tags.player_tag.like('%%%s%%' % " ".join(tags.data)))
        if not player_tag:
            for tag in tags.data:
                player_tag = Tags.query.filter(Tags.player_tag.like('%%%s%%' % tag))
        for i in player_tag:
            data.append(Players.query.get(i.player_index))
        userdata = Userdata.query.get(session['id'])
        data = data_recommend(data, userdata)
    return render_template('recommend.html', form=form, player_data=data)

init.py

import os
importsys
from flask import Flask
from flask_bootstrap import Bootstrap
from flask_login import LoginManager
from flask_sqlalchemy import SQLAlchemy

app = Flask('NBADataSystem')

#settings
WIN = sys.platform.startswith('win')
if WIN:
    prefix = 'sqlite:///'
else:
    prefix = 'sqlite:'

app.config.from_mapping(
    SECRET_KEY='dev',
)
app.config['SQLALCHEMY_DATABASE_URI'] = \
    os.getenv('DATABASE_URL', prefix + os.path.join(app.root_path, 'playerdata/Data.db'))
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

app.jinja_env.trim_blocks = True
app.jinja_env.lstrip_blocks = True

app.config['BOOTSTRAP_SERVE_LOCAL'] = True
bootstrap = Bootstrap(app)
db = SQLAlchemy(app)

login_manager = LoginManager()


from NBADataSystem import views