Make a simple library management system with Flask + Vue

design sketch:

preface

Before we start, let's talk about Django and Flask. Compare the decoration style: one is light luxury style (left in the figure below) and the other is Syrian style (right in the figure below):

 

Django is more comfortable to use. It is probably the "bag check-in" mode in the mouth of the tenant. It has complete tools. You only need to consider whether to eat roujiamo (CBV) or 4 dishes and 1 soup (FBV). Occasionally, you have to consider whether it is appropriate to change a refrigerator (database).

Using Flask is like finding a Syrian style rental house. It looks very simple. In fact, it has everything (referring to the floor and ceiling). However, if you want to have a different flavor, you have to decorate it according to your own preferences.

Decoration link

1. Flooring (written by flash basic style)

Coding tools depend on your preference. I use Visio Studio Code here, due to the use of vue framework, we should distinguish Flask from vue at the beginning and arrange a single private room for them. In other words, create two folders and store the front and back codes separately.

Create a new app in the backend folder Py as our back-end main program, write in it:

from flask import Flask

app = Flask(__name__)

@app.route("/")
def hello_world():
    return "<p>Hello, World!</p>"

It's probably like this:

Then we open the console, enter the flash folder, and enter the following code:

set FLASK_APP=app.py    
# Set the flash environment variable if the name is app Py or WSGI Py can ignore this code

flask run
# start-up

You can see that the console outputs an IP and opens it in the browser:

 * Environment: production
   WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.
 * Debug mode: off
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)

       

2. Select a storage room (database)

Here, I choose Flask + SQLAlchemy + SQLite as our data storage system, and import SQLAlchemy into the app:

from flask_sqlalchemy import SQLAlchemy

Create a table according to the fields we need:

app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///data.sqlite'
# Specify database file
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
# Allows you to modify the tracking database
db = SQLAlchemy(app)

class Books(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(80), nullable=False)
    author = db.Column(db.String(120), nullable=False)
    read= db.Column(db.Boolean)
db.create_all()
# Create table 

Rerun app Py file, you can see that the database file has been generatedNext, we define several functions to facilitate the addition, deletion, modification and query of the database:

# increase
def insertData(title,author,read):
    book=Books(title=title,author=author,read=read)
    db.session.add_all([book])
    db.session.commit()

# check
def selectDataAll():
    book_list=[]
    books = Books.query.all()
    # Similar to select * from Books
    for s in books:
        dic = {}
        dic['id'] = s.id
        dic['title'] = s.title
        dic['author'] = s.author
        dic['read'] = s.read
        print(f'Id: {s.id} | Title: {s.title} | Author: {s.author} | Read: {s.read}')

        print('----')
        book_list.append(dic)
    return book_list

# Delete
def deleteData(id):
    book = Books.query.get(id)
    # Similar to select * from Books where id = id 
    db.session.delete(book)
    db.session.commit()
    # Submit operation to database
    
# change
def updateData(id, title='', author='', read='', new_id=''):

    book = Books.query.get(id)
    if not title=='':
        book.title = title
    if not author == '':
        book.author = author
    if not read == '':
        book.read = read
    if not new_id == '':
        book.id=new_id
    db.session.commit()

Add data using the increment function we have written:

···

insertData('book1','zhangsan',0)
insertData('book2','lisi',1)

···

Run app After py, the data is added to the database.

#Ps: after running, remember to use the app Delete the above two sentences in py

3. Install doors and windows (accept the specified interactive information and respond)

···
from flask import Flask, jsonify, request, make_response
···

···
@app.route('/',methods=['GET','POST'])
def all_books():
    
    response_object = {'status':'success'}
    books = selectDataAll()
    response_object['books']=books
    return jsonify(response_object)
···

Everything is ready, we run the app Py, you can see that the data in the database has been displayed in the web page:

4. Exterior wall decoration

First, configure the required application and environment according to the following process:

