Flask と MySQL を使って URL 短縮機を構築する

HTMLBeginner
オンラインで実践に進む

はじめに

このプロジェクトでは、Flask と MySQL を使って簡単な URL 短縮サービスを作成する方法を学びます。データベースのセットアップ、Web インターフェイスの設計、URL の短縮、タグで URL を検索、アナリティクスを表示する機能の実装などを学びます。このプロジェクトは初心者にも親切で、Python とデータベース管理による Web 開発の包括的な洞察を提供します。

このプロジェクトはhttps://github.com/highoncarbs/shortyをベースにしており、元々は MIT ライセンスの下で利用可能です。

👀 プレビュー

カスタムサフィックス付き/なしで URL を変換し、タグで URL を検索し、リンクにアクセスします。

リンクにアクセスするために使用されたオペレーティングシステムとプラットフォームに関する情報を表示します。

🎯 タスク

このプロジェクトでは、以下のことを学びます。

  • Flask アプリケーションを MySQL データベースに接続する方法
  • URL 情報を格納するための MySQL データベーススキーマを作成および管理する方法
  • HTML と CSS を使ってフロントエンドの Web ページを実装し、バックエンドとやり取りする方法
  • Flask でフォームデータとリクエストを処理して短縮 URL を作成する方法
  • ユーザーを短縮 URL から元の URL にリダイレクトする機能を開発する方法
  • クリック数や基本的なブラウザ/プラットフォーム情報を含む URL の使用状況を追跡するための簡単なアナリティクス機能を作成する方法
  • ユーザーフレンドリーなエラーハンドリングとカスタム 404 ページを設計して、ユーザーエクスペリエンスを向上させる方法

🏆 成果

このプロジェクトを完了すると、以下のことができるようになります。

  • MySQL の基本操作を行うことができ、データベースとテーブルの作成、データの挿入、クエリなどができる
  • Flask の基本原理を理解し、ルーティング、リクエスト処理、テンプレートレンダリングなどができる
  • HTML フォームを使って Flask アプリケーションでデータを処理することができる
  • 基本的なフロントエンドデザイン原則を適用し、CSS を使って視覚的に魅力的な Web インターフェイスを作成することができる
  • URL の使用状況に関するデータを収集して表示するための簡単なアナリティクスを実装することができる
  • Web アプリケーションにおけるエラーハンドリングのベストプラクティスを実装して、信頼性とユーザーエクスペリエンスを向上させることができる

プロジェクト環境をセットアップする

まず、ターミナルでプロジェクト環境をセットアップする必要があります。これには、MySQL 接続に必要な Python パッケージをインストールし、MySQL サービスを起動することが含まれます。サービスが起動したら、URL を格納するためのデータベースとテーブルを作成します。

PyMySQL をインストールする:

pip install PyMySQL==1.1.0

MySQL サービスを起動し、MySQL シェルにログインする:

sudo service mysql start
mysql -u root

MySQL シェル内で、以下のコマンドを実行してデータベースとテーブルを作成する:

データベースを作成する:

CREATE DATABASE IF NOT EXISTS SHORTY;
USE SHORTY;

テーブルを作成する:

CREATE TABLE IF NOT EXISTS WEB_URL
(
    ID             INT AUTO_INCREMENT,
    URL            VARCHAR(512),
    S_URL          VARCHAR(80),
    TAG            VARCHAR(80),
    COUNTER        INT DEFAULT 0,
    CHROME         INT DEFAULT 0,
    FIREFOX        INT DEFAULT 0,
    SAFARI         INT DEFAULT 0,
    OTHER_BROWSER  INT DEFAULT 0,
    ANDROID        INT DEFAULT 0,
    IOS            INT DEFAULT 0,
    WINDOWS        INT DEFAULT 0,
    LINUX          INT DEFAULT 0,
    MAC            INT DEFAULT 0,
    OTHER_PLATFORM INT DEFAULT 0,
    PRIMARY KEY (ID)
);

この SQL ステートメントは、SHORTYデータベース内にWEB_URLという名前のテーブルを作成します。このテーブルは、短縮 URL に関連する情報といくつかの関連するアナリティクスを格納するために設計されています。

  • CREATE TABLE IF NOT EXISTS WEB_URL:このコマンドは、データベース内に既に存在しない場合にのみ、新しいWEB_URLという名前のテーブルを作成します。これにより、スクリプトを複数回実行したときのエラーを回避できます。
  • ID INT AUTO_INCREMENT:この列は、テーブルの主キーとして指定されており、新しいエントリごとに自動的にインクリメントされます。これは、新しいレコードが追加されるたびに、MySQL が自動的に一意の ID を割り当て、前の ID から 1 増やすことを意味します。
  • URL VARCHAR(512):この列は、短縮される元の URL を格納します。データ型VARCHAR(512)は、最大 512 文字の可変長文字列を保持できることを意味します。
  • S_URL VARCHAR(80):これは、最大 80 文字の短縮 URL 文字列の列です。
  • TAG VARCHAR(80):この列は、分類または検索目的で URL に関連付けられたタグを格納するために意図されており、最大 80 文字です。
  • COUNTER INT DEFAULT 0:この整数列は、おそらく短縮 URL がアクセスされた回数を追跡するために使用されます。新しいレコードが作成されるときには 0 に初期化されます。
    次のいくつかの列は、短縮 URL のアナリティクスデータを保持するために設計されています。
  • CHROMEFIREFOXSAFARIOTHER_BROWSER:これらの列は、異なる Web ブラウザからの訪問回数を追跡するために使用されます。それぞれが 0 に初期化される整数列です。
  • ANDROIDIOSWINDOWSLINUXMACOTHER_PLATFORM:ブラウザの列と同様に、これらは異なるオペレーティングシステム/プラットフォームからの訪問を追跡するために意図されており、それぞれの列は 0 に初期化されます。
  • PRIMARY KEY (ID):このステートメントのこの部分は、ID列がテーブルの主キーであることを指定します。主キーは、テーブル内の各レコードの一意の識別子であり、2 つのレコードが同じIDを持たないことを保証します。

このテーブル構造を使用すると、短縮 URL に関するデータを保存、取得、分析することができます。これには、短縮 URL がどのくらい頻繁にアクセスされるか、どのブラウザから、どのオペレーティングシステムからアクセスされるかが含まれます。

MySQL シェルを終了するには、次のコマンドを実行できます:

EXIT;
✨ 解答を確認して練習

インデックスページのテンプレートを作成する

インデックスページは、ユーザーが URL 短縮サービスとやり取りする場所です。HTML と Flask のテンプレート言語を使って動的なコンテンツを作成します。

templates/index.htmlに、以下の HTML コードを追加します。

