程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式師世界 >> 編程語言 >  >> 更多編程語言 >> Python

Python back-end flask learning project practice - build a Q & a website

編輯:Python

1. Project effect display

This is mainly the rear end , The front-end code is not shown , If you need code, you can comment or send a private letter

User registration 、 Login related :

Register with mailbox , And send the verification code to the mailbox to judge , A mailbox can only register one account

 

  Home page related :

Users can post questions and answer after logging in , It also provides search function , Show all the questions on the front page

  Search for :

 

  Comment on :

 

2. Project engineering catalog

blueprints:

The project blueprint includes the logical implementation of Q & A and the logical time of users

migrations:

Project database migration

static、templates:

Front-end correlation ,css、html Documents, etc.

3. Project implementation :

3.1 database

The main thing is to design a user table user surface , A mailbox corresponds to a verification code EmailCaptcha Table of , A problem question surface , A comment Answer surface

utilize flask Provided in SQLAlchemy We don't have to write it ourselves SQL Code , Just use object-oriented thinking

(1) newly build db object

Because it is needed in many files db object , So use a special file etx.py Store , And in app.py Initialize in :

etx.py:

from flask_mail import Mail
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
mail = Mail()

app.py:

app = Flask(__name__)
# Configuration item
app.config.from_object(config)
db.init_app(app)
mail.init_app(app)
migrate = Migrate(app, db)
# Assembly blueprint take book、course、user Modules are assembled in main.py in
app.register_blueprint(qa_bp)
app.register_blueprint(user_bp)

(2) Configuration database :

# Configuration variables of the database
HOSTNAME = '127.0.0.1'
PORT = '3306'
DATABASE = 'flask'
USERNAME = 'root'
PASSWORD = '*****'
DB_URI = 'mysql+pymysql://{}:{}@{}:{}/{}'.format(USERNAME, PASSWORD, HOSTNAME, PORT, DATABASE)
SQLALCHEMY_DATABASE_URI= DB_URI
# Close database modification tracking operation [ Improve performance ], It can be set to True, This allows you to track operations :
SQLALCHEMY_TRACK_MODIFICATIONS=False
# Turn on the output of the underlying execution sql sentence
SQLALCHEMY_ECHO = True

(3) Design models:

from exts import db
class EmailCaptchaModel(db.Model):
__tablename__="email_captcha"
id=db.Column(db.Integer,primary_key=True,autoincrement=True)
email=db.Column(db.String(100),nullable=True,unique=True)
captcha=db.Column(db.String(10),nullable=False)
create_time=db.Column(db.DateTime)
class UserModel(db.Model):
__tablename__ = "user"
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
username = db.Column(db.String(200),nullable=False,unique=True)
email = db.Column(db.String(100),nullable=False,unique=True)
password = db.Column(db.String(200),nullable=False)
join_time = db.Column(db.DateTime)
class QuestionModel(db.Model):
__tablename__ = "question"
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
title = db.Column(db.String(200), nullable=False)
content = db.Column(db.Text,nullable=False)
create_time = db.Column(db.DateTime)
author_id = db.Column(db.Integer,db.ForeignKey("user.id"))
author = db.relationship("UserModel",backref="questions")
class AnswerModel(db.Model):
__tablename__ = "answer"
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
content = db.Column(db.Text,nullable=False)
create_time = db.Column(db.DateTime)
question_id = db.Column(db.Integer,db.ForeignKey("question.id"))
author_id = db.Column(db.Integer, db.ForeignKey("user.id"))
question = db.relationship("QuestionModel",backref=db.backref("answers",order_by=create_time.desc()))
author = db.relationship("UserModel",backref="answers")

(4) Generate database

utilize flask The database migration function provided in can be migrated directly after updating the database

Enter... On the command line

step1:

flask db init

After this statement is executed, the... In the above file will be generated migrate Folder

step2:

flask db migrate

step3:

flask db upgrade

Update complete !

3.2 Send mail function

Click send verification code during registration and send verification code information to the registered mailbox through a fixed mailbox , At the same time, it is stored in the database to verify whether the input verification code is consistent with the received verification code .

Mainly to make use of flask_mail Send by email .

(1) Mailbox settings

# Mailbox configuration
# What is used in the project QQ mailbox
MAIL_SERVER = "smtp.qq.com"
MAIL_PORT = 465
MAIL_USE_TLS = False
MAIL_USE_SSL = True
MAIL_DEBUG = True
MAIL_USERNAME = "[email protected]"
MAIL_PASSWORD = "*****"
MAIL_DEFAULT_SENDER = "[email protected]"

(2) Get the verification code

You can test in the browser

