Ide: Pycharm Community 2019.3.1 Python version: 3.7.6

Start with a new project called Flask_demo1

If you are not using a virtual environment, you can ignore the venv directory

Install the flask

pip install flask

The first program file

Create a new py file, such as main.py, with the following code

from flask import Flask
web = Flask(__name__)

@web.route('/')
def hello_world() :
    return 'Hello, World! '

web.run(debug=True)
Copy the code

Pycharm already works (Shift+F10)To see the site running on port 5000, open your browser and typehttp://127.0.0.1:5000You have seen the pageWe add a movieList route to main.py and the code becomes

from flask import Flask
web = Flask(__name__)

@web.route('/')
def hello_world() :
    return 'Hello, World! '

@web.route('/movieList')
def movie_list() :
    return 'show movie list'

web.run(debug=True)
Copy the code

If you save the main.py file in PyCharm (CTRL + S), the service will be restarted automatically. If not, press CTRL +F5 or click the restart button below to restart the serviceGo to the browserhttp://127.0.0.1:5000/movieListYou can see that this new route is workingSo let’s modify this function movie_list to return an HTML

from flask import Flask
web = Flask(__name__)

@web.route('/')
def hello_world() :
    return 'Hello, World! '

@web.route('/movieList')
def movie_list() :
    return "' 
         
         '''

web.run(debug=True)
Copy the code

After saving the code and restarting the service, we go to the browser and refresh the page to see a video playerOf course, there is no video file in our project, so it cannot be played at present.

Create a static directory under your project, create a movies directory inside static, and put an MP4 file in it. I’m going to put a tetris.mp4 here, and I’m going to make changes to it in my movie_list. Static /movie/tetris.mp4 Several examples of MP4 files have been uploaded to Baidu web disk, if necessary, can be downloaded by yourself (link:Pan.baidu.com/s/1VxKtHN_2…Extraction code: TBIU)Save the file and restart the service before going to the browser. The video file has been loaded successfully and can be played by clicking Play

Use of templates

Through the above program, we have implemented the server local video playback, but if the page is in this way

@web.route('/movieList')
def movie_list() :
    return "' 
         
         '''
Copy the code

All strings are returned, so HTML development is too inefficient, so we now use templates to implement. Start by creating a templates directory in your project directory. In the templates directory, create a new movie_list.html fileThe file contents are as follows

<! DOCTYPE html><html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Video display</title>
</head>
<body>
<video width="400" height="300" controls="controls">
  <source src="static/movies/tetris.mp4" type="video/mp4" />
</video>
</body>
</html>
Copy the code

Then import render_template in main.py

from flask import render_template
Copy the code

Modify the code for movie_list as follows

@web.route('/movieList')
def movie_list() :
    return render_template('movie_list.html')
Copy the code

After the modification, restart the service. The page can be used normally.

Let’s put each of our four video files in the static/movies/ directory and try looping to render the template. The code for the movie_list function is modified as follows to pass movies as an array to the rendering engine for rendering.

@web.route('/movieList')
def movie_list() :
    movies = ['tetris.mp4'.'guess.mp4'.'bfcontrol1.mp4'.'bfcontrol2.mp4']
    return render_template('movie_list.html', movies=movies)
Copy the code

Templates /movie_list.html will look like this:

<! DOCTYPE html><html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Video display</title>
</head>
<body>
{% for movie in movies %}
    <video width="400" height="300" controls="controls">
      <source src="static/movies/{{movie}}" type="video/mp4" />
    </video>
{% endfor %}
</body>
</html>
Copy the code

When you reboot and refresh, you can see that all four videos have loadedNext we add another title to the video, we modify the structure of the movie array slightly, and the code for the movie_list function is changed as follows

@web.route('/movieList')
def movie_list() :
    movies = [{'file':'tetris.mp4'.'title':tetris},
              {'file':'guess.mp4'.'title':'Fill in the blanks with poetry'},
              {'file':'bfcontrol1.mp4'.'title':'1' pygame controls},
              {'file':'bfcontrol2.mp4'.'title':'2' pygame controls}]
    return render_template('movie_list.html', movies=movies)
Copy the code

File and title are used in movie_list.html