1. We need node in our computer JS (Chinese web address: http://nodejs.cn/ ), download and install directly (installation tutorial: https://www.runoob.com/nodejs/nodejs-install-setup.html ).

2. Install cnpm (cmd input: NPM install - G cnpm -- Registry)= http://registry.npm.taobao.org )

3. Install vue scaffold (cmd input: NPM install - G vue CLI)

4. Install webpack (cmd input: npm install webpack -g)

5. Find the vue folder we created earlier, cd it, cmd enter: vue create file name, and then an interface will appear:

The first option is the configuration saved in the past

The second is the default configuration

The third is custom (select features manually)

We select custom configuration, the up and down arrows on the keypad move, and the space is checked / unchecked.

Here we all choose.

Then press enter to proceed to the next stage:

#Ps: Note: the last item means whether to use the above configuration for future projects (save the configuration)

After installation, enter cmd under the root directory of vue and enter npm run serve

#Ps: if it fails, please check the package. In the root directory JSON file, and try to start using the npm run dev instruction

Start successfully, as shown in the figure below:

 

5. House renovation (linkage and optimization of front and rear ends, problem handling)

At this stage, we are almost at the end. By observing the renderings, we can conclude that the tools we need are:

vue:

  • Bootstrap # comes with its own style and is easy to use (cmd input in vue root directory: npm install bootstrap --save)
  • axios # is used to solve cross domain problems (cmd input under the root directory of vue: npm; install axios)

Flask:

  • CORS # is used to solve cross domain problems (cmd input: PIP3 install flash_cors)

After installing axios on the front end, use axios Post is a way to handle cross domain interactions

After installing the above tools, we will start the final work.

1. Modify the app. In the flash folder Py (configure cross domain interaction):
 

···
from flask_cors import CORS # Import CORS package
···

···
@app.after_request
def after(resp):

    resp = make_response(resp)
    resp.headers['Access-Control-Allow-Origin'] = '*'     # Allow cross domain addresses
    resp.headers['Access-Control-Allow-Methods'] = '*'    # Request '*' is all
    resp.headers['Access-Control-Allow-Headers'] = 'x-requested-with,content-type' # head
    resp.headers['Access-Control-Allow-Credentials'] = 'True'

    return resp

CORS(app, resources=r'/*', supports_credentials=True)

···

2. Create alert in src / components under vue folder vue files and books vue file

3. Configure router / index JS (or index.ts)

import Vue from "vue";
import VueRouter, { RouteConfig } from "vue-router";
import Books from "../components/Books.vue";
import Home from "../components/HelloWorld.vue";
import 'bootstrap/dist/css/bootstrap.css';
import BootstrapVue from 'bootstrap-vue'

Vue.config.productionTip=false
Vue.use(BootstrapVue);
Vue.use(VueRouter);

const routes: Array<RouteConfig> = [
  {
    path: "/home",
    name: "Home",
    component: Home,
  },
  {
    path: "/",                # Add books Add Vue to the route
    name: "Books",
    component: Books,
  },
  {
    path: "/about",
    name: "About",
    // route level code-splitting
    // this generates a separate chunk (about.[hash].js) for this route
    // which is lazy-loaded when the route is visited.
    component: () =>
      import(/* webpackChunkName: "about" */ "../views/About.vue"),
  },
];

const router = new VueRouter({
  mode: "history",
  base: process.env.BASE_URL,
  routes,
});

export default router;

4. Configure books Vue and alert vue

# Books.vue

<template>
  <div class="container" align="left">
    <div class="row">
      <div class="col-sm-10">
        <h1>Books</h1>
        <hr />
        <br />
         <div>
          <b-alert variant="success" show>{{ message }}</b-alert>
          <br>
        </div>
        <br />
        <button type="button" class="btn btn-success btn-sm">Add Book</button>
        <br />
        <br />
        <table class="table table-hover">
          <thead>
            <tr>
              <th scope="col">Title</th>
              <th scope="col">Author</th>
              <th scope="col">Read?</th>
              <th></th>
            </tr>
          </thead>
          <tbody>
            <tr v-for="(book, index) in books" :key="index">
              <td>{{ book.title }}</td>
              <td>{{ book.author }}</td>
              <td>
                <span v-if="book.read">Yes</span>
                <span v-else>No</span>
              </td>
              <td>
                <div class="btn-group" role="group">
                  <button type="button" class="btn btn-warning">Update</button>
                  &nbsp;
                  <button type="button" class="btn btn-danger">Delete</button>
                </div>
              </td>
            </tr>
          </tbody>
        </table>
      </div>
    </div>
  </div>
</template>


<script>
import axios from "axios";
import Alert from './Alert.vue'
export default {
  data() {
    return {
      props: ['message'],
      books: [],
      BookForm: {
        delbook:"",
        id: "",
        title: "",
        author: "",
        read: []
      },
      message: '',
    };
  },
  commponents:{
    alert:Alert,
  },
  methods: {

    getBooks() {
      const path="http://127.0.0.1:5000";
      axios
        .get(path)
        .then(res => {
          this.books=res.data.books;
        })
        .catch(error => {
          console.error(error);
        });
    },
    initForm() {
      this.BookForm.delbook='null';
      this.BookForm.id="null";
      this.BookForm.title="";
      this.BookForm.author="";
      this.BookForm.read=[];
    },
  },
  created() {
    this.getBooks();
  }
};
</script>
# Alert.vue

<template><div></div></template>

In books In Vue, we mainly build the basic framework of web pages. At present, we can only obtain the data in the database and display:

Next, we begin to write the code for the Add Book button:

<template>
  <div class="container" align="left">
    <div class="row">
      <div class="col-sm-10">
        <h1>Books</h1>
        <hr />
        <br />
         <div>
          <b-alert variant="success" show>{{ message }}</b-alert>
          <br>
        </div>
        <br />
        <button type="button" class="btn btn-success btn-sm" v-b-modal.book-add>Add Book</button>
        <br />
        <br />
        <table class="table table-hover">
          <thead>
            <tr>
              <th scope="col">Title</th>
              <th scope="col">Author</th>
              <th scope="col">Read?</th>
              <th></th>
            </tr>
          </thead>
          <tbody>
            <tr v-for="(book, index) in books" :key="index">
              <td>{{ book.title }}</td>
              <td>{{ book.author }}</td>
              <td>
                <span v-if="book.read">Yes</span>
                <span v-else>No</span>
              </td>
              <td>
                <div class="btn-group" role="group">
                  <button type="button" class="btn btn-warning">Update</button>
                  &nbsp;
                  <button type="button" class="btn btn-danger">Delete</button>
                </div>
              </td>
            </tr>
          </tbody>
        </table>
      </div>
    </div>
<!-- --------------------------------Add------------------------------ -->
    <!-- Note that with the above Add Book Button binding -->
    <b-modal ref="addBookModal" id="book-add" title="Add a new book" hide-footer>
      <b-form @submit="add_onSubmit" @reset="add_onReset" class="w-100">
        <b-form-group id="form-title-group" label="Title:" label-for="form-title-input">
          <b-form-input
            id="form-title-input"
            type="text"
            v-model="BookForm.title"
            required
            placeholder="Enter title"
          ></b-form-input>
        </b-form-group>
        <b-form-group id="form-author-group" label="Author:" label-for="form-author-input">
          <b-form-input
            id="form-author-input"
            type="text"
            v-model="BookForm.author"
            required
            placeholder="Enter author"
          ></b-form-input>
        </b-form-group>
        <b-form-group id="form-read-group">
          <b-form-checkbox-group v-model="BookForm.read" id="form-checks">
            <b-form-checkbox value="true">Read?</b-form-checkbox>
          </b-form-checkbox-group>
        </b-form-group>
        <b-button-group>
          <b-button type="submit" variant="primary">Submit</b-button>
          <b-button type="reset" variant="danger">Reset</b-button>
        </b-button-group>
      </b-form>
    </b-modal>
  </div>
</template>

And the corresponding script code:

<script>
import axios from "axios";
import Alert from './Alert.vue'
export default {
  data() {
    return {
      props: ['message'],
      books: [],
      BookForm: {
        delbook:"",
        id: "",
        title: "",
        author: "",
        read: []
      },
      message: '',
    };
  },
  commponents:{
    alert:Alert,
  },
  methods: {

    getBooks() {
      const path="http://127.0.0.1:5000";
      axios
        .get(path)
        .then(res => {
          this.books=res.data.books;
        })
        .catch(error => {
          console.error(error);
        });
    },
    initForm() {
      this.BookForm.delbook='null';
      this.BookForm.id="null";
      this.BookForm.title="";
      this.BookForm.author="";
      this.BookForm.read=[];
    },
        // --------------------------Add-----------------------------
    addBook(payload) {
      const path="http://127.0.0.1:5000";
      axios
        .post(path, payload)
        .then(() => {
          this.getBooks();
          this.message = 'Book added!'
        })
        .catch(error => {
          console.log(error);
          this.getBooks();
        });
    },
    add_onSubmit(evt) {
      evt.preventDefault();
      this.$refs.addBookModal.hide();
      let read=false;
      if(this.BookForm.read[0]) read=true;
      const payload={
        del_id:"null",
        id:"null",
        title: this.BookForm.title,
        author: this.BookForm.author,
        read
      };
      this.addBook(payload);
      this.initForm();
    },
    add_onReset(evt) {
      evt.preventDefault();
      this.$refs.addBookModal.hide();
      this.initForm();
    },
  },
  created() {
    this.getBooks();
  }
};
</script>

Modify the back-end code (app.py) to add the identification and operation of POST requests:

···

@app.route('/',methods=['GET','POST','OPTIONS'])
def all_books():
    
    response_object = {'status':'success'}
    books = selectDataAll()
    if request.method == 'POST':

        post_data = request.get_json()
        print(post_data)
        books_id = post_data.get('id')
        del_id = post_data.get('del_id')

        title = post_data.get('title'),
        author = post_data.get('author'),
        read = post_data.get('read')

        insertData(
        title=title[0],
        author=author[0],
        read=read
        )
        response_object['message'] = 'Book added!'
    else:
        response_object['books']=books
   
    return jsonify(response_object)

···

Do the same, write the update button click event and del event

Attached books Vue all codes:

<template>
  <div class="container" align="left">
    <div class="row">
      <div class="col-sm-10">
        <h1>Books</h1>
        <hr />
        <br />
         <div>
          <b-alert variant="success" show>{{ message }}</b-alert>
          <br>
        </div>
        <br />
        <button type="button" class="btn btn-success btn-sm" v-b-modal.book-add>Add Book</button>
        <br />
        <br />
        <table class="table table-hover">
          <thead>
            <tr>
              <th scope="col">Title</th>
              <th scope="col">Author</th>
              <th scope="col">Read?</th>
              <th></th>
            </tr>
          </thead>
          <tbody>
            <tr v-for="(book, index) in books" :key="index">
              <td>{{ book.title }}</td>
              <td>{{ book.author }}</td>
              <td>
                <span v-if="book.read">Yes</span>
                <span v-else>No</span>
              </td>
              <td>
                <div class="btn-group" role="group">
                  <button type="button" class="btn btn-warning" v-b-modal.book-up @click="book_update(index)">Update</button>
                  &nbsp;
                  <button type="button" class="btn btn-danger" @click="book_del(index)">Delete</button>
                </div>
              </td>
            </tr>
          </tbody>
        </table>
      </div>
    </div>
    <!-- ------------------------------------------------------Add-------------------------------------------------- -->
    <b-modal ref="addBookModal" id="book-add" title="Add a new book" hide-footer>
      <b-form @submit="add_onSubmit" @reset="add_onReset" class="w-100">
        <b-form-group id="form-title-group" label="Title:" label-for="form-title-input">
          <b-form-input
            id="form-title-input"
            type="text"
            v-model="BookForm.title"
            required
            placeholder="Enter title"
          ></b-form-input>
        </b-form-group>
        <b-form-group id="form-author-group" label="Author:" label-for="form-author-input">
          <b-form-input
            id="form-author-input"
            type="text"
            v-model="BookForm.author"
            required
            placeholder="Enter author"
          ></b-form-input>
        </b-form-group>
        <b-form-group id="form-read-group">
          <b-form-checkbox-group v-model="BookForm.read" id="form-checks">
            <b-form-checkbox value="true">Read?</b-form-checkbox>
          </b-form-checkbox-group>
        </b-form-group>
        <b-button-group>
          <b-button type="submit" variant="primary">Submit</b-button>
          <b-button type="reset" variant="danger">Reset</b-button>
        </b-button-group>
      </b-form>
    </b-modal>
    <!-- ----------------------------------------------------Up date------------------------------------------------ -->
    <b-modal ref="upBookModal" id="book-up" title="update book" hide-footer>
      <b-form @submit="up_onSubmit" @reset="up_onReset" class="w-100">
        <b-form-group id="form-title-group" label="Title:" label-for="form-title-input">
          <b-form-input
            id="form-title-input"
            type="text"
            v-model="BookForm.title"
            required
            placeholder="Enter title"
          ></b-form-input>
        </b-form-group>
        <b-form-group id="form-author-group" label="Author:" label-for="form-author-input">
          <b-form-input
            id="form-author-input"
            type="text"
            v-model="BookForm.author"
            required
            placeholder="Enter author"
          ></b-form-input>
        </b-form-group>
        <b-form-group id="form-read-group">
          <b-form-checkbox-group v-model="BookForm.read" id="form-checks">
            <b-form-checkbox value="true">Read?</b-form-checkbox>
          </b-form-checkbox-group>
        </b-form-group>
        <b-button-group>
          <b-button type="submit" variant="primary">Submit</b-button>
          <b-button type="reset" variant="danger">Reset</b-button>
        </b-button-group>
      </b-form>
    </b-modal>
    <!-- ------------------------------------------------------del-------------------------------------------------- -->
  
  </div>
</template>


<script>
import axios from "axios";
import Alert from './Alert.vue'
export default {
  data() {
    return {
      props: ['message'],
      books: [],
      BookForm: {
        delbook:"",
        id: "",
        title: "",
        author: "",
        read: []
      },
      message: '',
    };
  },
  commponents:{
    alert:Alert,
  },
  methods: {

    getBooks() {
      const path="http://127.0.0.1:5000";
      axios
        .get(path)
        .then(res => {
          this.books=res.data.books;
        })
        .catch(error => {
          console.error(error);
        });
    },
    initForm() {
      this.BookForm.delbook='null';
      this.BookForm.id="null";
      this.BookForm.title="";
      this.BookForm.author="";
      this.BookForm.read=[];
    },
        // --------------------------Add-----------------------------
    addBook(payload) {
      const path="http://127.0.0.1:5000";
      axios
        .post(path, payload)
        .then(() => {
          this.getBooks();
          this.message = 'Book added!'
        })
        .catch(error => {
          console.log(error);
          this.getBooks();
        });
    },
    add_onSubmit(evt) {
      evt.preventDefault();
      this.$refs.addBookModal.hide();
      let read=false;
      if(this.BookForm.read[0]) read=true;
      const payload={
        del_id:"null",
        id:"null",
        title: this.BookForm.title,
        author: this.BookForm.author,
        read
      };
      this.addBook(payload);
      this.initForm();
    },
    add_onReset(evt) {
      evt.preventDefault();
      this.$refs.addBookModal.hide();
      this.initForm();
    },
    // ------------------------up date-----------------------
    book_update:function(index){
      this.BookForm.id=index+1
    },
    upBook(payload) {
      const path="http://127.0.0.1:5000";
      axios
        .post(path, payload)
        .then(() => {
          this.getBooks();
          this.message = 'Book update!'
        })
        .catch(error => {
          console.log(error);
          this.getBooks();
        });
    },
    up_onSubmit(evt) {
      evt.preventDefault();
      this.$refs.upBookModal.hide();
      let read=false;
      if(this.BookForm.read[0]) read=true;
      const payload={
        id: this.BookForm.id,
        del_id: "null",
        title: this.BookForm.title,
        author: this.BookForm.author,
        read
      };
      this.upBook(payload);
      this.initForm();
    },
    up_onReset(evt) {
      evt.preventDefault();
      this.$refs.upBookModal.hide();
      this.initForm();
    },
    // --------------------------del-------------------------
    book_del:function(index){
      this.BookForm.delbook=index+1
      let read=false;
      if(this.BookForm.read[0]) read=true;
      const payload={
        id:"null",
        del_id: this.BookForm.delbook,
        title: this.BookForm.title,
        author: this.BookForm.author,
        read
      };
      this.delBook(payload);
      this.initForm();
    },
    delBook(payload) {
      const path="http://127.0.0.1:5000";
      axios
        .post(path, payload)
        .then(() => {
          this.getBooks();
          this.message = 'Book del!'
        })
        .catch(error => {
          console.log(error);
          this.getBooks();
        });
    },
  },
  created() {
    this.getBooks();
  }
};
</script>

Modify the back-end code and use the functions according to the rules:

from flask import Flask, jsonify, request, make_response
from flask_sqlalchemy import SQLAlchemy
from flask_cors import CORS


app = Flask(__name__)
@app.after_request
def after(resp):

    resp = make_response(resp)
    resp.headers['Access-Control-Allow-Origin'] = '*'
    resp.headers['Access-Control-Allow-Methods'] = '*'
    resp.headers['Access-Control-Allow-Headers'] = 'x-requested-with,content-type'
    resp.headers['Access-Control-Allow-Credentials'] = 'True'

    return resp


app.config['DEBUG'] = True
CORS(app, resources=r'/*', supports_credentials=True)

# ------------------database----------------------------
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///data.sqlite'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
db = SQLAlchemy(app)
class Books(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(80), nullable=False)
    author = db.Column(db.String(120), nullable=False)
    read= db.Column(db.Boolean)
db.create_all()

# increase
def insertData(title,author,read):
    book=Books(title=title,author=author,read=read)
    db.session.add_all([book])
    db.session.commit()



# check
def selectDataAll():
    book_list=[]
    books = Books.query.all()

    for s in books:
        dic = {}
        dic['id'] = s.id
        dic['title'] = s.title
        dic['author'] = s.author
        dic['read'] = s.read
        print(f'Id: {s.id} | Title: {s.title} | Author: {s.author} | Read: {s.read}')

        print('----')
        book_list.append(dic)
    return book_list

# Delete
def deleteData(id):
    book = Books.query.get(id)
    db.session.delete(book)
    db.session.commit()

# change
def updateData(id, title='', author='', read='', new_id=''):

    book = Books.query.get(id)
    if not title=='':
        book.title = title
    if not author == '':
        book.author = author
    if not read == '':
        book.read = read
    if not new_id == '':
        book.id=new_id
    db.session.commit()




# ------------------database---end----------------------





@app.route('/',methods=['GET','POST','OPTIONS'])
def all_books():
    
    response_object = {'status':'success'}
    books = selectDataAll()
    if request.method == 'POST':

        post_data = request.get_json()
        print(post_data)
        books_id = post_data.get('id')
        del_id = post_data.get('del_id')
        if books_id == 'null' and del_id == 'null':
            title = post_data.get('title'),
            author = post_data.get('author'),
            read = post_data.get('read')


            insertData(
                title=title[0],
                author=author[0],
                read=read
            )
            response_object['message'] = 'Book added!'
        elif (not books_id == 'null') and del_id == 'null':
            put_data = post_data
            books_id = put_data.get('id')
            title = put_data.get('title')
            author = put_data.get('author')
            read = put_data.get('read')
            updateData(
                id=books_id,
                title=title,
                author=author,
                read=read
            )
            response_object['message'] = 'Book update!'
        else:
            deleteData(del_id)
            response_object['message'] = 'Book del!'
    else:
        response_object['books']=books
    books = selectDataAll()
    for i in range(len(books)):
        id=books[i]['id']
        updateData(id=id,new_id=i+1)
    print(response_object)
    return jsonify(response_object)



if __name__ == '__main__':
    app.run(port=5000,debug=True)

So far, the codeword is hard. Please leave a praise before you go. Thank you first!

Keywords: Vue Flask

Added by dhe on Mon, 03 Jan 2022 18:10:48 +0200