URL Shortener using Flask — with Source Code

Abhishek Sharma
4 min readNov 2, 2022

--

Hello guys, in today’s blog we will build a URL Shortener using Flask. This will be an exciting blog, so without any further due, let’s do it…

Read the full blog here — https://machinelearningprojects.net/url-shortener-using-flask/

Checkout the video here…

Sneak Peek at our URL Shortener using Flask

Install required libraries

pip install flask hashids

Code Files For our URL Shortener

Our Project majorly consists of the following 3 code files:

  • app.py
  • index.html
  • stats.html

app.py

# URL Shortener using Flask

import sqlite3
from hashids import Hashids
from flask import Flask, render_template, request, flash, redirect, url_for

app = Flask(__name__)
app.config['SECRET_KEY'] = 'this should be a secret random string'


connection = sqlite3.connect('database.db')

c = connection.cursor()

c.execute('''CREATE TABLE IF NOT EXISTS urls(
id INTEGER PRIMARY KEY AUTOINCREMENT,
created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
original_url TEXT NOT NULL,
clicks INTEGER NOT NULL DEFAULT 0
)''')

def get_db_connection():
conn = sqlite3.connect('database.db')
conn.row_factory = sqlite3.Row
return conn


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_url=short_url)

return render_template('index.html')



@app.route('/<id>')
def url_redirect(id):
conn = get_db_connection()

original_id = hashids.decode(id)
if original_id:
original_id = original_id[0]
url_data = conn.execute('SELECT original_url, clicks FROM urls WHERE id = (?)', (original_id,)).fetchone()
original_url = url_data['original_url']
clicks = url_data['clicks']

conn.execute('UPDATE urls SET clicks = ? WHERE id = ?',(clicks+1, original_id))
conn.commit()
conn.close()
return redirect(original_url)
else:
flash('Invalid URL')
return redirect(url_for('index'))



@app.route('/stats')
def stats():
conn = get_db_connection()
db_urls = conn.execute('SELECT id, created, original_url, clicks FROM urls').fetchall()
conn.close()

urls = []
for url in db_urls:
url = dict(url)
url['short_url'] = request.host_url + hashids.encode(url['id'])
urls.append(url)

return render_template('stats.html', urls=urls)

index.html

<!doctype html>
<html lang="en">

<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"
integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">

<title>Welcome to FlaskShortener</title>
</head>

<body>
<nav class="navbar navbar-expand-md navbar-light bg-light">
<a class="navbar-brand" href="{{ url_for('index')}}">FlaskTodo</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav"
aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav">
<li class="nav-item active">
<a class="nav-link" href="#">About</a>
</li>

<li class="nav-item active">
<a class="nav-link" href="{{ url_for('stats')}}">Stats</a>
</li>
</ul>
</div>
</nav>
<div class="container">
{% for message in get_flashed_messages() %}
<div class="alert alert-danger">{{ message }}</div>
{% endfor %}

<h1>Welcome to FlaskShortener</h1>
<form method="post">
<div class="form-group">
<label for="url">URL</label>
<input type="text" name="url" placeholder="URL to shorten" class="form-control"
value="{{ request.form['url'] }}" autofocus></input>
</div>

<div class="form-group">
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</form>

{% if short_url %}
<hr>
<span>{{ short_url }}</span><br>
{% endif %}

</div>



<!-- Optional JavaScript -->
<!-- jQuery first, then Popper.js, then Bootstrap JS -->
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"
integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo"
crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"
integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1"
crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"
integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM"
crossorigin="anonymous"></script>
</body>

</html>

stats.html

<!doctype html>
<html lang="en">

<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"
integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">

<title>Welcome to FlaskShortener</title>
</head>

<body>
<nav class="navbar navbar-expand-md navbar-light bg-light">
<a class="navbar-brand" href="{{ url_for('index')}}">FlaskTodo</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav"
aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav">
<li class="nav-item active">
<a class="nav-link" href="#">About</a>
</li>

<li class="nav-item active">
<a class="nav-link" href="{{ url_for('stats')}}">Stats</a>
</li>
</ul>
</div>
</nav>
<h1>{% block title %} FlaskShortener Statistics {% endblock %}</h1>
<table class="table">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">Short</th>
<th scope="col">Original</th>
<th scope="col">Clicks</th>
<th scope="col">Creation Date</th>
</tr>
</thead>
<tbody>
{% for url in urls %}
<tr>
<th scope="row">{{ url['id'] }}</th>
<td>{{ url['short_url'] }}</td>
<td>{{ url['original_url'] }}</td>
<td>{{ url['clicks'] }}</td>
<td>{{ url['created'] }}</td>
</tr>
{% endfor %}
</tbody>
</table>

<!-- Optional JavaScript -->
<!-- jQuery first, then Popper.js, then Bootstrap JS -->
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"
integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo"
crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"
integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1"
crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"
integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM"
crossorigin="anonymous"></script>
</body>

</html>

Our Final Output

Refer to this article for deploying it online — How to Deploy a Flask app online using Pythonanywhere

And this is how you can create a URL Shortener using Flask…

So this is all for this blog folks. Thanks for reading it and I hope you are taking something with you after reading this and till the next time …

Read my last blog — Create an API in Flask and deploy it online

Check out my other machine learning projects, deep learning projects, computer vision projects, NLP projects, and Flask projects at machinelearningprojects.net.

--

--