<! DOCTYPE html><html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Video display</title>
</head>
<body>
{% for movie in movies %}
    <div width="400px" height="350px" >
        <video width="400" height="225" controls="controls">
          <source src="static/movies/{{movie['file']}}" type="video/mp4" />
        </video>
        <p>{{movie['title']}}</p>
    </div>
{% endfor %}
</body>
</html>
Copy the code

You can see that the title also displays normallyPage style added to make typography perfect and adaptive, changed to movie_list.html

<! DOCTYPE html><html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Video display</title>
    <style>
    .box-out {
      position:relative;
      #border:solid 1px # 555;
      float:left;
      padding:0px 10px;
    }
    .box-in {
      position:absolute;
      left:0;
      top:0px;
      right:0;
      bottom:0;
      margin:auto;
    }
    .title-in {
      position:absolute;
      top:240px;
      left:0;
      right:0;
      margin:auto;
      text-align:center;
      height:50px;
      line-height:50px;
      font-size:18px;
    }
    </style>
</head>
<body>
<div id="container">
{% for movie in movies %}
    <div class="box-out" style="height:280px; width:400px;">
        <video class="movie box-in" data-file="{{movie['file']}}" width="400" height="225" controls >
          <source src="static/movies/{{movie['file']}}" type="video/mp4" />
        </video>
        <p class="title-in" >{{movie['title']}}</p>
    </div>
{% endfor %}
</div>
<script>
    // Adjust the page horizontal center
    function resetContentPos(){
       var div = document.getElementById("container"); // Get the main container
       var allWidth = document.body.clientWidth;  // Width of the browser
       var n = parseInt(allWidth / 420);  // Depending on the width of the browser, it can display several videos
       var contentWidth = n * 420; // The total width of several videos
       div.style.marginLeft = (allWidth-contentWidth)/2+"px"; // The main container moves the normal remaining width to the right, centering the pair
    }
    (function(){
        resetContentPos(); // Adjust the page horizontal center}) ();window.onresize = function(){
        resetContentPos(); // Adjust the page horizontal center
    }
</script>
</body>
</html>
Copy the code

The page layout is as followsWhen the page is narrower, it looks like this

Data is stored

The operation data on the website will be stored below, such as the click times of each video after clicking to play the video, and the next loading page will be sorted according to the play times. In order to simplify the implementation of the website, we will first use XML file to read and write instead of database this time.

Create a new file directory under your project directory and create a movies.xml file in that directory with the following contents:

<? xml version="1.0" encoding="UTF-8"? > <root> <movie file="tetris.mp4" title=tetris></movie>
    <movie file="guess.mp4" title="Fill in the blanks with poetry."></movie>
    <movie file="bfcontrol1.mp4" title="Pygame controls 1"></movie>
    <movie file="bfcontrol2.mp4" title="Pygame controls 2"></movie>
</root>
Copy the code

In the project directory, create a new python file xml_lib.py to manipulate XML files, import the xml.dom library to manipulate them, and write a read_movies function to read videos from XML

from xml.dom.minidom import parse
import xml.dom.minidom

xml_file = 'file/movies.xml'

def read_movies() :
    DOMTree = xml.dom.minidom.parse(xml_file)
    root = DOMTree.documentElement
    movies = root.getElementsByTagName('movie')

    movie_arr = []
    for movie in movies:
        movie_dic = {}
        movie_dic['file'] = movie.getAttribute('file')
        movie_dic['title'] = movie.getAttribute('title')
        movie_arr.append(movie_dic)

    return movie_arr
Copy the code

The current directory structure looks like thisThen we use the read_movies function in xml_lib in main.py and modify the main.py code to become

from flask import Flask
from flask import render_template
web = Flask(__name__)
import xml_lib
@web.route('/')
def hello_world() :
    return 'Hello, World! '

@web.route('/movieList')
def movie_list() :
    return render_template('movie_list.html', movies=xml_lib.read_movies())

web.run(debug=True)
Copy the code

Now our website will be displayed using the configuration in XML. If you change the title of the video in XML, you can see that you refresh the page and immediately see the title change.We will add a class name for video called Movie and a data item data-file, which will bind the name of the video and upload it to the server after clicking

        <video class="movie box-in" data-file="{{movie['file']}}" width="400" height="225" controls >
          <source src="static/movies/{{movie['file']}}" type="video/mp4" />
        </video>
Copy the code

In javascript, we bind the play event

    (function(){
        resetContentPos(); // Adjust the page horizontal center

        var movie_items = document.getElementsByClassName('movie'); // Get all class items with movie, i.e., all videos
        for(var i=0; i<movie_items.length; i++){// Iterate over the video
             movie_items[i].addEventListener('play'.function(t){ // Bind the playback event of the video
                  var filename = t.target.dataset.file; // Get the value of data-filealert(filename); })}}) ();Copy the code

Refresh the site and we see that when you click on the video, the corresponding name pops up now.Now, back on the server side, we want to save the number of hits per video, so let’s add a function incr_movie in xml_lib.py to increase the number of hits per video, and the code for incr_movie is as follows

def incr_movie(name) :
    movies = read_movies()  # Read the movie first

    dom = xml.dom.minidom.Document()  Create a DOM tree
    root_node = dom.createElement('root')  Create the root node
    dom.appendChild(root_node)  Add the root node to the DOM tree
    for movie_dic in movies:  # Loop over all movies read from XML
        movie_node = dom.createElement('movie')  Create the movie node
        filename = movie_dic['file']  Get the name from the dictionary
        movie_node.setAttribute('file', filename)  Set file to the movie node
        title = movie_dic['title']  Get the title in the dictionary
        movie_node.setAttribute('title', title)  Set the title property to the movie node
        count = movie_dic.get('count'.0)  # the number of hits to get the video in the dictionary, default to 0 if there are no hits
        if filename == name:  If you want to increase the click count, then click count +1
            count += 1
        movie_node.setAttribute('count'.str(count))  # set the count attribute to the movie node
        root_node.appendChild(movie_node)  Add the movie node to the root node
    with open(xml_file, 'w', encoding='utf-8') as fs:
        dom.writexml(fs, indent=' ', addindent='\t', newl='\n', encoding='UTF-8')
Copy the code

Let’s add another route, incrMovie, to main.py

@web.route('/incrMovie')
def incr_movie() :
    name = request.args.get('name')  Select name from request parameters
    xml_lib.incr_movie(name)  
    return '1'
Copy the code

Restart the site, and we type in the browserhttp://127.0.0.1:5000/incrMovie?name=tetris.mp4Normally, we see that the page returns 1, and when we look at the XML, we see that movie has an extra attribute countWe can also make some changes to read_movies in xml_lib, since it did not read count before, and now we want to add reads of count. The code for read_movies is as follows

def read_movies() :
    DOMTree = xml.dom.minidom.parse(xml_file)
    root = DOMTree.documentElement
    movies = root.getElementsByTagName('movie')

    movie_arr = []
    for movie in movies:
        movie_dic = {}
        movie_dic['file'] = movie.getAttribute('file')
        movie_dic['title'] = movie.getAttribute('title')
        if movie.hasAttribute('count'):
            movie_dic['count'] = int(movie.getAttribute('count'))
        else:
            movie_dic['count'] = 0
        movie_arr.append(movie_dic)

    return movie_arr
Copy the code

This way, restart the site after each visithttp://127.0.0.1:5000/incrMovie?name=tetris.mp4 this link, you will see the corresponding video count is on the rise Ok, back end done, let’s go back to the front end and use this interface. Since there are no JS libraries referenced and no jquery used, we’ll just use the native web request, movie_list.html, and modify it to look like this

<! DOCTYPE HTML > < HTML lang="en"> <head> <meta charset=" utF-8 "> <title> video </title> <style>. Box-out {position:relative; #border:solid 1px #555; float:left; padding:0px 10px; } .box-in { position:absolute; left:0; top:0px; right:0; bottom:0; margin:auto; } .title-in { position:absolute; top:240px; left:0; right:0; margin:auto; text-align:center; height:50px; line-height:50px; font-size:18px; } </style> </head> <body> <div id="container"> {% for movie in movies %} <div class="box-out" style="height:280px; width:400px;" > <video class="movie box-in" data-file="{{movie['file']}}" width="400" height="225" controls > <source src="static/movies/{{movie['file']}}" type="video/mp4" /> </video> <p class="title-in" >{{movie['title']}}</p> </div> {% Function resetContentPos(){var div = document.getelementById ("container"); / / get the main container var allWidth = document. Body. ClientWidth; Var n = parseInt(allWidth / 420); Var contentWidth = n * 420; Div. Style. marginLeft = (allWidth-contentWidth)/2+"px"; Function (){resetContentPos();} (function(){resetContentPos(); / / adjust the page level center var movie_items = document. The getElementsByClassName (' movie '); For (var I =0; i<movie_items.length; I ++){// go through the video movie_items[I]. AddEventListener ('play',function(t){var filename = t.target.dataset. File; Var XHR = new XMLHttpRequest(); xhr.open('GET','incrMovie? name='+filename); xhr.setRequestHeader('Content-Type', 'text/plain'); Xhr.onreadystatechange = function(){// Response completed, If (xhr.readyState == 4&&xhr.status == 200){console.log(xhr.responsetext); }} // Send to server xhr.send(null); })}}) (); window.onresize = function(){ resetContentPos(); } </script> </body> </ HTML >Copy the code

Ok, so when we click play for different videos, we see that the count is increased again. Now, of course, we also count pauses and plays (if we want to count the play event once, then we change the Play event to ended event). We haven’t done sorting the number of plays yet. We’ll put that sort in the movie_list route, modify the movie_list function in main.py, and sort it by movies.sort(key=lambda x: X [‘count’], reverse=True) the entire code for movie_list is as follows

@web.route('/movieList')
def movie_list() :
    movies = xml_lib.read_movies()
    Sort by count; sort by descending
    movies.sort(key=lambda x: x['count'], reverse=True)
    return render_template('movie_list.html', movies=movies)
Copy the code

Okay, so now that we’re done, let’s go to different videos and click on it, refresh the page, and we’ll see that the videos are sorted by the number of times they’ve been played.There is also a concurrency pit. Due to the concurrency of the site, XML reads and writes may be triggered at the same time, so errors may occur. For security reasons, we need to introduce a thread lock for xml_lib reads and writes

from xml.dom.minidom import parse
import xml.dom.minidom
import threading

xml_file = 'file/movies.xml'

lock = threading.RLock()
def read_movies() :
    lock.acquire()  # lock ZhuDou
    DOMTree = xml.dom.minidom.parse(xml_file)
    lock.release()  # releases the lock
    root = DOMTree.documentElement
    movies = root.getElementsByTagName('movie')

    movie_arr = []
    for movie in movies:
        movie_dic = {}
        movie_dic['file'] = movie.getAttribute('file')
        movie_dic['title'] = movie.getAttribute('title')
        if movie.hasAttribute('count'):
            movie_dic['count'] = int(movie.getAttribute('count'))
        else:
            movie_dic['count'] = 0
        movie_arr.append(movie_dic)

    return movie_arr

def incr_movie(name) :
    movies = read_movies()  # Read the movie first
    dom = xml.dom.minidom.Document()  Create a DOM tree
    root_node = dom.createElement('root')  Create the root node
    dom.appendChild(root_node)  Add the root node to the DOM tree
    for movie_dic in movies:  # Loop over all movies read from XML
        movie_node = dom.createElement('movie')  Create the movie node
        filename = movie_dic['file']  Get the name from the dictionary
        movie_node.setAttribute('file', filename)  Set file to the movie node
        title = movie_dic['title']  Get the title in the dictionary
        movie_node.setAttribute('title', title)  Set the title property to the movie node
        count = movie_dic.get('count'.0)  # the number of hits to get the video in the dictionary, default to 0 if there are no hits
        if filename == name:  If you want to increase the click count, then click count +1
            count += 1
        movie_node.setAttribute('count'.str(count))  # set the count attribute to the movie node
        root_node.appendChild(movie_node)  Add the movie node to the root node

    lock.acquire()  # write lock
    with open(xml_file, 'w', encoding='utf-8') as fs:
        dom.writexml(fs, indent=' ', addindent='\t', newl='\n', encoding='UTF-8')
    lock.release()  # releases the lock
Copy the code

Finally, attach the complete code for main.py

from flask import Flask, render_template, request
web = Flask(__name__)
import xml_lib
@web.route('/')
def hello_world() :
    return 'Hello, World! '

@web.route('/movieList')
def movie_list() :
    movies = xml_lib.read_movies()
    Sort by count; sort by descending
    movies.sort(key=lambda x: x['count'], reverse=True)
    return render_template('movie_list.html', movies=movies)

@web.route('/incrMovie')
def incr_movie() :
    name = request.args.get('name')  Select name from request parameters
    xml_lib.incr_movie(name)
    return '1'

web.run(debug=True)
Copy the code