@bp.route("/captcha", methods=['POST'])
def get_captcha():
email = request.form.get("email")
# from letters Random extraction from the set 4 Generated verification code letters A set is a collection of English and numbers
letters = string.ascii_letters + string.digits
captcha = "".join(random.sample(letters, 4))
if email:
message = Message(
subject=" Mailbox test ",
recipients=[email],
body=f" Your registration verification code is :{captcha}"
)
mail.send(message)
# Store in database : Through the first email The query , If the email Just update captcha Just go , If it doesn't exist, add a record
captcha_model = EmailCaptchaModel.query.filter_by(email=email).first()
if captcha_model:
captcha_model.captcha = captcha
# captcha_model.create_time=datetime.time.now()
db.session.commit()
else:
captcha_model = EmailCaptchaModel(email=email, captcha=captcha)
db.session.add(captcha_model)
db.session.commit()
print("captcha:", captcha)
return jsonify({"code": 200, "message": "suceess"})
else:
return jsonify({"code": 400, "message": "mail It's empty "})

3.3  User registration and login 、 Log out

(1) Determine whether the registration and login forms meet the requirements

Can be used directly flask Medium wtforms Format restrictions :

Create a new one forms.py:

import wtforms
from wtforms.validators import length,email,EqualTo,InputRequired
from models import EmailCaptchaModel,UserModel
class LoginForm(wtforms.Form):
email = wtforms.StringField(validators=[email()])
password = wtforms.StringField(validators=[length(min=6,max=20)])
class RegisterForm(wtforms.Form):
username = wtforms.StringField(validators=[length(min=3,max=20,message=" The length is in 3 and 20 Between ")])
email = wtforms.StringField(validators=[email()])
captcha = wtforms.StringField(validators=[length(min=4, max=4)])
password = wtforms.StringField(validators=[length(min=6,max=20,message=" The length is in 6 and 20 Between ")])
password_confirm = wtforms.StringField(validators=[EqualTo("password")])
def validate_captcha(self,field):
captcha = field.data
email = self.email.data
captcha_model = EmailCaptchaModel.query.filter_by(email=email).first()
print(captcha_model.captcha)
if not captcha_model or captcha_model.captcha.lower() != captcha.lower():
print(" Verification code error ")
raise wtforms.ValidationError(" Mailbox verification code error !")
def validate_email(self,field):
email = field.data
user_model = UserModel.query.filter_by(email=email).first()
if user_model:
print(" The mailbox already exists ")
raise wtforms.ValidationError(" The mailbox already exists !")
class QuestionForm(wtforms.Form):
title = wtforms.StringField(validators=[length(min=3, max=200)])
content = wtforms.StringField(validators=[length(min=5)])
class AnswerForm(wtforms.Form):
content = wtforms.StringField(validators=[length(min=1)])

(2) register

Registration is mainly to judge whether the format is correct , And determine whether the verification code is correct , If correct , A new generation user Object inserted into user In the table . At the same time, the password is encrypted for storage

@bp.route('/register', methods=['GET', 'POST'])
def register():
if request.method == 'GET':
return render_template("register.html")
else:
form = RegisterForm(request.form)
if form.validate():
print(" Verify success ")
username = form.username.data
email = form.email.data
password = form.password.data
# Password encryption
hash_password = generate_password_hash(password=password)
captcha = form.captcha.data
create_time = datetime.datetime.now()
# 1. adopt email Inquire about user surface If it exists, notify the user that it already exists New if it doesn't exist
user_model = UserModel.query.filter_by(email=email).first()
if user_model:
print(" The mailbox has been registered , Please re-enter ")
return redirect(url_for("user.register"))
user = UserModel(username=username, email=email, password=hash_password, join_time=create_time)
db.session.add(user)
db.session.commit()
return redirect(url_for("user.login"))
else:
print(" Registration verification failed ")
return redirect(url_for("user.register"))

(3) Sign in

First, check whether this user exists , If yes, perform password verification

@bp.route('/login', methods=['GET', 'POST'])
def login():
""" Sign in :guest1:123456
0. Pass the verification
1. Find out by email user_model
2. If it exists, compare whether the password is correct correct : Login successful Incorrect : Wrong password
3. Does not exist directly prompts the user that does not exist and returns to the registration page """
if request.method == 'GET':
return render_template("login.html")
else:
form = LoginForm(request.form)
if form.validate():
email = form.email.data
password_input = form.password.data
user_model = UserModel.query.filter_by(email=email).first()
if user_model:
if check_password_hash(user_model.password, password=password_input):
print(" Login successful ")
session['user_id'] = user_model.id
return redirect("/")
else:
print(" Wrong password ")
flash(" Wrong password ")
return redirect(url_for("user.login"))
else:
print(" The user does not exist , Please register ")
flash(" The user does not exist , Please register ")
return redirect(url_for("user.register"))
else:
print(" Please enter the account or password in the correct format ")
flash(" Please enter the account or password in the correct format ")
return redirect(url_for("user.login"))

