Created On: June 08, 2021, Last Updated On: May 14, 2022

bootstrap datatables example 1

Public

bootstrap datatables editable csrf

By Ozzie Ghani3 new


Source Code:  https://github.com/Ozzie6935/datatables_001

Steps

# Prepare virtual environment
python3 -m venv venv
cd venv
source bin/activate

# Clone
git clone git@github.com:Ozzie6935/datatables_001.git

# Install dependencies
pip install --upgrade pip
pip install -r requirements.txt

# Run App
python app.py

# Load Users
https://example.com/load_users/<num>
https://example.com/load_users/200



requirement.text

Flask==1.0.3
Flask-SQLAlchemy==2.4.0
SQLAlchemy==1.3.6
requests



app.py

from flask import Flask, request, flash, url_for, redirect, render_template, jsonify
from flask_sqlalchemy import SQLAlchemy
from flask_wtf.csrf import CsrfProtect
import requests
import random

app = Flask(__name__)

app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////Users/osmanghani/venv/datatables/db.db'
app.config['SECRET_KEY'] = 'thisissecret'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False


db = SQLAlchemy(app)
CsrfProtect(app)

class STUDENTS(db.Model):

    __tablename__ = 'students'

    id = db.Column(db.Integer, primary_key = True)
    name = db.Column(db.String(100))
    city = db.Column(db.String(100))
    active = db.Column('is_active', db.Boolean(), nullable=False,
                       server_default='0')

    def __init__(self, **kwargs):
            # Call Flask-SQLAlchemy's constructor.
        super(STUDENTS, self).__init__(**kwargs)

    @classmethod
    def find_student_by_id(cls, student_id):
        return STUDENTS.query.filter(STUDENTS.id == student_id).first()


def getRandomFromList(l):
    """
    Provides renadom pick from provided list
    """
    random_index = random.randint(0,len(l)-1)
    return l[random_index]

def get_user_data():
    """
    :Example Data return
    : you can also use endpoints
    {"results":[{"gender":"female","name":{"title":"Mrs","first":"Marianne","last":"Gauthier"},"location":{"street":{"number":20,"name":"Lake of Bays Road"},"city":"Grand Falls","state":"Prince Edward Island","country":"Canada","postcode":"G0C 2L7","coordinates":{"latitude":"-60.4553","longitude":"98.2136"},"timezone":{"offset":"+3:00","description":"Baghdad, Riyadh, Moscow, St. Petersburg"}},"email":"marianne.gauthier@example.com","login":{"uuid":"c5a8096c-14b0-429c-8c00-079882df3c7d","username":"beautifulbear505","password":"4444","salt":"qSclKVdW","md5":"1457a6c328661877ea661bfcf7b4290d","sha1":"772b1e3cb9409c44f5f92a0a6713a5a1e70e0ab6","sha256":"03448b2ee5ca69dd633a80d95daf4c7e84a5683c0dd63849a43a1b33614dfc19"},"dob":{"date":"1978-01-16T23:57:41.491Z","age":43},"registered":{"date":"2011-05-31T18:43:06.163Z","age":10},"phone":"189-284-8036","cell":"844-527-4846","id":{"name":"","value":null},"picture":{"large":"https://randomuser.me/api/portraits/women/49.jpg","medium":"https://randomuser.me/api/portraits/med/women/49.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/49.jpg"},"nat":"CA"}],"info":{"seed":"bfbf78ad0d65075e","results":1,"page":1,"version":"1.3"}}
    """
    r = requests.get('https://randomuser.me/api/', timeout=2.50)
    if r.status_code == 200:
        return r.json()
    return r.status_code

def to_bool(s):
    if isinstance(s, str):
        if s.lower() == 'true':
             return True
        elif s.lower() == 'false':
             return False
        else:
             raise ValueError # evil ValueError that doesn't tell you what the wrong value was
    elif isinstance(s, bool):
        return bool(s)
    elif s == 1:
        return True
    elif s == 0:
        return False
    else:
         raise ValueError

@app.route('/')
def index():
    print(get_user_data())
    return render_template('index.html', students = STUDENTS.query.all() )

# https://example.com/load_data/200
@app.route('/load_data', defaults={'num': 10})
@app.route('/load_data/<int:num>')
def load_data(num):
    for i in range(int(num)):
        d = get_user_data()
        fname = d['results'][0]['name']['first']
        lname = d['results'][0]['name']['last']
        city = d['results'][0]['location']['city']
        name = f"{fname} {lname}"

        data = {
        "name": name,
        "city": city,
        "active": getRandomFromList([True, False])
        }
        d = STUDENTS(**data)
        db.session.add(d)
        db.session.commit()

    return f"{num} recored added successfully"