<!doctype html>
<html>
  <head>
    <title>Shorty</title>
    <!-- ホスティング時にローカル SVG 画像を追加する。 -->
    <link
      href="https://fonts.googleapis.com/icon?family=Material+Icons"
      rel="stylesheet"
    />
    <script src="https://cdnjs.cloudflare.com/ajax/libs/clipboard.js/1.7.1/clipboard.min.js"></script>
    <link rel="stylesheet" type="text/css" href="../static/skeleton.css" />
    <link rel="stylesheet" type="text/css" href="../static/normalize.css" />
    <link rel="stylesheet" type="text/css" href="../static/main.css" />
    <link
      href="https://fonts.googleapis.com/css?family=Roboto:300,400,700,900"
      rel="stylesheet"
    />
  </head>
  <body>
    <div class="container  main_header">
      <h3 align="left"><a href="{{url_for('index')}}">Shorty</a></h3>
      <p>A very simple URL shortening service.</p>
    </div>

    <div class="u-full-width shorty">
      <div class="container"></div>
    </div>
  </body>
</html>

その主なコンポーネントの概要は以下の通りです。

  • Google Material Icons:<link>タグが Google Material Icons ライブラリをインポートし、より魅力的なユーザーインターフェイスのために事前定義されたアイコンを使用できるようにします。
  • Clipboard.js:<script>タグに Clipboard.js ライブラリが含まれています。これは、クリップボードにコンテンツをコピーするための人気のある JavaScript ライブラリです。これは URL 短縮サービスに便利で、ユーザーが短縮 URL を簡単にコピーできるようにします。
  • スタイルシート:テンプレートは、スタイリング用にいくつかの CSS ファイルにリンクしています。
    • skeleton.css:基本的なスタイリングとレスポンシブなグリッドシステムを提供する軽量の CSS フレームワーク。
    • normalize.css:ブラウザの既定のスタイルをリセットして、異なるブラウザ間で一貫したスタイリングを維持します。
    • main.css:「Shorty」サービス固有のカスタムスタイルが含まれています。
  • Google Fonts:別の<link>タグが Google Fonts から「Roboto」フォントファミリーをインポートし、印刷用のさまざまなフォントウェイトを提供します。
  • <body>の中で、container main_headerクラスのdivが使われてヘッダーセクションを作成しています。これには以下が含まれます。
    • 見出し(<h3>)で、Flask のurl_for関数によってインデックスページにリダイレクトするリンク(<a>)が含まれており、'index'ルートの URL を動的に生成します。
    • サービスを「非常にシンプルな URL 短縮サービス」と説明する段落(<p>)。
✨ 解答を確認して練習

URL の短縮とタグベースの検索を実装する

このステップでは、URL の短縮とタグベースの URL 検索という 2 つの重要な機能を統合することで Web インターフェイスを強化します。これにより、ユーザーは URL を短縮するだけでなく、タグを使って効率的に整理して取得することができるようになります。

URL の短縮

まず、インデックスページにユーザーが短縮したい URL を入力できるフォームを作成します。カスタムサフィックスとタグのオプションフィールドにより、個別化された短縮 URL と管理を容易にするための分類が可能になります。

templates/index.htmlに以下のコードを追加します。

<!-- Search URL block -->
<div class="search_url_block">
  <form method="post" action="/search" name="search_tag_block">
    <input type="text" name="search_url" placeholder="Search tags " />
    <button type="submit" class="button-primary search_url_btn" value="Search">
      Search
    </button>
  </form>
</div>
<!-- end block -->

最初のコードブロックは、関連するタグで URL を検索するために設計されたフォームを追加します。

  • search_url_block:このコンテナは検索フォームを保持し、ページ上の区別されたセクションとして、より良い構成とスタイリングを可能にします。
  • <form>:検索ボタンがクリックされたときに/searchエンドポイントに POST リクエストを送信するフォームを定義します。このフォームは識別のためにsearch_tag_blockと名付けられています。
  • <input>:ユーザーが検索したいタグを入力できるテキスト入力フィールド。placeholder属性は、フィールドの目的に関するユーザーへのヒントを提供します。
  • <button>:フォーム送信を開始する送信ボタン。button-primaryクラスはおそらく CSS で定義された特定のスタイリングを追加します。

タグベースの検索

URL 短縮機能を補完するために、ユーザーがタグで URL を検索できる機能も実装します。この機能はインデックステンプレートに統合され、ユーザーが対応する URL を見つけるためにタグを入力できる簡単なフォームを提供します。

templates/index.htmlに以下のコードを追加します。

<!-- URL Input block -->
<form method="post" action="" name="generate_block">
  <div class="row">
    <input type="text" name="url_input" placeholder="Enter URL" />
    <input type="text" name="url_custom" placeholder="Enter Custom Suffix" />
    <input type="text" name="url_tag" placeholder="Tag URL" />
    <button class="button-primary generate">Generate</button>
  </div>
</form>
<!-- end block -->

2 番目のコードブロックは、ユーザーが URL を短縮するためのフォームを導入し、カスタマイズ用の追加フィールドを備えています。

  • 全体のフォームは、method="post"と不明なaction属性を持つ<form>要素にラップされています。これは、生成ボタンがクリックされたときにフォームデータが POST リクエストで現在の URL に送信されることを意味します。
  • フォーム内で、rowクラスの<div>がレイアウトと整列に役立ち、入力フィールドとボタンが適切に配置されることを保証します。
  • 3 つの<input type="text">要素が異なる目的で用意されています。
    • 最初の入力フィールドは、ユーザーが短縮したい元の URL を入力するためのものです。
    • 2 番目は、短縮 URL のオプションのカスタムサフィックスを許可し、ユーザーが自分たちの短いリンクを個別化できるようにします。
    • 3 番目のフィールドはタグ用で、ユーザーが短縮 URL に分類または説明的なラベルを追加して、取得と管理を容易にすることができます。
  • button-primaryクラスと "Generate" というテキストを持つ<button>がフォームの送信ボタンとして機能します。このボタンをクリックすると、サーバーにデータが送信され、提供された情報を使って短縮 URL が作成されます。

これらの強化により、基本的な URL 短縮だけでなく、さらに多くの機能を提供することでユーザーエクスペリエンスが大幅に改善されます。タグで URL を検索する機能により、短縮リンクの効率的な管理と取得が可能になり、カスタムサフィックスとタグを追加するオプションにより、URL の個別化と分類が可能になります。この設定は HTML フォームを利用してユーザー入力を収集し、その後サーバーサイドの Flask アプリケーションによって処理されて、望ましいアクションを実行します。

✨ 解答を確認して練習

エラーを処理して短縮 URL を表示する

このステップでは、エラーメッセージの処理と短縮 URL の表示を行うことで、ユーザーエクスペリエンスを向上させます。

エラーを処理する

まず、ユーザーにエラーメッセージを表示する機能を追加します。ユーザーが無効な URL や存在しないタグを送信した場合など、何かがうまくいかないときにフィードバックを提供することは重要です。適切なエラー処理により、アプリケーションがより堅牢でユーザーにやさしくなります。

templates/index.htmlに以下のコードを追加します。

<!-- Error Display block -->
{% if error!= '' %}
<p class="error_disp">{{error}}</p>
{% endif %} {% if shorty_url %}
<!-- end block-->

