Sick Gaming
[Tut] How I Used the Flask Framework to Create an URL Shortener Application - Printable Version

+- Sick Gaming (https://www.sickgaming.net)
+-- Forum: Programming (https://www.sickgaming.net/forum-76.html)
+--- Forum: Python (https://www.sickgaming.net/forum-83.html)
+--- Thread: [Tut] How I Used the Flask Framework to Create an URL Shortener Application (/thread-100981.html)



[Tut] How I Used the Flask Framework to Create an URL Shortener Application - xSicKxBot - 04-14-2023

How I Used the Flask Framework to Create an URL Shortener Application

<div>
<div class="kk-star-ratings kksr-auto kksr-align-left kksr-valign-top" data-payload='{&quot;align&quot;:&quot;left&quot;,&quot;id&quot;:&quot;1289207&quot;,&quot;slug&quot;:&quot;default&quot;,&quot;valign&quot;:&quot;top&quot;,&quot;ignore&quot;:&quot;&quot;,&quot;reference&quot;:&quot;auto&quot;,&quot;class&quot;:&quot;&quot;,&quot;count&quot;:&quot;1&quot;,&quot;legendonly&quot;:&quot;&quot;,&quot;readonly&quot;:&quot;&quot;,&quot;score&quot;:&quot;5&quot;,&quot;starsonly&quot;:&quot;&quot;,&quot;best&quot;:&quot;5&quot;,&quot;gap&quot;:&quot;5&quot;,&quot;greet&quot;:&quot;Rate this post&quot;,&quot;legend&quot;:&quot;5\/5 - (1 vote)&quot;,&quot;size&quot;:&quot;24&quot;,&quot;title&quot;:&quot;How I Used the Flask Framework to Create an URL Shortener Application&quot;,&quot;width&quot;:&quot;142.5&quot;,&quot;_legend&quot;:&quot;{score}\/{best} - ({count} {votes})&quot;,&quot;font_factor&quot;:&quot;1.25&quot;}'>
<div class="kksr-stars">
<div class="kksr-stars-inactive">
<div class="kksr-star" data-star="1" style="padding-right: 5px">
<div class="kksr-icon" style="width: 24px; height: 24px;"></div>
</p></div>
<div class="kksr-star" data-star="2" style="padding-right: 5px">
<div class="kksr-icon" style="width: 24px; height: 24px;"></div>
</p></div>
<div class="kksr-star" data-star="3" style="padding-right: 5px">
<div class="kksr-icon" style="width: 24px; height: 24px;"></div>
</p></div>
<div class="kksr-star" data-star="4" style="padding-right: 5px">
<div class="kksr-icon" style="width: 24px; height: 24px;"></div>
</p></div>
<div class="kksr-star" data-star="5" style="padding-right: 5px">
<div class="kksr-icon" style="width: 24px; height: 24px;"></div>
</p></div>
</p></div>
<div class="kksr-stars-active" style="width: 142.5px;">
<div class="kksr-star" style="padding-right: 5px">
<div class="kksr-icon" style="width: 24px; height: 24px;"></div>
</p></div>
<div class="kksr-star" style="padding-right: 5px">
<div class="kksr-icon" style="width: 24px; height: 24px;"></div>
</p></div>
<div class="kksr-star" style="padding-right: 5px">
<div class="kksr-icon" style="width: 24px; height: 24px;"></div>
</p></div>
<div class="kksr-star" style="padding-right: 5px">
<div class="kksr-icon" style="width: 24px; height: 24px;"></div>
</p></div>
<div class="kksr-star" style="padding-right: 5px">
<div class="kksr-icon" style="width: 24px; height: 24px;"></div>
</p></div>
</p></div>
</div>
<div class="kksr-legend" style="font-size: 19.2px;"> 5/5 – (1 vote) </div>
</p></div>
<p>A URL shortener service generates a shorter, more readable version of the URL it was given. Flask, a Python web framework can be used to create a URL shortener app. </p>
<p>So, we will create an application allowing users to enter a URL and shorten it. We will use the SQLite database engine to store application data.<br />If you prefer to learn how this is done using the <a href="https://blog.finxter.com/how-i-created-an-url-shortener-app-using-django/" data-type="post" data-id="1196939" target="_blank" rel="noreferrer noopener">Django framework, you are free to read this article</a>.</p>
<h2 class="wp-block-heading">Set up</h2>
<div class="wp-block-image">
<figure class="aligncenter size-full"><img loading="lazy" decoding="async" width="773" height="579" src="https://blog.finxter.com/wp-content/uploads/2023/04/image-109.png" alt="" class="wp-image-1289261" srcset="https://blog.finxter.com/wp-content/uploads/2023/04/image-109.png 773w, https://blog.finxter.com/wp-content/uploads/2023/04/image-109-300x225.png 300w, https://blog.finxter.com/wp-content/uploads/2023/04/image-109-768x575.png 768w" sizes="(max-width: 773px) 100vw, 773px" /></figure>
</div>
<p>Create a new folder for this project. Then, create and <a href="https://blog.finxter.com/setup-a-virtual-environment-with-visual-studio-code-in-python/" data-type="post" data-id="935562" target="_blank" rel="noreferrer noopener">activate a virtual environment</a> by running the following commands in your terminal.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">python3 -m venv venv
source venv/bin/activate</pre>
<p><a href="https://blog.finxter.com/how-to-install-flask-in-python/" data-type="post" data-id="35862" target="_blank" rel="noreferrer noopener">Install Flask</a> and the <code>hashids</code> library.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">pip install flask hashids</pre>
<p>The <code>hashids</code> library will be used to generate a unique ID. You will understand this as we proceed.</p>
<h2 class="wp-block-heading">Creating a Database Engine</h2>
<div class="wp-block-image">
<figure class="aligncenter size-full"><img decoding="async" loading="lazy" width="773" height="515" src="https://blog.finxter.com/wp-content/uploads/2023/04/image-110.png" alt="" class="wp-image-1289263" srcset="https://blog.finxter.com/wp-content/uploads/2023/04/image-110.png 773w, https://blog.finxter.com/wp-content/uploads/2023/04/image-110-300x200.png 300w, https://blog.finxter.com/wp-content/uploads/2023/04/image-110-768x512.png 768w" sizes="(max-width: 773px) 100vw, 773px" /></figure>
</div>
<p>Since we will store application data, we must create a database file. Do it and call the file <code>schema.sql</code>. Then, write the following SQL commands.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">DROP TABLE IF EXISTS urls;
CREATE TABLE urls( id INTEGER PRIMARY KEY AUTOINCREMENT, created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, original_url TEXT NOT NULL, clicks INTEGER NOT NULL DEFAULT 0
);</pre>
<p>If the above code seems strange, you may want to familiarize yourself with SQL commands. </p>
<p>We want to create a table named <code>urls</code>. As we don’t want to face issues caused by several tables with the same name, we must first delete it. That’s what is meant by ‘<code>DROP TABLE…</code>’</p>
<p>The table is then created with four columns. The <code>id</code> column will contain the unique integer value for each entry. Next is the date the shortened URL was generated. The third column is the original URL. Finally, the number of times the URL was clicked.</p>
<p>The <code>schema.sql</code> file can only be executed with the help of a Python script. So, we create another file called <code>init_db.py</code></p>
<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">import Sqlite3 connection = Sqlite3.connect('database.db') with open('schema.sql') as sql: connection.executescript(sql.read()) connection.commit()
connection.close()
</pre>
</p>
<p>Once you run the script (with <code>python3 init_db.py</code>), a new file called <code>database.db</code> will be created. This is where all application data will be stored.</p>
<p>The <code>connect()</code> method creates the file. As soon as the file is created, it is then populated with the urls table. This is done by first opening and reading the content from the <code>schema.sql</code>. </p>
<p>It then calls the <code>executescript()</code> method to execute all the SQL commands in the SQL file. After which, we commit and close the file. By now, your folder should contain the following files:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">database.db init_db.py schema.sql</pre>
<h2 class="wp-block-heading">Creating the Database Connection</h2>
<div class="wp-block-image">
<figure class="aligncenter size-full"><img decoding="async" loading="lazy" width="607" height="911" src="https://blog.finxter.com/wp-content/uploads/2023/04/image-111.png" alt="" class="wp-image-1289264" srcset="https://blog.finxter.com/wp-content/uploads/2023/04/image-111.png 607w, https://blog.finxter.com/wp-content/uploads/2023/04/image-111-200x300.png 200w" sizes="(max-width: 607px) 100vw, 607px" /></figure>
</div>
<p>Let us open a connection to the database file. Create a file and name it <code>db_connection.py</code>.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">import sqlite3 def get_db_connection(): conn = sqlite3.connect('database.db') conn.row_factory = sqlite3.Row return conn
</pre>
<p>Notice that we set the row-factory attribute to <code>sqlite3.Row</code>. This makes it possible to access values by column name. We then return the connection object, which will be used to access the database.</p>
<h2 class="wp-block-heading">The Main File</h2>
<div class="wp-block-image">
<figure class="aligncenter size-full"><img decoding="async" loading="lazy" width="607" height="911" src="https://blog.finxter.com/wp-content/uploads/2023/04/image-112.png" alt="" class="wp-image-1289267" srcset="https://blog.finxter.com/wp-content/uploads/2023/04/image-112.png 607w, https://blog.finxter.com/wp-content/uploads/2023/04/image-112-200x300.png 200w" sizes="(max-width: 607px) 100vw, 607px" /></figure>
</div>
<p>Next, create another file and name it <code>main.py</code>. This will be our main file. In this file, we will import the database connection file.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">from db_connection import get_db_connection
from hashids import Hashids
from flask import Flask, flash, render_template, request, url_for, redirect app = Flask(__name__)
app.config['SECRET_KEY'] = 'Your secret key' hashids = Hashids(min_length=4, salt=app.config['SECRET_KEY']) @app.route('/', methods=('GET', 'POST'))
def index(): conn = get_db_connection() if request.method == 'POST': url = request.form['url'] if not url: flash('The URL is required!') return redirect(url_for('index')) url_data = conn.execute('INSERT INTO urls (original_url) VALUES (?)', (url,)) conn.commit() conn.close() url_id = url_data.lastrowid hashid = hashids.encode(url_id) short_url = request.host_url + hashid return render_template('index.html', short_run=short_url) return render_template('index.html')
</pre>
<p>We create an instance of the Flask class. The <code>__name__</code> variable allows Flask to locate other resources, including templates in the current directory. We then create hashids object that will have four characters. (You can choose to have more characters). We use a secret key to specify the salt for the Hashids library. </p>
<div class="wp-block-image">
<figure class="aligncenter size-full"><img decoding="async" loading="lazy" width="720" height="405" src="https://blog.finxter.com/wp-content/uploads/2023/04/image-107.png" alt="" class="wp-image-1289239" srcset="https://blog.finxter.com/wp-content/uploads/2023/04/image-107.png 720w, https://blog.finxter.com/wp-content/uploads/2023/04/image-107-300x169.png 300w" sizes="(max-width: 720px) 100vw, 720px" /></figure>
</div>
<p>The <code>index()</code> function is decorated with the <code>@app.route</code> <a href="https://blog.finxter.com/3-top-design-patterns-in-python-singletons-decorators-and-iterators/" data-type="post" data-id="151218" target="_blank" rel="noreferrer noopener">decorator</a> that assigns the URL (<code>'/'</code>) to the function, thus turning it into a Flask view function.</p>
<p>In the <code>index()</code> function, we open a database connection. Then, we check if the request method is POST. If so, the code block under it will be executed. If not, we only return an empty web page using the <code>render_template()</code> method.</p>
<p>If the request method is POST, we use <code>request.form['url']</code> to collect input from the template file (<code>index.html</code>). The output is the URL to shorten. However, if the user gives no URL, we simply flash a message and redirect the user back to the same <code>index.html</code> web page.</p>
<p>If a URL is given, it will be added to the database by executing the command, <code>INSERT INTO …</code></p>
<p>After closing the database, we select the last row id of the database, which is the current URL added. Remember the AUTOINCREMENT keyword in the id column of the database file. This ensures that the id is incremented with each new entry.</p>
<p>With the last row id selected, we use the <code>hashids.encode()</code> method to generate a unique hash and concatenate it to the URL of the application’s host (indicated with the <code>request.host_url</code> attribute). This becomes the shortened URL that would be displayed to the user.</p>
<p>Please <a href="https://github.com/finxter/flask_url_shortener" data-type="URL" data-id="https://github.com/finxter/flask_url_shortener" target="_blank" rel="noreferrer noopener">check my GitHub page</a> for the template files. Make sure you create a templates folder to keep the HTML files.</p>
<p>The local server is opened when you run <code>python3 main.py</code> in your terminal. This is possible because of the special <code>name</code> variable and the <code>app.run()</code> method.</p>
<h2 class="wp-block-heading">Adding Extra Features</h2>
<div class="wp-block-image">
<figure class="aligncenter size-full"><img decoding="async" loading="lazy" width="607" height="911" src="https://blog.finxter.com/wp-content/uploads/2023/04/image-113.png" alt="" class="wp-image-1289268" srcset="https://blog.finxter.com/wp-content/uploads/2023/04/image-113.png 607w, https://blog.finxter.com/wp-content/uploads/2023/04/image-113-200x300.png 200w" sizes="(max-width: 607px) 100vw, 607px" /></figure>
</div>
<p>Won’t it be nice to know how many times each URL has been clicked and have them displayed on a web page? We are going to add that feature. Update your <code>app.py</code> by adding the following:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@app.route('/stats')
def stats(): conn = get_db_connection() db_urls = conn.execute('SELECT * FROM urls').fetchall() conn.close() urls = [] for url in db_urls: url = dict(url) url['short_url'] = request.host_url + hasids.encode(url['id']) urls.append(url) return render_template('stats.html', urls=urls)</pre>
<p>We again open a database connection, and fetch all the columns in the urls table (indicated by <code>*</code>) and a <a href="https://blog.finxter.com/python-lists/" data-type="post" data-id="7332" target="_blank" rel="noreferrer noopener">list</a> of all the rows using the <code>fetchall()</code> method.</p>
<figure class="wp-block-image size-full"><img decoding="async" loading="lazy" width="720" height="405" src="https://blog.finxter.com/wp-content/uploads/2023/04/image-108.png" alt="" class="wp-image-1289254" srcset="https://blog.finxter.com/wp-content/uploads/2023/04/image-108.png 720w, https://blog.finxter.com/wp-content/uploads/2023/04/image-108-300x169.png 300w" sizes="(max-width: 720px) 100vw, 720px" /></figure>
<p>After closing the database, we loop through the result. In each iteration, we convert the <code>sqlite3.Row</code> object to a <a href="https://blog.finxter.com/python-dictionary/" data-type="post" data-id="5232" target="_blank" rel="noreferrer noopener">dictionary</a> and repeat the same thing we did previously to encode the id number. This is then concatenated to form a new URL. Finally, we <a href="https://blog.finxter.com/python-list-append/" data-type="post" data-id="6605" target="_blank" rel="noreferrer noopener">append the result</a> to an empty list and render it to the browser. </p>
<p class="has-base-2-background-color has-background"><img src="https://s.w.org/images/core/emoji/14.0.0/72x72/1f4a1.png" alt="?" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Notice we didn’t commit the database as we did previously. This is because we didn’t make changes to the database. We close it after fetching the data we needed.</p>
<p>Your folder should now have the following files:</p>
<ul>
<li><code>database.db</code>, </li>
<li><code>db_connection.py</code>, </li>
<li><code>init_db.py</code>, </li>
<li><code>main.py</code>, </li>
<li><code>schema.sql</code>, <code>templates</code>.</li>
</ul>
<h2 class="wp-block-heading">Templates Files</h2>
<div class="wp-block-image">
<figure class="aligncenter size-full"><img decoding="async" loading="lazy" width="773" height="511" src="https://blog.finxter.com/wp-content/uploads/2023/04/image-114.png" alt="" class="wp-image-1289269" srcset="https://blog.finxter.com/wp-content/uploads/2023/04/image-114.png 773w, https://blog.finxter.com/wp-content/uploads/2023/04/image-114-300x198.png 300w, https://blog.finxter.com/wp-content/uploads/2023/04/image-114-768x508.png 768w" sizes="(max-width: 773px) 100vw, 773px" /></figure>
</div>
<p>As earlier stated, you should check my <a href="https://github.com/finxter/flask_url_shortener" data-type="URL" data-id="https://github.com/finxter/flask_url_shortener">GitHub page</a> for the templates files. We created a <code>base.html</code> file inside the <code>templates</code> folder that other files will inherit. </p>
<p>The other two files have certain things that make rendering dynamic content to our Flask web page possible. It is the <code>{% ... %}</code> and <code>{ ... }</code> code blocks. </p>
<p>These are Jinja2 templating language that comes together with the Flask library. </p>
<p>The <code>render_templates()</code> method in the <code>stats()</code> function has another argument, <code>urls</code>. This is from the <code>stats.html</code> web page, while the other <code>urls</code> is the variable that will be displayed on the web page.</p>
<h2 class="wp-block-heading">Conclusion</h2>
<div class="wp-block-image">
<figure class="aligncenter size-full"><img decoding="async" loading="lazy" width="607" height="911" src="https://blog.finxter.com/wp-content/uploads/2023/04/image-115.png" alt="" class="wp-image-1289273" srcset="https://blog.finxter.com/wp-content/uploads/2023/04/image-115.png 607w, https://blog.finxter.com/wp-content/uploads/2023/04/image-115-200x300.png 200w" sizes="(max-width: 607px) 100vw, 607px" /></figure>
</div>
<p>This is one of the ways to create a URL shortener app using the Flask framework. This project has expose us to how Flask works as well as how it interacts with database. If you struggle to understand some of what we did, that should be expected as a beginner. However, as you keep working on projects, it will become second nature to you.</p>
<p class="has-base-2-background-color has-background"><img src="https://s.w.org/images/core/emoji/14.0.0/72x72/1f4a1.png" alt="?" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong>Recommended</strong>: <a href="https://blog.finxter.com/how-i-created-an-url-shortener-app-using-django/" data-type="post" data-id="1196939" target="_blank" rel="noreferrer noopener">How I Created an URL Shortener App Using Django</a></p>
</div>


https://www.sickgaming.net/blog/2023/04/13/how-i-used-the-flask-framework-to-create-an-url-shortener-application/