@app.route('/update_student', methods=['GET', 'POST', 'DELETE', 'PUT'])
def update_student():
    jsonData = request.get_json()
    data = request.json

    id = request.form['pk']
    key = request.form['name']
    value =  request.form['value']

    ## if field holds boolean values, converst string values to bool
    if key.lower() in ['active']:
        value = to_bool(value)

    # update database
    s = STUDENTS.find_student_by_id(student_id=id)
    setattr(s, key, value)
    db.session.add(s)
    db.session.commit()

    # print("=>",id, request.form, key, value, type(value))
    # for k,v in request.form.items():
    #     print(k, v)

    return jsonify(id=id)


if __name__ == '__main__':
   db.create_all()
   app.run(debug = True)


index.html

<!DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
  <meta name="description" content="{% block meta_description %}{% endblock %}">
  <meta name="csrf-token" content="{{ csrf_token() }}">
  <meta name="author" content="Osman Ghani">


  <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" integrity="sha384-JcKb8q3iqJ61gNV9KGb8thSsNjpSL0n8PARn9HuZOnIxN0hoP+VmmDGMN5t9UJ0Z" crossorigin="anonymous">
  <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.0/css/all.css" integrity="sha384-lZN37f5QGtY3VHgisS14W3ExzMWZxybE1SJSEsQp9S+oqd12jhcu+A56Ebc1zFSJ" crossorigin="anonymous">
  <link rel="stylesheet" href="https://cdn.datatables.net/1.10.25/css/dataTables.bootstrap4.min.css">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.5.2/css/bootstrap.css">
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js" integrity="sha384-9/reFTGAW83EW2RDu2S0VKaIzap3H66lZH81PoYlFhbGU+6BZp6G7niu735Sk7lN" crossorigin="anonymous"></script>
  <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js" integrity="sha384-B4gt1jrGC7Jh4AgTPSdUtOBvfO8shuf57BaghqFfPlYxofvL8/KUEfYiJOMMV+rV" crossorigin="anonymous"></script>
  <script src="https://cdn.datatables.net/1.10.25/js/jquery.dataTables.min.js"></script>
  <script src="https://cdn.datatables.net/1.10.25/js/dataTables.bootstrap4.min.js"></script>
  <link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/bootstrap-editable.css')}}">
  <script src="{{ url_for('static', filename='js/bootstrap-editable.js')}}"></script>

  <script type="text/javascript">
    var csrftoken = $('meta[name=csrf-token]').attr('content');

    $.ajaxSetup({
      beforeSend: function(xhr, settings) {
        if (!/^(GET|HEAD|OPTIONS|TRACE)$/i.test(settings.type)) {
          xhr.setRequestHeader("X-CSRFToken", csrftoken)
        }
      }
    });
  </script>
</head>

<body>

  <div class="container">
    <div class="panel panel-default">
      <div class="panel-heading">DataTable</div>
      <div class="panel-body">
        <div class="table-responsive">
          <table id="sample_data" class="table table-striped table-bordered" style="width:100%">
            <thead>
              <tr>
                <th>ID</th>
                <th>Name</th>
                <th>City</th>
                <th>Active</th>
              </tr>
            </thead>
            <tbody>
              {% for s in students %}
              <tr>
                <td data-pk="{{s.id}}">{{s.id}}</td>
                <td data-name="name" class="name" data-type="text" data-pk="{{s.id}}">{{s.name}}</td>
                <td data-name="city" class="city" data-type="text" data-pk="{{s.id}}">{{s.city}}</td>
                <td data-name="active" class="active" data-type="text" data-pk="{{s.id}}">{{s.active}}</td>

              </tr>
              {% endfor %}
            </tbody>
          </table>
        </div>
      </div>
    </div>
  </div>

  <br />
  <br />


</body>



<script type="text/javascript" language="javascript">
  $(document).ready(function() {
    var dataTable = $('#sample_data').DataTable();

    $('#sample_data').editable({
      container: 'body',
      selector: 'td.city',
      url: '/update_student',
      title: 'city',
      type: 'POST',
      validate: function(value) {
        if ($.trim(value) == '') {
          return 'This field is required';
        }
      }
    });
    $('#sample_data').editable({
      container: 'body',
      selector: 'td.active',
      url: '/update_student',
      title: 'active',
      type: 'POST',
      validate: function(value) {
        if ($.trim(value) == '') {
          return 'This field is required';
        }
      }
    });
  });
</script>

</html>