在本教程中,我们将使用 Flask 构建 URL 缩短器。此工具接受任何 URL 并生成更短、更易读的版本,如 bit.ly .
该应用程序将允许用户输入一个 URL 和一个可选的自定义短 ID,并生成一个更短的版本。
以下是我们要构建的内容:
该应用程序的前端并不吸引人,因为该项目的主要重点是构建后端项目。
一些示例缩短的 URL 是 https://shorty-flask.herokuapp.com/mzkpK8sw 和 https://shorty-flask.herokuapp.com/linkify .
创建虚拟环境并安装依赖项
在本教程中,我们将使用 Pipenv 来管理我们的虚拟环境。
Pipenv 是一款工具,可自动为您的项目创建和管理虚拟环境,并在 Pipfile
您安装/卸载软件包时添加/删除软件包。它还会生成至关重要的 Pipfile.lock
,用于生成确定性构建。
您可以阅读 本文 以了解更多信息。
Pipenv 是一个外部库,我们需要明确安装它。要安装该库,请使用 pip 命令:
pip install pipenv
安装完成后,我们可以创建一个虚拟环境并使用以下命令激活它:
pipenv shell
要停用虚拟环境,我们有一个简单的命令:
exit
创建并激活虚拟环境后,就可以安装所需的库了。
-
p12
pipenv install Flask
-
p13
pipenv install Flask-Migrate
-
p14
pipenv install Flask-SQLAlchemy
-
第15页
pipenv install psycopg2
-
p16
pipenv install gunicorn
-
p17
pipenv install python-decouple
如何设置Flask项目
我们要做的第一件事是创建一个 Flask 项目。如果你查看 Flask 的 官方文档 最小的应用程序 。
但是,我们不会遵循这一点。我们将编写一个更具扩展性且具有良好基础结构的应用程序。如果您愿意,可以按照 本指南 开始使用 Flask。
包中 的 core 。要将普通目录转换为 Python 包,我们只需包含一个 __init__.py
文件。因此,让我们首先创建核心包。
$ mkdir core
之后,让我们 __init__.py
在核心目录中创建文件:
$ cd core
$ touch __init__.py
$ cd ..
在项目的根目录中,创建一个名为 的文件 config.py
。我们将在此文件中存储项目的配置。在文件中,添加以下内容:
from decouple import config
DATABASE_URI = config("DATABASE_URL")
if DATABASE_URI.startswith("postgres://"):
DATABASE_URI = DATABASE_URI.replace("postgres://", "postgresql://", 1)
class Config(object):
DEBUG = False
TESTING = False
CSRF_ENABLED = True
SECRET_KEY = config('SECRET_KEY', default='guess-me')
SQLALCHEMY_DATABASE_URI = DATABASE_URI
SQLALCHEMY_TRACK_MODIFICATIONS = False
class ProductionConfig(Config):
DEBUG = False
class StagingConfig(Config):
DEVELOPMENT = True
DEBUG = True
class DevelopmentConfig(Config):
DEVELOPMENT = True
DEBUG = True
class TestingConfig(Config):
TESTING = True
在上面的脚本中,我们创建了一个 Config
类并在其中定义了各种属性。此外,我们还创建了继承该类的不同子类(根据不同的开发阶段) Config
。
请注意,我们正在使用一些环境变量,例如 SECRET_KEY 和 DATABASE_URL 在根目录中 .env
创建一个名为的文件
SECRET_KEY=verysecretkey
DATABASE_URL=sqlite:///shorty.db
APP_SETTINGS=config.DevelopmentConfig
FLASK_APP=core
除了 SECRET_KEY 和 DATABASE_URL ,我们还指定了 APP_SETTINGS 和 FLASK_APP .
的 APP_SETTINGS 类之一 config.py
。我们将其设置为项目的当前阶段。是 的值 FLASK_APP 我们创建的包的名称。
现在,我们可以在文件中添加以下内容 core/__init__.py
:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
from decouple import config
app = Flask(__name__)
app.config.from_object(config("APP_SETTINGS"))
db = SQLAlchemy(app)
migrate = Migrate(app, db)
from core import routes
在上面的 Python 脚本中,我们首先从已安装的 Flask 模块导入 Flask 类。接下来,我们创建 app
Flask 类的对象。我们使用参数 __name__
来指示应用程序的模块或包,以便 Flask 知道在哪里找到其他文件(例如模板)。
根据文件中的变量 将应用程序配置设置为 APP_SETTINGS .env
。要在我们的应用程序中使用 Flask-SQLAlchemy 和 Flask-Migrate,我们只需要 SQLAlchemy
从 Migrate
和 flask_sqlalchemy
类和 flask_migrate
。
然后应用程序导入 routes
尚不存在的模块。
要运行该应用程序,我们将使用 main.py
包含以下内容的文件:
from core import app
if __name__ == '__main__':
app.run()
如何创建数据库表
为了定义数据库表,我们将 models.py
在核心包中创建一个文件。在其中,我们可以编写以下代码:
from core import db
from datetime import datetime
class ShortUrls(db.Model):
id = db.Column(db.Integer, primary_key=True)
original_url = db.Column(db.String(500), nullable=False)
short_id = db.Column(db.String(20), nullable=False, unique=True)
created_at = db.Column(db.DateTime(), default=datetime.now(), nullable=False)
我们首先导入了 db
在文件中初始化的对象 __init__.py
。然后我们创建一个 ShortUrls
类,其中包含一些字段,例如 id (主键)、 original_url (由用户提供)、 short_id (由我们生成或由用户提供)和 created_at (时间戳)。
然后我们可以使用 Flask-Migrate 命令将新表迁移到数据库。我们将使用的命令是:
-
flask db init
— 开始时初始化数据库(仅使用一次) -
flask db migrate
— 将新的更改迁移到数据库(每次我们在数据库表中进行更改时使用) -
flask db upgrade
— 使用新的更改升级我们的数据库(与迁移命令一起使用)
运行数据库初始化后,我们将 在项目中 migrations
在“migrations”中,我们将看到它有一个名为“versions”的文件夹,其中包含创建的迁移脚本。
如何创建缩短网址的主页
在此步骤中,我们将为索引页创建一个 Flask 路由,该路由将允许用户输入 URL,然后我们会将该 URL 保存到数据库中。此路由将使用用户提供的自定义短 ID 或自行生成一个短 ID,构造短 URL,然后将其呈现为结果。
首先,让我们 routes.py
在核心包中创建一个文件并创建一个 Python 函数来生成短 ID。
from random import choice
import string
def generate_short_id(num_of_chars: int):
"""Function to generate short_id of specified number of characters"""
return ''.join(choice(string.ascii_letters+string.digits) for _ in range(num_of_chars))
为了生成短 ID,我们使用了 Python 随机 选择 。此外,我们还使用了 Python 内置的 字符串 模块来处理字母(小写 + 大写)和数字。
现在,我们需要为索引路由提供的索引页创建一个模板。此模板将有一个简单的表单,用户可以在其中输入原始 URL 和自定义短 ID(可选)并提交。
但我们不会 index.html
直接创建。我们可以使用 Jinja2 中的模板继承概念。因此,让我们在包中创建一个 templates 目录 core
并 base.html
在其中创建一个文件。您可以将 HTML 代码粘贴到该文件中。
{% block title %} {% endblock %}
{% for message in get_flashed_messages() %}
{{ message }}
{% endfor %}
{% block content %} {% endblock %}
请注意,对于样式,我们在这里使用 Bootstrap 。
上述代码块中的大部分代码都是 Bootstrap 所需的标准 HTML 代码。 <meta>
标签为 Web 浏览器提供信息,标签 <link>
链接 Bootstrap CSS 文件,标签 <script>
链接到允许一些其他 Bootstrap 功能的 JavaScript 代码。
您可以查看 Bootstrap 文档 以获取更多信息。
该 <title>{% block title %} {% endblock %}</title>
标签允许继承模板定义自定义标题。
我们使用 for message in get_flashed_messages()
循环来显示闪现的消息(警告、警报等)。
占位 {% block content %} {% endblock %}
符是继承模板放置内容的地方,以便所有模板都可以访问这个基本模板,从而避免重复。
接下来,创建 index.html
将扩展此 base.html
文件的文件:
{% extends 'base.html' %}
{% block content %}
{% block title %} Welcome to Shorty {% endblock %}
{% if short_url %}
{{ short_url }}
{% endif %}
{% endblock %}
在这里,我们扩展 base.html
、定义标题,并创建一个包含两个输入的表单,名为 url
和 custom_id
.
输入 url
框允许用户输入要缩短的 URL。它的值为 request.form['url']
,用于在提交失败的情况下(即用户未提供 URL)存储数据。同样, custom_id
输入框允许用户输入自定义短 ID。然后我们有一个提交按钮。
然后我们检查 short_url
变量是否有任何值——如果表单提交并且短网址生成成功,则为真。如果条件为真,我们将在表单下显示短网址。
现在我们可以重写我们的索引视图函数如下 routes.py
:
from datetime import datetime
from core.models import ShortUrls
from core import app, db
from random import choice
import string
from flask import render_template, request, flash, redirect, url_for
def generate_short_id(num_of_chars: int):
"""Function to generate short_id of specified number of characters"""
return ''.join(choice(string.ascii_letters+string.digits) for _ in range(num_of_chars))
@app.route('/', methods=['GET', 'POST'])
def index():
if request.method == 'POST':
url = request.form['url']
short_id = request.form['custom_id']
if short_id and ShortUrls.query.filter_by(short_id=short_id).first() is not None:
flash('Please enter different custom id!')
return redirect(url_for('index'))
if not url:
flash('The URL is required!')
return redirect(url_for('index'))
if not short_id:
short_id = generate_short_id(8)
new_link = ShortUrls(
original_url=url, short_id=short_id, created_at=datetime.now())
db.session.add(new_link)
db.session.commit()
short_url = request.host_url + short_id
return render_template('index.html', short_url=short_url)
return render_template('index.html')
该 index()
函数是 Flask 视图函数 装饰器 @app.route
修饰的函数 。它的返回值被转换成 HTTP 响应,供 HTTP 客户端(例如 Web 浏览器)显示。
内部 index()
给 methods=['GET', 'POST']
来接受 GET 和 POST 请求 app.route()
。
然后,如果请求是 GET 请求,它会跳过条件 if request.method == 'POST'
直到最后一行。在这里我们渲染一个名为的模板 index.html
,它将包含一个表单,供用户输入要缩短的 URL。
如果请求是 POST 请求,则 if request.method == 'POST'
条件为真,这意味着用户已提交 URL。我们将 URL 存储在变量中 url
。如果用户提交了空表单,则闪现该消息 The URL is required!
并重定向到索引页。
如果用户输入了 custom_id
,我们将其存储在 short_id ,否则我们使用之前创建的函数生成随机短id。
如果用户提交了 URL,我们将创建一个 new_link
包含所有数据(如 original_url
short_id
和 )的 created_at
。然后我们提交交易。
然后,我们使用 构造短 URL request.host_url
,这是 Flask 对象提供的属性, request
用于访问应用程序主机的 URL。这将 http://127.0.0.1:5000/
在开发环境中以及 our_domain
我们部署应用程序时使用。
例如, short_url
变量将具有一个类似于的值 http://127.0.0.1:5000/asdf1gHJ
,它是将用户重定向到存储在数据库中的原始 URL 的短 URL,其 ID 与 asdf1gHJ
.
最后,我们通过 index.html
传递 short_url
给模板来渲染模板。
我们现在可以运行服务器并测试我们的视图功能。
我们已经创建了一个 Flask 应用程序,其中的页面可以接受 URL 并生成更短的 URL,但是这些 URL 还不会执行任何操作。
下一步,我们将添加一条路线,从短网址中提取 short_id,找到原始网址,并将用户重定向到该网址。
如何添加重定向路由
在此步骤中,我们将添加一条新路由,该路由采用应用程序生成的短 ID 并获取原始 URL。最后,我们将用户重定向到原始 URL。
@app.route('/')
def redirect_url(short_id):
link = ShortUrls.query.filter_by(short_id=short_id).first()
if link:
return redirect(link.original_url)
else:
flash('Invalid URL')
return redirect(url_for('index'))
通过 URL short_id
接受一个值 url_redirect()
视图函数。例如,访问 http://127.0.0.1:5000/asdf1gHJ
会将字符串传递 'asdf1gHJ'
给 short_id
参数。
在视图函数中,我们使用 从数据库获取链接 short_id
。如果不是 None,视图函数将 original_url
使用 short_id
与此关联的 redirect()
。否则,它将闪现一条错误消息,通知用户 URL 无效,并将其重定向到索引页。
现在我们可以再次运行服务器并最终测试应用程序。
如何在 Heroku 上部署应用程序
上部署我们的应用 Heroku ,我们需要对项目进行一些更改。但首先,您应该在 Heroku 上创建一个免费帐户。
前往 heroku.com 并创建一个帐户。创建帐户后,您就可以继续了。
登录你的 Heroku 帐户,你会看到类似这样的屏幕:
点击 新建 按钮,然后点击 创建新应用 。输入应用名称,然后点击 创建应用按钮 。确保名称可用。
单击 “设置” 选项卡,向下滚动到 “Buildpacks” 。单击 “添加 buildpack” 按钮并添加 Python .
由于我们需要为该应用程序提供一个数据库,因此我们将在资源中添加一个 Postgres 数据库(可在 Heroku 上免费获取)。
点击 资源选项 卡,在搜索框中搜索Postgres。在搜索结果中选择 Heroku Postgres ,然后点击 提交订单表单 将其添加到资源中。
由于我们在项目中使用了环境变量,因此我们需要在 Heroku 上添加它们。
单击 “设置” 选项卡,滚动到 “配置变量” ,然后单击 “显示配置变量” 在项目中 .env
打开
请注意,我们已将其设置 APP_SETTINGS
为, config.ProductionConfig
因为我们正在公开部署该应用程序。
我们将使用 GitHub 部署我们的应用程序,这将使我们的任务更加轻松。如果您没有 GitHub 帐户,请 在此处 。如果您有 GitHub 帐户,请登录您的帐户。登录后,您将看到类似的屏幕:
使用绿色的 新建 按钮为您的项目创建一个存储库。然后转到系统上的项目。确保您的系统中安装了 Git。如果没有,请从 此处 。在您的项目中打开一个终端并输入以下命令:
$ git init
$ git remote add origin
$ git add .
$ git commit -m "Initial commit"
$ git push origin main
将 替换 <your-repository-url-here>
为 GitHub 提供的 URL。
现在我们需要添加 Heroku 所需的两个新文件 - Procfile
和 runtime.txt
:
web: gunicorn main:app
这声明了一个进程类型, web
以及运行它所需的命令。
名称 web
很重要。它声明此进程类型将附加到 HTTP 路由 堆栈,并在部署时接收 Web 流量。请注意,Procfile 文件没有任何扩展名。
接下来,创建一个 runtime.txt
文件并在其中添加你的 Python 版本:
python-3.9.7
另外,创建一个 .gitignore
文件并添加以下内容:
# Django #
*.log
*.pot
*.pyc
__pycache__
media
db.sqlite3
# Backup files #
*.bak
# If you are using PyCharm #
.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/dictionaries
.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.xml
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
.idea/**/gradle.xml
.idea/**/libraries
*.iws /out/
# Python #
*.py[cod]
*$py.class
# Distribution / packaging
.Python build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
.pytest_cache/
nosetests.xml
coverage.xml
*.cover
.hypothesis/
# Jupyter Notebook
.ipynb_checkpoints
# pyenv
.python-version
# celery
celerybeat-schedule.*
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# mkdocs documentation
/site
# mypy
.mypy_cache/
# Sublime Text #
*.tmlanguage.cache
*.tmPreferences.cache
*.stTheme.cache
*.sublime-workspace
*.sublime-project
# sftp configuration file
sftp-config.json
# Package control specific files Package
Control.last-run
Control.ca-list
Control.ca-bundle
Control.system-ca-bundle
GitHub.sublime-settings
# Visual Studio Code #
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
.history
这告诉 Git 忽略这些文件。
现在,我们已经做出了足够的更改,并准备使用以下命令提交并将其推送到 GitHub 存储库:
$ git add .
$ git commit -m "Ready for deployment"
$ git push origin main
现在我们已经完全准备好在 Heroku 上部署我们的应用程序了。
打开 Heroku 应用并单击 Deploy 选项卡。在 页面的 Deployment 方法
连接成功后,你会看到一个叫做 Deploy Branch 的按钮,点击该按钮,部署过程就会开始:
Heroku 将安装 requirements.txt 文件中提到的所有依赖项,并使用 Runtime.txt 文件中提到的 Python 版本。该过程完成后,您将看到如下成功消息:
我们的应用程序已成功部署!
但还剩一步。如果你还记得的话,每当我们对数据库进行任何更改时,我们都需要迁移数据库。同样,这里也需要迁移数据库。
单击 更多 ,然后单击 运行控制台 以运行 bash。单击后,您将看到一个文本框。在那里输入以下命令:
运行命令后,您将看到数据库迁移正在进行。这样,您的应用就已成功部署,您可以开始测试了!
现在,您可以按照 本教程 向您的 Heroku 应用添加自定义域,因为 Heroku URL 太长了。
包起来
我们创建了一个 Flask 应用程序,允许用户输入长 URL 并生成较短的版本。如果您愿意,可以向此应用程序添加更多功能,例如用户身份验证、缩短的 URL 统计等。
谢谢阅读!
Github 仓库: https://github.com/ashutoshkrris/Flask-URL-Shortener
发表评论 取消回复