このブロックは、URL 短縮プロセス中にエラーが発生した場合にユーザーにフィードバックを提供するために設計されています。

  • {% if error!= '' %}:これは、Flask のテンプレート構文 Jinja2 を使用した条件文です。error変数が空でないことをチェックします。error変数は Flask のバックエンドからテンプレートに渡されることが想定されています。エラーメッセージがある場合、条件はTrueに評価されます。
  • <p class="error_disp">{{error}}</p>:条件がTrueの場合、この段落要素がレンダリングされ、error変数に含まれるエラーメッセージが表示されます。error_dispクラスはおそらくエラーメッセージのスタイリングに使用され、ユーザーの注意を引くために視覚的に区別されます。
  • {% endif %}:これは条件ブロックを閉じます。error変数が空の場合、このブロックからの何もがページにレンダリングされません。

短縮 URL を表示する

次に、URL が正常に短縮された後、短縮 URL をユーザーに表示します。これには、インデックスページにフォーム送信後に短縮 URL を動的に表示するセクションを作成することが含まれます。このセクションには、簡単な共有のためのクリップボードにコピーするボタンも備えています。

templates/index.htmlに以下のコードを追加します。

<!-- URL Generator Display block -->
<div class="gen_block">
  <p class="gen_url">
    Shorty URL is
    <b><a id="short-url" href="{{shorty_url}}">{{shorty_url}}</a></b>
  </p>
  <button
    class="button-primary copy-btn"
    data-clipboard-action="copy"
    data-clipboard-target="#short-url"
  >
    Copy
  </button>
</div>
{% endif %}
<!-- end block -->

このブロックは、URL が正常に短縮されたときに表示され、ユーザーが短縮 URL を簡単にコピーできる方法を提供します。

  • {% if shorty_url %}shorty_url変数が存在して空でないことをチェックする別の条件文です。この変数はサービスによって生成された短縮 URL を保持するはずです。
  • <p class="gen_url">:この段落は短縮 URL を示すメッセージを表示します。その中で、<a id="short-url" href="{{shorty_url}}">{{shorty_url}}</a>は、短縮 URL をリンクテキストとhref属性の両方として持つハイパーリンクを作成し、ユーザーが直接クリックできるようにします。
  • <button>:このボタンは、簡単な共有のために短縮 URL をクリップボードにコピーするように設計されています。スタイリング用のクラス(button-primary)と機能用のクラス(copy-btn)を使用しています。data-clipboard-action属性は実行するアクション(コピー)を指定し、data-clipboard-targetはコピー元のターゲット要素(短縮 URL のリンク)を示します。この設定は、クリップボード操作機能を処理するために Clipboard.js(または同様のライブラリ)の統合を想定しています。
  • {% endif %}:短縮 URL とコピーボタンを表示する条件ブロックを閉じます。shorty_urlが設定されていないか空の場合、このセクションはレンダリングされません。

これらの強化は、URL 短縮サービスの使いやすさに大きく貢献します。エラーメッセージは重要なフィードバックを提供し、ユーザーに誤りを修正するように導き、問題を知らせます。一方、簡単なコピー機能付きの短縮 URL の表示は、短縮リンクの作成と共有においてシームレスな体験を可能にします。

✨ 解答を確認して練習

短縮 URL を一覧表示して管理する

最後のステップは、データベースに保存されているすべての短縮 URL を、その元の URL、受け取ったクリック数、および詳細なアナリティクスへのリンクとともに一覧表示するセクションを作成することです。この機能により、ユーザーは 1 か所で短縮 URL を表示して管理できるようになり、アプリケーションがより機能的でユーザーにやさしくなります。

templates/index.htmlに以下のコードを追加します。

        <!-- URL List Block -->
        {% if not error %}
        {% if not shorty_url %}
        <!-- Add Empty list case -> 'Wow. Such Empty!' -->
        <div style="overflow-x:auto;">
            <div class="table_list u-full-width">
                <table>
                    <thead>
                    <tr>
                        <th>Original URL</th>
                        <th>Short URL</th>
                        <th>Clicks</th>
                        <th>Info</th>
                    </tr>
                    </thead>

                    <tbody>
                    {% for url in table %}
                    <tr>
                        <td style="padding-left: 5px;">{{url[1]}}</td>
                        <td><a href="{{host+url[2]}}">{{ host+url[2]}}</a></td>
                        <td style="text-align: center;">{{url[4]}}</td>
                        <td id="info"><a href=" {{url_for('analytics',short_url=url[2])}} "><i class="material-icons">info_outline</i></a>
                        </td>
                    </tr>

                    {% endfor %}
                    </tbody>
                </table>
            </div>
        </div>
        {% endif %}
        {% endif %}
    </div>
</div>
<script type="text/javascript">
    var clipboard = new Clipboard('.copy-btn');
</script>
</html>

このコードは、データベースに保存されているすべての短縮 URL を一覧表示するために設計されており、元の URL、短縮 URL、クリック数、およびより詳細なアナリティクスへのリンクなどの情報を提供します。そのコンポーネントの詳細な解説は以下の通りです。

  • このブロックは、エラーがない場合にのみ一覧を表示するようにする条件文{% if not error %}で始まります。これは、エラーメッセージを表示する必要がある場合には、クリーンなユーザーインターフェイスを維持するのに役立ちます。
  • 別の条件文{% if not shorty_url %}は、新しい短縮 URL が生成された直後に一覧が表示されないようにチェックします。この条件は、新しい URL が短縮された直後にユーザーの注意を新しく作成された短縮 URL に集中させるために使用される場合があります。
  • overflow-x:auto; のスタイルが div に適用されており、小さな画面で表を水平方向にスクロールできるようにして、応答性と使いやすさを向上させています。
  • table 要素は、「元の URL」、「短縮 URL」、「クリック数」、「情報」の列見出しを定義する thead セクションで構成されています。このレイアウトにより、ユーザーは提示されるデータを理解しやすくなります。
  • tbody セクションは、Flask/Jinja2 のループ {% for url in table %} を使用してデータで動的に埋められます。このループは、Flask のバックエンドから渡される URL のコレクション(table)を反復処理し、各 URL のデータを新しいテーブル行(<tr>)に表示します。
  • 各行内で、元の URL は美観のためにいくらかの余白付きのセル(<td>)に表示されます。短縮 URL は、ホスト名(host)に短縮パス(url[2])を追加することで構築されたクリック可能なリンク(<a>)として提示されます。このホスト名もバックエンドから渡される必要があります。
  • 「クリック数」の列には、短縮 URL がアクセスされた回数が表示され、読みやすさを向上させるために中央に配置されています。
  • 「情報」の列には、各短縮 URL のアナリティクスページへのリンクが含まれています。このリンクは、Flask の url_for 関数を使用して生成され、短縮 URL をパラメータとしてアナリティクスルートへの URL を動的に作成します。Google Material Icons セットのアイコン(<i class="material-icons">info_outline</i>)が使用されて、アナリティクスリンクを視覚的に表しています。
  • {% endfor %} タグがループを閉じ、table コレクション内の各 URL に対して行が作成されることを保証します。
  • 条件ブロックは {% endif %} タグで閉じられます。
  • 下部には、<script> タグが .copy-btn クラスに対して Clipboard.js を初期化しています。これは、以前のセクション(例えば、短縮 URL をコピーするため)で使用されている場合があります。このスクリプトにより、copy-btn クラスを持つ任意の要素にクリップボードにコピーする機能が有効になり、Clipboard.js ライブラリを利用します。

