使用Flask和MongoDB构建一个Python笔记应用程序
由于其用户友好的语法,Python是一种非常容易学习的语言。此外,Python有很多开源的库,几乎Python的每一个用例都有一个现有的库。
Python有几个网络应用框架,如Django和Flask。Flask是一个开源的、轻量级的Python web应用框架。
Flask的设计是为了使一个简单的应用程序能够容易地启动和运行。
我们将使用MongoDB作为数据库。MongoDB是一个跨平台、面向文档的数据库平台。它使用JSON对象作为其数据图元。
当与一个网络应用程序一起工作时,你可能不知道被发送的确切数据格式。在这种情况下,像MongoDB这样的NoSQL数据库将是数据处理和存储的良好解决方案。
在这篇文章中,我们将使用Flask和MongoDB创建一个简单的笔记应用程序。
前提条件
要跟上这篇文章,以下基本信息是必不可少的。
- 使用Python的基本知识。
- 在你的电脑上安装[Python]。
- 在你的电脑上安装了[MongoDB]。
- 在你的计算机上安装[Pip]。
设置Flask应用程序
我们将使用virtualenv来设置应用程序。Virtualenv 是一个用于创建独立 Python 环境的工具。它可以防止全局安装只在单个应用程序中使用的依赖项。
运行下面的命令来安装virtualenv。
pip install virtualenv
为了测试virtualenv是否正确安装,运行下面的命令。
virtualenv --version
要启动,在你希望项目所在的项目文件夹中运行以下命令。
virtualenv venv
如果环境没有被自动激活,在左边有你的项目文件夹的名字,那么运行下面的命令来激活它。
source venv/bin/activate
激活后,我们需要两个依赖项。
- flask - 它对于设置网络资源是必不可少的。
- PyMongo - 这将形成从MongoDB到我们应用程序的基础设施。
要安装这些依赖项,请使用下面的命令。
pip install flask PyMongo
设置MongoDB
为了开始在我们的应用程序中设置MongoDB,我们需要在项目根目录下创建一个app.py 文件。这将是我们的主文件。
在这个app.py 文件中,添加以下代码块。
from flask import Flask
from flask_pymongo import PyMongo
app = Flask(__name__)
app.config["MONGO_URI"] = "mongodb://localhost:27017/flaskCrashCourse"
mongo = PyMongo(app)
if __name__ == "__main__":
app.run(debug=True)
在这里,我们已经为一个基本的Flask应用程序做了基本配置。我们。
- 已经导入了必要的包。
- 设置了主
app变量。 - 初始化了一个
PyMongo的实例。 - 在
debug模式下启动应用程序。这意味着我们对应用程序所做的每一个改动都会被自动重新加载。
为了测试这一点,运行下面的命令。
python3 app.py
上面的命令将启动该应用程序。你可以从端口号5000访问它;即:http://localhost:5000 。现在,你将得到一个Not Found ,因为我们还没有定义任何路由。
让我们在下一步骤中讨论这个问题。
设置路由
首先,让我们从flask ,导入request 模块。
from flask import request, Flask
我们将有四个路由。
- 获取笔记的路由。
- 添加笔记的路线。
- 编辑笔记的路线。
- 删除笔记的路线。
让我们从添加获取笔记的路由开始。这将是一个主页。
在你的app.py 文件中添加以下内容。
@app.route('/')
def home():
return "<p>The home page</p>"
每当人们访问主页(/)时,装饰器将执行下面的函数,它将返回一个段落。
让我们为add-note 路由、edit-note 路由和delete-note 路由做同样的事情,添加以下代码。
@app.route('/add-note', methods=['GET','POST'])
def addNote():
if(request.method == "GET"):
return "<p>Add note page</p>"
elif (request.method == "POST"):
# logic for adding a note
@app.route('/edit-note', methods=['GET','POST'])
def editNote():
if(request.method == "GET"):
return "<p>Edit note page</p>"
elif (request.method == "POST"):
#logic for editing a note
@app.route('/delete-note', methods=['POST'])
def deleteNote():
# logic for deleting a note
add-note 途径接受两个方法;当用户访问该页面时,GET 笔记,当用户提交包含新笔记细节的填写表格时,POST 。
同样适用于edit-note ;当用户访问该页面时,GET ,当用户在该页面提交表单时,POST 。
在这一点上,我们只返回页面的段落。我们需要返回更多的视觉内容,并处理那些不返回页面的路由的注释逻辑。我们在下一步做这个。
为路由添加逻辑和模板
首先,我们将从render_template 和redirect 模块中导入flask 。
from flask import request,Flask,render_template,redirect
顾名思义,render_template 将加载一个HTML 模板文件,而redirect 将在从一个路由重定向到另一个路由时被调用,特别是那些不返回页面的路由。
在模板上工作
在项目根目录下,创建一个文件夹,并将其命名为templates 。在该文件夹中,创建一个base.html 文件并添加以下代码。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link
rel="stylesheet"
href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css"
integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm"
crossorigin="anonymous"
/>
<title>{% block title%} {% endblock %}</title>
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<a class="navbar-brand" href="#">Notes app</a>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav mx-auto">
<li class="nav-item {{ 'active' if homeIsActive == True }}">
<a class="nav-link" href="/">Home</a>
</li>
<li class="nav-item {{ 'active' if addNoteIsActive == True }}">
<a class="nav-link" href="/add-note">Add note</a>
</li>
</ul>
</div>
</nav>
{% block content %} {% endblock %}
<footer>
<hr />
<p class="text-center">Notes app</p>
</footer>
</body>
</html>
为了提高代码的重用性,所有的模板都将从一个基础文件中加载。此外,由于Flask使用Jinja进行模板制作,动态内容将被加载到每个页面。
根据上面的文件,每个页面只有title 和body content 会有所不同,这也是我们在简单应用中想要的。
主页路线
在templates文件夹中,创建一个pages 文件夹。在里面,创建一个home.html 文件并添加以下代码。
{% extends 'base.html'%} {% block title %} Home {% endblock %} {% block content
%}
<div class="container mt-5 mb-5 px-10 ">
<div class="row">
{% if (notes is defined) and notes %} {% for note in notes %}
<div class="col-md-6 offset-md-3 mb-2 ">
<div class="card">
<div class="card-body">
<p class="card-text text-muted">
{{ note['createdAt'].strftime('%Y-%m-%d') }}
</p>
<h4 class="card-title">{{ note['title'] }}</h4>
<p class="card-text">{{ note['description'] }}</p>
<div class="d-flex justify-content-between">
<a href="/edit-note?form={{ note['_id'] }}" class="btn btn-primary">
Edit
</a>
<form method="POST" action="/delete-note">
<input type="hidden" name="_id" value="{{ note['_id'] }}" />
<button type="submit" class="btn btn-danger">Delete</button>
</form>
</div>
</div>
</div>
</div>
{% endfor %} {% else %}
<div class="col-md-6 offset-md-3 text-center">
<h4>You have not added any notes</h4>
<a href="/add-note" class="btn btn-primary"> Add note </a>
</div>
{% endif %}
</div>
</div>
{% endblock %}
在上面的文件中,我们是。
- 扩展我们之前创建的基础文件。
- 设置页面的标题。
- 设置页面的主体,包括检查我们是否有添加的注释。如果有,我们就循环查看,或者输出一条信息和一个行动呼吁。对于每个笔记,我们都要显示其创建日期、标题和描述。
在app.py ,编辑home 路线函数,如下图所示。
@app.route("/")
def home():
# get the notes from the database
notes = list(mongo.db.notes.find({}).sort("createdAt",-1));
# render a view
return render_template("/pages/home.html",homeIsActive=True,addNoteIsActive=False,notes=notes)
在home() 函数中,我们正在。
- 从数据库中获取笔记;按降序排列。
- 返回一个视图,传递数据。
homeIsActive和addNoteIsActive为导航条,设置活动页面,notes为获取的数据。
为了测试这个主页路线,确保你的应用程序正在运行,并在浏览器上刷新页面。由于你没有任何添加的笔记,你将会收到一条信息和一个行动呼吁。
添加注释的路径
在templates/pages ,创建一个文件add-note.html 。在这个文件中,添加以下代码。
{% extends 'base.html'%} {% block title %} Add note {% endblock %} {% block
content %}
<div class="container mt-5 mb-5 px-10 ">
<div class="row">
<div class="col-md-6 offset-md-3">
<form method="POST" action="/add-note">
<div class="form-group">
<label for="title">Title</label>
<input
type="text"
class="form-control"
id="title"
aria-describedby="noteTitle"
placeholder="Enter note title"
name="title"
required
/>
<small id="noteTitle" class="form-text text-muted"
>E.g My new room.</small
>
</div>
<div class="form-group">
<label for="description">Description</label>
<textarea
id="description"
name="description"
class="form-control"
placeholder="Some description"
aria-describedby="description"
required
>
</textarea>
<small id="description" class="form-text text-muted"
>E.g My new room number is 1234.</small
>
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
</div>
</div>
</div>
{% endblock %}
在上面的文件中,我们正在
- 扩展普通的
base.html文件。 - 设置标题。
- 设置正文,它是一个带有标题和描述字段的表单。
在app.py 中,编辑addNote() 函数如下。
@app.route("/add-note", methods=['GET','POST'])
def addNote():
if(request.method == "GET"):
return render_template("pages/add-note.html",homeIsActive=False,addNoteIsActive=True)
elif (request.method == "POST"):
# get the fields data
title = request.form['title']
description = request.form['description']
createdAt = datetime.datetime.now()
# save the record to the database
mongo.db.notes.insert({"title":title,"description":description,"createdAt":createdAt})
# redirect to home page
return redirect("/")
当我们在上面的函数中有一个GET 的调用时,我们只是返回一个带有导航栏配置变量的视图。
当我们有一个POST 的调用时,我们得到从表单提交的数据,将其保存到数据库,并重定向到主页。
为了测试该功能,确保开发服务器正在运行,并刷新add-note 页面。你应该看到一个表单,当你填写并提交时,你将被重定向到主页;现在有一个保存的笔记。
编辑笔记的途径
在templates/pages 文件夹中,创建一个edit-note.html 文件。在该文件中,添加以下代码。
{% extends 'base.html'%} {% block title %} Edit note {% endblock %} {% block
content %}
<div class="container mt-5 mb-5 px-10 ">
<div class="row">
<div class="col-md-6 offset-md-3">
<form method="POST" action="/edit-note">
<input type="hidden" name="_id" value="{{ note._id }}" />
<div class="form-group">
<label for="title">Title</label>
<input
type="text"
class="form-control"
id="title"
aria-describedby="noteTitle"
placeholder="Enter note title"
name="title"
value="{{ note.title }}"
required
/>
<small id="noteTitle" class="form-text text-muted"
>E.g My new room.</small
>
</div>
<div class="form-group">
<label for="description">Description</label>
<textarea
id="description"
name="description"
class="form-control"
placeholder="Some description"
aria-describedby="description"
required
>
{{ note.description }}</textarea
>
<small id="description" class="form-text text-muted"
>E.g My new room number is 1234.</small
>
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
</div>
</div>
</div>
{% endblock %}
在上面的文件中,我们扩展了普通的base.html 文件,添加了一个标题和一个正文内容;只是一个预先填写了特定笔记数据的表格。
在app.py 中,编辑editNote 函数如下。
@app.route('/edit-note', methods=['GET','POST'])
def editNote():
if request.method == "GET":
# get the id of the note to edit
noteId = request.args.get('form')
# get the note details from the db
note = dict(mongo.db.notes.find_one({"_id":ObjectId(noteId)}))
# direct to edit note page
return render_template('pages/edit-note.html',note=note)
elif request.method == "POST":
#get the data of the note
noteId = request.form['_id']
title = request.form['title']
description = request.form['description']
# update the data in the db
mongo.db.notes.update_one({"_id":ObjectId(noteId)},{"$set":{"title":title,"description":description}})
# redirect to home page
return redirect("/")
在上面的函数中,我们有两个调用。
- 一个
GET调用,在这里我们使用它的 id 从数据库中获得笔记的细节,并使用这些细节渲染表单。 - 一个
POST,我们从表单中获得更新的细节,并从数据库中更新笔记,之后你会被重定向到主页。
为了测试这个功能。
- 确保开发服务器正在运行。
- 刷新主页。
- 对于任何笔记,点击编辑,编辑任何字段,然后点击
Submit。新的细节应该被反映出来。
删除笔记的途径
在app.py ,编辑deleteNote ,如下所示。
@app.route('/delete-note', methods=['POST'])
def deleteNote():
# get the id of the note to delete
noteId = request.form['_id']
# delete from the database
mongo.db.notes.delete_one({ "_id": ObjectId(noteId)})
# redirect to home page
return redirect("/")
从上面的函数中,我们得到要删除的笔记的id ,从数据库中删除它,并把它重定向到主页。
为了测试这个功能。
- 确保开发服务器正在运行。
- 刷新主页。
- 对于任何笔记,点击删除;它应该被成功删除。
总结
在这篇文章中,我们使用Flask和MongoDB构建了一个简单的笔记应用。