Mdwiki development road 2 resources and track record


1. Bootstrap snippet:

If you don’t have art cells, the way to be lazy is to look for them, such as the login box interface.
Sidebar selection:… Mentioned
Other resources:
A more dazzling HTML template (although not adopted in the end)
Bootstrap theme

2. CSS height of div: 100% invalid solution:

Add the following to the CSS:

html, body{ margin:0; height:100%; }

3. Alembic migration failed, SQLite lack of alter support solution:

Set in env.pyrender_as_batch=True


4. Markdown extension:…
More useful
Table of Contents(toc)、
Codehilite (code highlight)
Meta data (metadata can be added in front of the file, such as title, author, etc.)
New line to break
Tables (table plug-in)

5. About flask:

Implementation principle of flask request, G, session
Understand context in depth
Flash session timeout setting
By default, the flash session fails when you close the browser. You can change this behavior by setting the permanent session.

from datetime import timedelta
from flask import session, app

def make_session_permanent():
    session.permanent = True
    app.permanent_session_lifetime = timedelta(minutes=30)

By default, permanent session lifetime is 31 days.

6. About Sqlalchemy:

Sqlalchemy experience
SqlAlchemy query many-to-many relationship

class Restaurant(db.Model):

    dishes = db.relationship('Dish', secondary=restaurant_dish,

Then retrieve all dishes for a restaurant, you can do:

x = Dish.query.filter(Dish.restaurants.any(name=name)).all()

The following SQL statements are generated:

SELECT dish.*
FROM dish
    EXISTS (
        SELECT 1
        FROM restaurant_dish
   = restaurant_dish.dish_id
            AND EXISTS (
                SELECT 1
                FROM restaurant
                    restaurant_dish.restaurant_id =
                    AND = :name

7. How to solve the problem of circular import

1. Lazy import
That is, write the import statement in the method or function, and limit its scope to local.
The disadvantage of this method is that there will be performance problems.
2. Change from XXX import YYY to import XXX; xxx.yyy to access
3. Organization code
The problem of circular import often means that there is a problem with the layout of the code, and the competitive resources can be merged or separated. When merging, they are all written into one file. Separation is to extract the resources that need to be imported into a third-party file. In short, it is to turn the cycle into one-way.
Follow up articles of specific solutions and paste the code again

8. Some about Python:

Good logging practice in Python
How do I check if a variable exists?
To check the existence of a local variable:

if 'myVar' in locals():
  # myVar exists.

To check the existence of a global variable:

if 'myVar' in globals():
  # myVar exists.

To check if an object has an attribute:

if hasattr(obj, 'attr_name'):
  # obj.attr_name exists.
if('attr_name' in dir(obj)):

There is also a case in a less elegant place, by catching exceptions:

except NameError:
    myVar = None
# Now you're free to use myVar without Python complaining.

9. About GIT and GitHub

How do I delete a Git branch with TortoiseGit
Why is it not successful to tag git Library

How to modify the project language of the warehouse on GitHub?

Are projects often identified as JavaScript projects when they are placed in GitHub? This Q & A gives the answer.
Cause of the problem:
GitHub identifies project types based on the number of files in the project
terms of settlement:
Project root add.gitattributesThe contents of the document are as follows:

*.js linguist-language=python

Function: identify the. JS file in the project as Python language

10. About ide:

Indexing excluded directories in PyCharm
pycharm convert tabs to spaces automatically

11. About celery:

periodic task for celery sent but not executed
Because I didn’t read the official documents carefully, I worked on it for a long time. The periodic task scheduler of celery needs to configure beat and run beat process, but is it OK to only run beat process? No way! That’s where I got hit. You have to run a worker at the same time. That is to say, both beat and worker need to be run from the command line. For periodic tasks, beat is indispensable. Other tasks can only run workers.

12. Setting environment variables in supervisor or gunicorn

If in the form of the gunicorn command line: – e option

gunicorn -w 4 -b -k gevent -e aliyun_api_key=value,SECRET_KEY=mysecretkey app:app 

If it is in the form of file: raw? Env

import multiprocessing

bind = ""
workers = multiprocessing.cpu_count() * 2 + 1
proc_name = "mdwiki"
user = "nginx"
#group = "nginx"
loglevel = "info"
#errorlog = "/home/myproject/log/gunicorn.log"
raw_env = [

If you use supervisor to configure environment variables

command=/usr/bin/gunicorn -n mdwiki -w 4 -b -k gevent app:app