この最後のステップは、ユーザーに短縮 URL の包括的な概要を提供することで、「Shorty」URL 短縮サービスの機能を完結させ、リンクの管理と分析を容易にします。Flask/Jinja2 による動的データレンダリングと配慮深い UI デザインの統合により、ユーザーにやさしい体験が保証されます。

✨ 解答を確認して練習

検索ページのテンプレートを作成する

ユーザーがタグで URL を検索できるようにするために、検索ページが必要です。

templates/search.htmlに、以下の HTML コードを追加します。

<!DOCTYPE html>
<html>
<head>
    <title>Shorty</title>
    <link href="https://fonts.googleapis.com/icon?family=Material+Icons"
          rel="stylesheet">
    <link rel="stylesheet" type="text/css" href="../static/skeleton.css">
    <link rel="stylesheet" type="text/css" href="../static/normalize.css">
    <link rel="stylesheet" type="text/css" href="../static/main.css">
    <link href="https://fonts.googleapis.com/css?family=Roboto:300,400,700,900" rel="stylesheet">
</head>
<body>
<div class="container main_header">
    <h3 align="left"><a href="{{url_for('index')}}">Shorty</a></h3>
    <p>A dead simple URL shortener service.</p>
</div>
<!-- Search results  -->
<div class=" container search_header">
    <h4>Search Results for : <b> {{ search_tag }} <b></h4>

    <div style="overflow-x:auto;">
        <div class="table_list u-full-width">
            <table>
                <thead>
                <tr>
                    <th>Original URL</th>
                    <th>Short URL</th>
                    <th>Clicks</th>
                    <th>Info</th>

                </tr>
                </thead>

                <tbody>
                {% for url in table %}
                <tr>
                    <td style="padding-left: 5px;">{{url[1]}}</td>
                    <td><a href="{{ host+url[2]}}">{{host+url[2]}}</a></td>
                    <td style="text-align: center;">{{url[4]}}</td>
                    <td id="info"><a href=" {{url_for('analytics',short_url=url[2])}} "><i class="material-icons">info_outline</i></a>
                    </td>
                </tr>
                {% endfor %}
                </tbody>
            </table>
        </div>
    </div>
</div>
</body>
</html>

このコードは、「Shorty」URL 短縮サービスの検索結果ページのテンプレートを作成します。このページは、ユーザーがタグで URL を検索した結果を表示するように設計されています。このテンプレートの詳細な解説は以下の通りです。

  • <body>内で、ヘッダーセクション(<div class="container main_header">)はインデックスページと同じように、一貫した見た目と感じを提供します。これには、インデックスページにリダイレクトするクリック可能なリンク({{url_for('index')}})としてサービス名(「Shorty」)とサービスの簡単な説明が含まれています。
  • <div class="container search_header">セクションは、検索結果エリアを導入し、最初に検索に使用されたタグ({{ search_tag }})を動的に表示するヘッダー(<h4>)で始まります。
  • 結果は、水平方向のスクロール用にスタイリングされたdiv内の表に表示され(overflow-x:auto;)、小さな画面のデバイスでもアクセス可能になっています。
  • 表構造(<table>)は、ヘッダー(<thead>)と本体(<tbody>)のセクションで構成されています。ヘッダーは、「元の URL」、「短縮 URL」、「クリック数」、「情報」の列を定義しており、インデックスページに表示されるリストと同じです。
  • 表の本体は、Flask のバックエンドから渡される URL のコレクション(table)を反復処理するループ({% for url in table %})を使用して動的に埋められます。各反復処理では、表の新しい行(<tr>)が URL 用に作成されます。
    • 元の URL は、読みやすさを向上させるためにいくらかの余白付きで表示されます。
    • 短縮 URL は、Flask のテンプレート構文を使用して動的に挿入されるホスト名に短縮パスを追加することで構築されたクリック可能なリンクとして提示されます。
    • 「クリック数」の列には、短縮 URL がアクセスされた回数が表示され、明確にするためにテキストが中央に配置されています。
    • 「情報」の列は、各 URL の詳細なアナリティクスへのリンクを提供し、Flask のurl_for関数を使用して URL を動的に生成し、視覚的な表現のためにアイコン(<i class="material-icons">info_outline</i>)を使用しています。

この検索結果テンプレートは、ユーザーがタグに基づいて URL を効果的に見つけて管理できるようにすることで「Shorty」サービスを強化し、シームレスで直感的なユーザーエクスペリエンスを提供します。インデックスページからの一貫したスタイルとレイアウト要素の使用により、アプリケーション全体で統一感のあるデザインが保証されます。

✨ 解答を確認して練習

アナリティクスページのテンプレートを作成する

アナリティクスページでは、短縮 URL の使用状況に関する詳細な情報、クリック数、ブラウザーとプラットフォームの統計情報が表示されます。

templates/data.htmlに、以下の HTML コードを追加します。

<!doctype html>
<html>
  <head>
    <title>Shorty</title>

    <!-- Add Local SVG image when hosting. -->
    <link
      href="https://fonts.googleapis.com/icon?family=Material+Icons"
      rel="stylesheet"
    />

    <link rel="stylesheet" type="text/css" href="../static/skeleton.css" />
    <link rel="stylesheet" type="text/css" href="../static/normalize.css" />
    <link rel="stylesheet" type="text/css" href="../static/main.css" />
    <link
      href="https://fonts.googleapis.com/css?family=Roboto:300,400,700,900"
      rel="stylesheet"
    />
  </head>
  <body>
    <div class="container  main_header">
      <h3 align="left"><a href="{{url_for('index')}}">Shorty</a></h3>
      <p>A dead simple URL shortener service.</p>
    </div>
    <div class=" container modal-content">
      <!-- Array index -> 
      broswer : 
          CHROME,
          FIREFOX,
          SAFARI,
          OTHER_BROWSER,
      platform:
          ANDROID,
          IOS,
          WINDOWS,
          LINUX,
          MAC,
          OTHER_PLATFORM
       -->
      <div class="url_info">
        <h4>
          Analytics data for :
          <a href="{{host+info[1]}}">{{'localhost/'+info[1]}}</a>
        </h4>
        <p>
          Original URL :
          <a style="text-decoration: none" href="{{info[0]}}">{{info[0]}}</a>
        </p>
      </div>
      <div class="data_block">
        <div class="browser_list">
          <h4>Browser</h4>
          <table>
            <thead>
              <tr>
                <th>Chrome</th>
                <th>Firefox</th>
                <th>Safari</th>
                <th>Other Broswers</th>
              </tr>
            </thead>

            <tbody>
              <tr>
                <td style="padding-left: 5px;">{{browser[0]}}</td>
                <td>{{browser[1]}}</td>
                <td>{{browser[2]}}</td>
                <td>{{browser[3]}}</td>
              </tr>
            </tbody>
          </table>
        </div>
        <div class="platform_list">
          <h4>Platform</h4>
          <table>
            <thead>
              <tr>
                <th>Android</th>
                <th>IOS</th>
                <th>Windows</th>
                <th>Linux</th>
                <th>Mac</th>
                <th>Other Platforms</th>
              </tr>
            </thead>
            <tbody>
              <tr>
                <td style="padding-left: 5px;">{{platform[0]}}</td>
                <td>{{platform[1]}}</td>
                <td>{{platform[2]}}</td>
                <td>{{platform[3]}}</td>
                <td>{{platform[4]}}</td>
                <td>{{platform[5]}}</td>
              </tr>
            </tbody>
          </table>
        </div>
      </div>
    </div>
  </body>