(4) Log out

Delete session that will do

@bp.route('/logout')
def logout():
session.clear() # eliminate session Can be
return redirect(url_for("user.login"))

3.4  Access page permission management

Users cannot publish Q & a when they are not logged in , This can be achieved by using a decorator

""" Decorator """
from flask import g, redirect, url_for
from functools import wraps
""" If you are not logged in, you cannot access , Go to the login page If you are logged in, the normal logic processing """
def login_required(func):
@wraps(func)
def wrapper(*args, **kwargs):
if hasattr(g, "user"):
return func(*args, **kwargs)
else:
print(" Cannot access without logging in ")
return redirect(url_for("user.login"))
return wrapper

Add... To the method that requires access restriction

@bp.route('/public_question', methods=['GET', 'POST'])
@login_required
def public_question():

You can set the access permissions !!!

3.5 Q & a view 、 Search for

Q & a function : In fact, it is to generate a QuestionModel, Will meet the requirements of Question Store in database

(1)QuestionModel:

class QuestionModel(db.Model):
__tablename__ = "question"
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
title = db.Column(db.String(200), nullable=False)
content = db.Column(db.Text,nullable=False)
create_time = db.Column(db.DateTime)
author_id = db.Column(db.Integer,db.ForeignKey("user.id"))
author = db.relationship("UserModel",backref="questions")

(2) Form validation :

class QuestionForm(wtforms.Form):
title = wtforms.StringField(validators=[length(min=3, max=200)])
content = wtforms.StringField(validators=[length(min=5)])

(3) Q & a function

@bp.route('/public_question', methods=['GET', 'POST'])
@login_required
def public_question():
""" Post Q & A """
if request.method == 'GET':
return render_template("public_question.html")
else:
form = QuestionForm(request.form)
if form.validate():
title = form.title.data
content = form.content.data
create_time = datetime.datetime.now()
question = QuestionModel(title=title, content=content, author=g.user, create_time=create_time)
db.session.add(question)
db.session.commit()
print(" Successful Q & a release ")
return redirect(url_for("qa.index"))
else:
flash(" Incorrect format ")
return redirect(url_for("qa.public_question"))

(4) Problem details view

@bp.route("/question/<int:question_id>")
def question_detail(question_id):
question = QuestionModel.query.get(question_id)
return render_template("detail.html", question=question)

(5) Problem search

You can query and search in both title and content , Only if one of them is met, it will be output

@bp.route('/search')
def search():
q = request.args.get("q")
questions = QuestionModel.query.filter(
or_(QuestionModel.title.contains(q), QuestionModel.content.contains(q))).order_by(db.text("create_time"))
print(" The search results ", questions == None)
if questions:
return render_template("index.html", questions=questions)
else:
print(" Search results are empty ")
return " Search results are empty "

3.6 Comment function

Comments can be made after posting questions , A process consistent with the problem

(1) Generate AnswerModel:

class AnswerModel(db.Model):
__tablename__ = "answer"
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
content = db.Column(db.Text,nullable=False)
create_time = db.Column(db.DateTime)
question_id = db.Column(db.Integer,db.ForeignKey("question.id"))
author_id = db.Column(db.Integer, db.ForeignKey("user.id"))
question = db.relationship("QuestionModel",backref=db.backref("answers",order_by=create_time.desc()))
author = db.relationship("UserModel",backref="answers")

(2) Generate form validation :

class AnswerForm(wtforms.Form):
content = wtforms.StringField(validators=[length(min=1)])

(3) Comment

@bp.route("/answer/<int:question_id>", methods=['POST'])
@login_required
def answer(question_id):
form = AnswerForm(request.form)
if form.validate():
content = form.content.data
create_time = datetime.datetime.now()
answer_model = AnswerModel(content=content, author=g.user, question_id=question_id, create_time=create_time)
db.session.add(answer_model)
db.session.commit()
return redirect(url_for("qa.question_detail", question_id=question_id))
else:
flash(" Form validation failed !")
return redirect(url_for("qa.question_detail", question_id=question_id))

4. summary

It is a simple small project to practice hands , Novices can see this to get started directly , But the project also needs to be improved , For example, you can also set up avatars for registration , In this way, you can display your avatar on the home page .


  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式師世界 All Rights Reserved