如何使用Flask和MongoDB构建一个Python笔记应用程序

546 阅读8分钟

使用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_templateredirect 模块中导入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进行模板制作,动态内容将被加载到每个页面。

根据上面的文件,每个页面只有titlebody 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() 函数中,我们正在。

  • 从数据库中获取笔记;按降序排列。
  • 返回一个视图,传递数据。homeIsActiveaddNoteIsActive 为导航条,设置活动页面,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构建了一个简单的笔记应用。