</html>

このコードには、クリック数、ブラウザーの使用状況、およびプラットフォームの分布に関する情報が含まれています。その構造とコンポーネントの解説は以下の通りです。

  • container modal-content クラスの div が、アナリティクス情報をカプセル化しており、ページ内のモーダルまたは区別されたコンテンツブロックとしてスタイリングされています。
  • url_info div は以下の内容を提示します。
    • 特定の短縮 URL のアナリティクスに関するデータであることを示す <h4> 見出し。短縮 URL は、hostinfo[1] 変数を使用して構築されたクリック可能なリンクとして表示されます。ここで、info[1] には短縮パスが含まれています。
    • 元の URL をクリック可能なリンクとして表示する段落(<p>)で、元のコンテンツへのアクセスを容易にします。
  • 2 つの別々のセクションである browser_listplatform_list は、それぞれブラウザーとプラットフォームの使用統計を表示する表を含んでいます。
    • browser_list セクションには、Chrome、Firefox、Safari、その他のブラウザーの見出しがある表が含まれています。<tbody> セクションには、テンプレートに渡される browser 配列変数から抽出された対応する統計情報が表示されます。
    • 同様に、platform_list セクションには、Android、iOS、Windows、Linux、Mac、その他のプラットフォームの見出しがあるプラットフォーム使用状況の表があります。使用統計は表の本体に表示され、platform 配列変数から取得されています。
  • 表は、見出し用に <thead> を、実際のデータ用に <tbody> を使用しており、意味のある HTML を保証し、スタイリングとアクセシビリティを容易にします。
  • 表内のデータセル(<td>)は、各ブラウザーとプラットフォームのそれぞれのカウントを表示し、読みやすさのために整列とスタイリングが施されています。

このテンプレートは、ユーザーにアナリティクスデータを効果的に伝え、短縮 URL がどのようにアクセスされているか、つまり視聴者が使用しているブラウザーとプラットフォームに関する洞察を提供します。クリーンなレイアウトと、データを明確に区別されたセクションに分けることで、ユーザーが URL のパフォーマンスを理解して解釈するのが容易になります。

✨ 解答を確認して練習

404 ページのテンプレートを作成する

カスタム 404 ページは、短縮 URL が見つからない場合に、より役立つエラーメッセージを提供することで、ユーザーエクスペリエンスを向上させます。

templates/404.htmlに、以下の HTML コードを追加します。

<!doctype html>
<html>
  <head>
    <title>Shorty</title>

    <!-- Add Local SVG image when hosting. -->
    <link
      href="https://fonts.googleapis.com/icon?family=Material+Icons"
      rel="stylesheet"
    />

    <link rel="stylesheet" type="text/css" href="../static/skeleton.css" />
    <link rel="stylesheet" type="text/css" href="../static/normalize.css" />
    <link rel="stylesheet" type="text/css" href="../static/main.css" />
    <link
      href="https://fonts.googleapis.com/css?family=Roboto:300,400,700,900"
      rel="stylesheet"
    />
  </head>
  <body>
    <div class="lost">
      <h2>Oi, chap you seem lost!</h2>
    </div>
  </body>
</html>

このカスタム 404 ページのテンプレートは、軽快なニュアンスを保ちながら、ユーザーに対して探しているページが存在しないことを効果的に伝えます。

✨ 解答を確認して練習

ウェブインターフェイスをデザインする

次に、ウェブインターフェイスをデザインします。まず、アプリケーションのスタイルを設定するためのメイン CSS ファイルを作成します。

static/main.cssに、HTML 要素をスタイリングするための以下の CSS コードを追加します。

html {
  border-top: 5px solid #d9edf7;
}
body {
  font-family: "Roboto", sans-serif;
  margin-top: 50px;
  margin-bottom: 0;
}
h3 {
  padding: 0;
  margin: 0;
}
h3 a {
  font-weight: 700;
  text-decoration: none;
  color: black;
}
h3 a:hover {
  color: grey;
  transition: 0.2s all;
}
/** メインヘッダー */
.main_header {
  margin-bottom: 20px;
}
/* 検索ブロック */
.search_url_block {
  padding: 15px;
  background-color: #d9edf7;
  color: #31708f;
  border-radius: 5px;
  margin-bottom: 10px;
}
form {
  margin: 0;
}

.search_header {
  margin-top: 20px;
}

.material-icons {
  padding: 5px;
  padding-top: 7px;
  opacity: 0.7;
}

.material-icons:hover {
  opacity: 1;
}
/* URL 生成ブロック */

.gen_block {
  margin-top: 10px;
  padding: 15px;
  background-color: #dff0d8;
  color: #2b542c;
  border-radius: 5px;
  width: auto;
  font-size: 20px;
}
/* エラー表示 */
.error_disp {
  padding: 15px;
  border-radius: 5px;
  background-color: #fcf8e3;
  color: #b84442;
  width: auto;
  font-size: 20px;
  margin-top: 10px;
}

/* テーブル表示ブロック*/

.table_list {
  padding-top: 10px;
  margin-top: 40px;
  border-top: 2px solid lightgrey;
}
table {
  font-size: 20px;
  width: 100%;
}
thead {
  font-weight: 700;
  padding: 2px;
}
tbody {
  font-weight: 400;
}
th {
  padding: 5px;
}
td {
  padding: 5px;
}
tr {
  padding: 5px;
}
tbody tr:hover {
  background-color: #f5f5f5;
  transition: 0.1s all ease-out;
}

/* アナリティクスブロック*/
.url_info {
  margin-top: 10px;
  padding: 15px;
  background-color: #d9edf7;
  color: #31708f;
  border-radius: 5px;
  margin-bottom: 10px;
}
.url_info h4,
p {
  margin: 0;
  padding: 0;
}
.data_block {
  margin-top: 20px;
}

/* 404. 見つからない */
.lost {
  margin-top: 20px;
}
.lost h2 {
  font-weight: 700;
  font-size: 40px;
  text-align: center;

  color: #31708f;
}
.lost p {
  font-weight: 400;
  font-size: 20px;
  text-align: center;
}

全体的なデザインは、背景色、文字色、パディングの組み合わせを使って、クリーンで現代的なインターフェイスを作り出し、操作しやすくしています。さまざまな要素に対するボーダー半径の使用により、インターフェイスにソフトで親近感のある感じが与えられ、ホバーエフェクトによってインタラクティビティが向上します。Roboto フォントの一貫した使用により、アプリケーション全体で統一感のある見た目が保たれています。

✨ 解答を確認して練習

データベース接続と操作関数

ユーティリティ関数は、データベース接続、URL の検証、ブラウザーとプラットフォームのカウンターの更新、および短縮 URL 用のランダムトークンの生成を担当します。

