在本教程中,我们将使用 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 给模板来渲染模板。

我们现在可以运行服务器并测试我们的视图功能。

1_ufNnbLzmSkxovhLYbJybHA

我们已经创建了一个 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 帐户,你会看到类似这样的屏幕:

Screenshot-2021-12-26-130519

点击 新建 按钮,然后点击 创建新应用 。输入应用名称,然后点击 创建应用按钮 。确保名称可用。

Screenshot-2021-12-26-130553

单击 “设置” 选项卡,向下滚动到 “Buildpacks” 。单击 “添加 buildpack” 按钮并添加 Python .

Screenshot-2021-12-26-130636

由于我们需要为该应用程序提供一个数据库,因此我们将在资源中添加一个 Postgres 数据库(可在 Heroku 上免费获取)。

点击 资源选项 卡,在搜索框中搜索Postgres。在搜索结果中选择 Heroku Postgres ,然后点击 提交订单表单 将其添加到资源中。

Screenshot-2021-12-26-131308

由于我们在项目中使用了环境变量,因此我们需要在 Heroku 上添加它们。

单击 “设置” 选项卡,滚动到 “配置变量” ,然后单击 “显示配置变量” 在项目中 .env 打开

Screenshot-2021-12-26-131347

请注意,我们已将其设置 APP_SETTINGS 为, config.ProductionConfig 因为我们正在公开部署该应用程序。

我们将使用 GitHub 部署我们的应用程序,这将使我们的任务更加轻松。如果您没有 GitHub 帐户,请 在此处 。如果您有 GitHub 帐户,请登录您的帐户。登录后,您将看到类似的屏幕:

screenshot-2021-12-02-095432_kwefk5

使用绿色的 新建 按钮为您的项目创建一个存储库。然后转到系统上的项目。确保您的系统中安装了 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 方法

Screenshot-2021-12-26-131430

连接成功后,你会看到一个叫做 Deploy Branch 的按钮,点击该按钮,部署过程就会开始:

Screenshot-2021-12-26-131502

Heroku 将安装 requirements.txt 文件中提到的所有依赖项,并使用 Runtime.txt 文件中提到的 Python 版本。该过程完成后,您将看到如下成功消息:

Screenshot-2021-12-26-131709

我们的应用程序已成功部署!

但还剩一步。如果你还记得的话,每当我们对数据库进行任何更改时,我们都需要迁移数据库。同样,这里也需要迁移数据库。

单击 更多 ,然后单击 运行控制台 以运行 bash。单击后,您将看到一个文本框。在那里输入以下命令:

Screenshot-2021-12-26-132156

运行命令后,您将看到数据库迁移正在进行。这样,您的应用就已成功部署,您可以开始测试了!

现在,您可以按照 本教程 向您的 Heroku 应用添加自定义域,因为 Heroku URL 太长了。

包起来

我们创建了一个 Flask 应用程序,允许用户输入长 URL 并生成较短的版本。如果您愿意,可以向此应用程序添加更多功能,例如用户身份验证、缩短的 URL 统计等。

谢谢阅读!

Github 仓库: https://github.com/ashutoshkrris/Flask-URL-Shortener

点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论

微信小程序

微信扫一扫体验

立即
投稿

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部