データベース接続

まず、pymysqlを使ってデータベース接続を設定します。これは、Flask アプリケーションが MySQL データベースとやり取りするために不可欠です。

utils.pyに、以下の Python コードを追加します。

from urllib.parse import urlparse
import random
import string

import pymysql


db_config = {
    "host": "localhost",
    "user": "root",
    "password": "",
    "db": "SHORTY"
}


def get_db_connection() -> pymysql.Connection:
    """Create and return a new database connection."""
    return pymysql.connect(**db_config)
  • pymysqlライブラリは MySQL データベースに接続するために使用されます。このライブラリを使うと、Python アプリケーションが簡単な API を使って MySQL データベースとやり取りできます。
  • db_config辞書には、ホスト、ユーザー、パスワード、データベース名などのデータベース接続パラメータが含まれています。これらは、おそらくより良いセキュリティとモジュラリティのために別のconfigモジュールからインポートされています。設定を分離することで、メインコードベースを変更することなく簡単に調整できます。
  • get_db_connection()関数は、pymysql.connect(**db_config)関数を使ってデータベースに新しい接続を作成して返します。**db_config構文は、辞書をキーワード引数に展開するために使用されます。

データベース操作関数

データベース接続を確立した後、次のステップはデータベースで操作を行う関数を作成することです。これには、特定の短縮 URL のデータの一覧表示と、ブラウザーとプラットフォームの使用状況に基づくカウンターの更新が含まれます。

utils.pyに、以下の Python コードを追加します。

def list_data(shorty_url: str) -> tuple:
    """
    Takes short_url for input.
    Returns counter, browser, platform ticks.
    """
    with get_db_connection() as conn, conn.cursor() as cursor:

        su = [shorty_url]
        info_sql = "SELECT URL, S_URL, TAG FROM WEB_URL WHERE S_URL = %s; "
        counter_sql = "SELECT COUNTER FROM WEB_URL WHERE S_URL = %s; "
        browser_sql = "SELECT CHROME, FIREFOX, SAFARI, OTHER_BROWSER FROM WEB_URL WHERE S_URL = %s;"
        platform_sql = "SELECT ANDROID, IOS, WINDOWS, LINUX, MAC, OTHER_PLATFORM FROM WEB_URL WHERE S_URL = %s;"

        cursor.execute(info_sql, su)
        info_fetch = cursor.fetchone()
        cursor.execute(counter_sql, su)
        counter_fetch = cursor.fetchone()
        cursor.execute(browser_sql, su)
        browser_fetch = cursor.fetchone()
        cursor.execute(platform_sql, su)
        platform_fetch = cursor.fetchone()

    return info_fetch, counter_fetch, browser_fetch, platform_fetch

def update_counters(cursor: pymysql.Connection, short_url: str, browser_dict: dict, platform_dict: dict) -> None:
    """Update browser and platform counters in the database for the given short_url."""
    counter_sql = """UPDATE WEB_URL SET COUNTER = COUNTER + 1,
                     CHROME = CHROME + %s, FIREFOX = FIREFOX + %s, SAFARI = SAFARI + %s, OTHER_BROWSER = OTHER_BROWSER + %s,
                     ANDROID = ANDROID + %s, IOS = IOS + %s, WINDOWS = WINDOWS + %s, LINUX = LINUX + %s, MAC = MAC + %s, OTHER_PLATFORM = OTHER_PLATFORM + %s
                     WHERE S_URL = %s;"""
    cursor.execute(counter_sql, (browser_dict['chrome'], browser_dict['firefox'], browser_dict['safari'], browser_dict['other'],
                                 platform_dict['android'], platform_dict['iphone'], platform_dict[
                                     'windows'], platform_dict['linux'], platform_dict['macos'], platform_dict['other'],
                                 short_url))
  • list_data(shorty_url)関数は、特定の短縮 URL(shorty_url)に対してWEB_URLテーブルからさまざまな情報を取得するように設計されています。データベースに接続し、元の URL、関連するタグ、アクセスカウンター、ブラウザー、およびプラットフォームのアナリティクスを取得するために 4 つの SQL クエリを実行します。各クエリは個別に実行され、結果が取得されて返されます。
  • update_counters(cursor, short_url, browser_dict, platform_dict)関数は、データベース内の特定の短縮 URL のアクセスカウンター、ブラウザー、およびプラットフォームのカウントを更新します。この関数は、データベースカーソル、短縮 URL、および各ブラウザーとプラットフォームのカウントを含む 2 つの辞書を引数にとります。提供されたデータに基づいて短縮 URL のカウンターを増やすためのUPDATE SQL 文を構築します。この関数は、この関数を呼び出す前にブラウザーとプラットフォームの情報が決定されており、この情報が辞書(browser_dictplatform_dict)として渡されることを前提としています。これらの辞書のキーは、WEB_URLテーブルの列に対応しています。

この設定は、Flask と MySQL を使った Web アプリケーションの典型的なパターンであり、共通のデータベース操作に対してユーティリティ関数が定義されています。これらの関数は、その後、アプリケーション全体でインポートして使用され、データベースとのやり取りを行い、メインアプリケーションロジックから直接的なデータベースアクセスと SQL クエリを抽象化します。

✨ 解答を確認して練習

非データベースユーティリティ関数を実装する

最後に、データベースとやり取りしないユーティリティ関数を実装します。これには、短縮 URL 用のランダムトークンの生成と URL の検証が含まれます。

utils.pyに、以下の Python コードを追加します。

def random_token(size: int = 6) -> str:
    """
    Generates a random string of 6 chars, use size argument
    to change the size of token.
    Returns a valid token of desired size,
    *default is 6 chars
    """
    BASE_LIST = string.digits + string.ascii_letters

    token = ''.join((random.choice(BASE_LIST)) for char in range(size))
    return token


def url_check(url: str) -> bool:
    """
    Expects a string as argument.
    Retruns True, if URL is valid else False.
    For detailed docs look into urlparse.
    """
    try:
        result = urlparse(url)
        if all([result.scheme, result.netloc]):
            return True
        else:
            return False
    except:
        return False
  • random_token関数は、短縮 URL を作成するためのトークンとして機能するランダムな文字列を生成します。デフォルトでは 6 文字のトークンを作成しますが、size引数を使って調整できます。
    • トークンの生成には、数字(string.digits)と英字(string.ascii_letters)の組み合わせをベースとしたリストを使用します。
    • トークンは、sizeパラメータで指定された回数だけ、BASE_LISTからランダムに文字を選択することで生成されます。これは、リスト内包表記とrandom.choice()を使って行われ、指定されたシーケンスからランダムな要素を選択します。
    • 生成されたトークンは文字列として返されます。このトークンは、短縮 URL の識別子として使用できます。
  • url_check関数は、与えられた URL が適切な形式であることを確認します。
    • urllib.parseモジュールのurlparse関数を使って、与えられた URL をコンポーネントに解析します。
    • この関数は、URL にスキーム(例:httphttps)とネットロケーション(ネットワーク位置、例:www.example.com)の両方があるかどうかを確認します。これらの両方が URL が有効であるために必要な重要なコンポーネントです。
    • 両方のコンポーネントが存在する場合、関数はTrueを返して URL が有効であることを示します。どちらかが欠けている場合、または解析中に例外が発生した場合(例:入力が文字列でない場合)、関数はFalseを返します。
    • この検証は、アプリケーションが処理および保存するのが有効な URL のみであることを確認するために重要です。

これらのユーティリティ関数は、URL 短縮サービスに不可欠であり、短縮 URL の一意の識別子を生成し、システムが有効な URL のみを受け付けることを確保するための重要な機能を提供します。

✨ 解答を確認して練習

初期化とインデックスルートを実装する

最後に、URL 短縮サービスのコア部分である Flask アプリケーションを構築します。

まず、インデックスルートを設定します。このルートはメインページを表示し、GET および POST リクエストの両方を処理します。GET リクエストの場合、すべての短縮 URL を表示します。POST リクエストの場合、短縮する新しい URL を受け取り、一意のトークンを生成してデータベースに保存します。

app.pyに、以下の Python コードを追加します。

from flask import Flask, request, redirect, render_template, make_response

from utils import get_db_connection, list_data, random_token, update_counters, url_check


app = Flask(__name__)


@app.route('/', methods=['GET', 'POST'])
def index():
    with get_db_connection() as conn, conn.cursor() as cursor:
        ## Fetch all data to display on index
        cursor.execute("SELECT * FROM WEB_URL;")
        result_all_fetch = cursor.fetchall()

        if request.method == 'POST':
            og_url = request.form.get('url_input')
            custom_suff = request.form.get('url_custom', '')
            tag_url = request.form.get('url_tag', '')

            token_string = random_token() if not custom_suff else custom_suff

            if og_url and url_check(og_url):
                cursor.execute(
                    "SELECT S_URL FROM WEB_URL WHERE S_URL = %s FOR UPDATE", (token_string,))
                if cursor.fetchone() is None:
                    cursor.execute(
                        "INSERT INTO WEB_URL(URL, S_URL, TAG) VALUES(%s, %s, %s)", (og_url, token_string, tag_url))
                    conn.commit()
                    return render_template('index.html', shorty_url=f"{shorty_host}{token_string}")
                else:
                    error = "The custom suffix already exists. Please use another suffix or leave it blank for a random one."
            else:
                error = "Invalid URL provided. Please enter a valid URL."

            return render_template('index.html', table=result_all_fetch, host=shorty_host, error=error)

        return render_template('index.html', table=result_all_fetch, host=shorty_host)

app.py内のindex関数は、Python で書かれたマイクロウェブフレームワークである Flask を使って URL 短縮サービスのコア機能を設定します。この関数は、アプリケーションのインデックスルート(/)がどのように動作し、GET および POST リクエストの両方を処理するかを定義します。以下はコードの詳細な説明です。

Flask のセットアップ

  • Flask アプリケーションはapp = Flask(__name__)で初期化されます。
  • @app.route('/', methods=['GET', 'POST'])デコレータは、index関数がルート URL(/)へのリクエストを処理し、GET および POST の両方のメソッドを受け付けることを指定します。

GET リクエストの処理

  • 関数が GET リクエストを受け取ると、get_db_connection()ユーティリティ関数を使ってデータベースに接続し、WEB_URLテーブルからすべてのレコードを取得します。これは、インデックスページにすべての短縮 URL を表示するためです。
  • 取得したレコードは、ホスト URL(shorty_host)とともにrender_template関数に渡され、index.htmlテンプレートをレンダリングします。このテンプレートには、おそらく各短縮 URL とその詳細を表示するためのテーブルまたはリストが含まれています。

POST リクエストの処理

  • POST リクエストの場合、通常はインデックスページのフォームから送信されます。関数は、フォームデータから元の URL(og_url)、オプションのカスタムサフィックス(custom_suff)、およびオプションのタグ(tag_url)を抽出します。
  • その後、カスタムサフィックスが提供されない場合、random_token()を使って短縮 URL 用のランダムトークンを生成します。このトークン(またはカスタムサフィックス)は、短縮 URL の一意の識別子として機能します。
  • 処理を続ける前に、関数はurl_check(og_url)を使って元の URL を検証します。URL が有効で、トークン/サフィックスが一意で(データベースに既に存在しない)場合、新しいレコードがWEB_URLテーブルに挿入され、元の URL、短縮 URL としてのトークン/サフィックス、およびタグが含まれます。
  • 操作が成功すると、関数はindex.htmlテンプレートを再レンダリングし、新しく短縮された URL(shorty_url)とすべての既存のレコードを表示します。
  • トークン/サフィックスが既にデータベースに存在する場合、または元の URL が無効な場合、エラーメッセージが設定され、エラーメッセージと既存のレコードを含むindex.htmlテンプレートがレンダリングされます。

エラーハンドリングとテンプレートのレンダリング

  • render_template関数は、すべてのレコードのリスト(table)、短縮リンクのベースホスト URL(host)、新しく短縮された URL(shorty_url)、およびエラーメッセージ(error)などのさまざまなパラメータを渡して、index.htmlテンプレートをレンダリングするために広く使用されます。この関数は、Python 変数を HTML テンプレートに挿入することで、Flask における動的なコンテンツのレンダリングを容易にします。

この Flask アプリケーションは、URL 短縮サービスのバックエンドとして機能し、データベースのやり取り、URL の検証、トークンの生成を処理する一方で、ユーザーの操作とデータベースのコンテンツに基づいて動的に Web ページを生成します。

✨ 解答を確認して練習

リダイレクトルートとアナリティクスルートを実装する

リダイレクトルート

次に、短縮 URL から元の URL にリダイレクトするためのルートを作成します。このルートは、任意の短縮 URL をキャプチャし、データベースで検索して、ユーザーを元の URL にリダイレクトします。

app.pyに以下のコードを追加します。

@app.route('/<short_url>')
def reroute(short_url):
    with get_db_connection() as conn, conn.cursor() as cursor:
        platform = request.user_agent.platform or 'other'
        browser = request.user_agent.browser or 'other'
        browser_dict = {'firefox': 0, 'chrome': 0,'safari': 0, 'other': 0}
        platform_dict = {'windows': 0, 'iphone': 0,
                         'android': 0, 'linux': 0,'macos': 0, 'other': 0}

        ## Increment browser and platform counters
        browser_dict[browser] = browser_dict.get(browser, 0) + 1
        platform_dict[platform] = platform_dict.get(platform, 0) + 1

        cursor.execute(
            "SELECT URL FROM WEB_URL WHERE S_URL = %s;", (short_url,))
        try:
            new_url = cursor.fetchone()[0]
            update_counters(cursor, short_url, browser_dict, platform_dict)
            conn.commit()
            return redirect(new_url)
        except Exception:
            return render_template('404.html'), 404
  • @app.route('/<short_url>')デコレータは、ルート URL の後に続く任意のパスセグメントと一致する動的ルートを作成します。このセグメント(short_url)は、引数としてreroute関数に渡されます。
  • 関数内では、データベース接続を確立し、要求が発生したブラウザーとプラットフォームを追跡するための辞書を初期化します。Flask のrequest.user_agentを使ってブラウザーとプラットフォームを判断します。
  • その後、与えられたshort_urlに関連付けられた元の URL を見つけるための SQL クエリを実行します。見つかった場合、update_counters関数を使ってデータベース内のブラウザーとプラットフォームのカウンターを更新します。
  • データベースに変更をコミットした後、関数は Flask のredirect関数を使ってユーザーを元の URL に送信します。
  • short_urlがデータベースに見つからない場合、またはその他の例外が発生した場合、関数はrender_template('404.html')を使って 404 エラーページをレンダリングします。

アナリティクスルート

特定の短縮 URL に関する詳細情報、たとえばそれがアクセスされた回数や、どのプラットフォームとブラウザーからアクセスされたかを表示するアナリティクスルートを作成します。

app.pyに以下のコードを追加します。

@app.route('/analytics/<short_url>')
def analytics(short_url):
    info_fetch, counter_fetch, browser_fetch, platform_fetch = list_data(
        short_url)
    return render_template("data.html", host=shorty_host, info=info_fetch, counter=counter_fetch, browser=browser_fetch, platform=platform_fetch)
  • @app.route('/analytics/<short_url>')デコレータは、特定の短縮 URL に関するアナリティクスにアクセスするためのルートを定義します。short_urlは URL パスからキャプチャされ、analytics関数に渡されます。
  • 関数はlist_data(short_url)を呼び出し、これはデータベースに短縮 URL に関する情報を照会します。これには、それがアクセスされた回数や、異なるブラウザーとプラットフォームにわたるアクセスの分布が含まれます。
  • 取得したデータ(info_fetchcounter_fetchbrowser_fetchplatform_fetch)は、ホスト URL(shorty_host)とともにrender_template関数に渡され、data.htmlテンプレートをレンダリングします。このテンプレートはおそらく、表やチャートなどのユーザーにやさしい形式でアナリティクスデータを提示します。

これらのルートは、URL 短縮サービスの機能を拡張し、短縮 URL からユーザーを元の宛先にリダイレクトするだけでなく、それらの短縮 URL がどのように使用されているか、アクセス回数や、リンクがアクセスされるデバイスとブラウザーの種類を含む洞察を提供することができます。この情報は、共有された URL の到達範囲と影響を理解するために役立ちます。

✨ 解答を確認して練習

検索ルートを実装してアプリケーションを実行する

検索ルート

ユーザーがタグで短縮 URL を検索できるようにするための検索ルートを設定します。このルートは、GET および POST リクエストの両方を処理し、それぞれ検索フォームを表示し、検索クエリを処理します。

app.pyに以下のコードを追加します。

@app.route('/search', methods=['GET', 'POST'])
def search():
    s_tag = request.form.get('search_url', '')
    if not s_tag:
        return render_template('index.html', error="Please enter a search term.")

    with get_db_connection() as conn, conn.cursor() as cursor:
        cursor.execute("SELECT * FROM WEB_URL WHERE TAG = %s", (s_tag,))
        search_tag_fetch = cursor.fetchall()
        return render_template('search.html', host=shorty_host, search_tag=s_tag, table=search_tag_fetch)
  • @app.route('/search', methods=['GET', 'POST'])デコレータは、/searchにルートを設定し、GET および POST リクエストの両方を処理します。GET リクエストは検索フォームを表示するために使用できますが、POST リクエストはユーザーが送信したフォームデータを処理します。
  • search関数内では、request.form.get('search_url', '')が送信されたフォームデータから検索用語を取得しようとします。2 番目のパラメータ('')は、'search_url'が見つからない場合のデフォルト値で、この場合には検索用語が空文字列になります。
  • 検索用語が提供されていない場合(not s_tag)、関数はエラーメッセージを付けてユーザーをインデックスページにリダイレクトします。このエラーメッセージは、検索用語が必要であることを示しています。
  • 検索用語が提供された場合、関数はデータベースに接続し、WEB_URLテーブル内のTAG列が提供された検索用語と一致するすべてのレコードを見つけるための SQL クエリを実行します。これにより、ユーザーは特定のタグに関連付けられたすべての短縮 URL を見つけることができます。
  • このクエリの結果(search_tag_fetch)は、ホスト URL(shorty_host)と検索用語(s_tag)とともにrender_template関数に渡され、search.htmlテンプレートをレンダリングします。このテンプレートはおそらく結果をリストまたはテーブル形式で表示し、ユーザーが一致するすべてのレコードを見て、おそらくそれらとやり取りすることができます(たとえば、元の URL を訪問したり、アナリティクスを表示したり)。

アプリケーションを実行する

最後に、Flask アプリケーションを実行するためのコードを追加します。これには、アプリケーションがリッスンするホストとポートを設定すること、および環境変数を指定することが含まれます。

app.pyの末尾に以下のコードを追加します。

shorty_host = "https://****.labex.io/"

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=8080)

注:shorty_host内の URL を現在の環境の URL に置き換える必要があります。Web 8080 タブに切り替えることで見つけることができ、URL は/で終わる必要があります。

Web 8080 タブの URL

これで、以下のコマンドを使ってプロジェクトを実行できます。

python app.py

"Web 8080"タブに切り替えて Web ページを再読み込みすると、以下のような効果が見られます。

カスタムサフィックス付きまたはなしで URL を変換し、タグで URL を検索し、リンクにアクセスします。

リンクにアクセスするために使用されたオペレーティングシステムとプラットフォームに関する情報を表示します。

✨ 解答を確認して練習

まとめ

URL 短縮プロジェクトを完了しました!おめでとうございます!このツールは、長い URL を短くて管理しやすいリンクに変換することで、共有を簡素化します。ただし、念頭に置いておく重要な点がいくつかあります:

  1. ベース URL の長さ:短縮サービス自体のベース URL が長い場合、結果として得られる短縮 URL は期待通りに短くならない場合があります(このプロジェクトの場合のように)。短縮 URL の総長にはベース URL が含まれるため、短縮サービスの有効性が制限される可能性があります。最も簡潔な URL を得るには、サービスのベース URL またはドメイン名を短くすることを検討してください。

  2. ウェブサイトの埋め込み制限:「Refused to display 'https://scholar.google.com/' in a frame because it set 'X-Frame-Options' to'sameorigin'.」のようなエラーが発生する場合があります。このエラーは、一部のウェブサイトが「クリックジャッキング」攻撃に対するセキュリティ強化のため、X-Frame-Options HTTP ヘッダを使用して他のドメインの iframe 内にコンテンツを表示させないように設定しているために発生します。サイトがこのヘッダを「sameorigin」に設定すると、埋め込みを同じオリジンを共有する iframe に制限します。これは URL 短縮サービスの制限ではなく、宛先ウェブサイトによって実施されるセキュリティ対策です。円滑なリダイレクトのためには、短縮 URL を直接リンクとして使用することが望ましく、iframe に埋め込むよりも良いでしょう。

これらの点は、Web 開発における利便性とセキュリティのバランスと、最適なツールの使用のためのユーザーの意識の重要性を浮き彫りにしています。