Check if time is passed – Python

In this tutorial, you will learn how to check if the time is passed in Python.

First, we will get the future time in UTC. In order to get this, first we will get the current time in UTC.

Then we will add 24 hours in it.

After that, we will get time_struct object from it. This will be used to get the Unix timestamp.

Then we will the Unix timestamp using the time_struct object.

Same can be done for getting the current time in UTC but without adding 24 hours in it.

delta is the difference between future Unix timestamp and current one.

Then we will convert the seconds into minutes by dividing it to 60 since each minute has 60 seconds.

And again dividing that to 60 since each hour has 60 minutes. This will return the number of hours since the time is passed.

Finally, we will check if the delta is less than or equal to zero. If it is, it means that the time is passed. If not, it means that the time is not passed yet.

from datetime import datetime, timezone, timedelta
import time

future_time = datetime.now(timezone.utc)		# current datetime in UTC
future_time = future_time + timedelta(hours=24)	# current time + 24 hours
future_time = future_time.timetuple()			# instance of time.struct_time
future_time = time.mktime(future_time)			# Unix timestamp

current_time = datetime.now(timezone.utc)		# current datetime in UTC
current_time = current_time.timetuple()			# instance of time.struct_time
current_time = time.mktime(current_time)		# Unix timestamp

delta = future_time - current_time				# difference between future datetime and current datetime (in seconds)
delta = delta / 60 / 60							# convert seconds into hours

if delta <= 0:								   # check if the time is passed
	print("Time passed")
else:
	print("Time not passed")

You can check the real-world example of this in the URL shortener app we created in Python.

Convert UTC to local timezone – Python

Here’s how you can get the date and time in UTC and convert it to user’s local timezone in Python.

from fastapi import FastAPI
from datetime import datetime, timezone as timezone_module
from dateutil import tz

app = FastAPI()

utc = datetime.now(timezone_module.utc)

# Hardcode zones:
from_zone = tz.gettz("UTC")
to_zone = tz.gettz("Asia/Karachi")

# you can get user's local timezone in Javascript using following code:
# Intl.DateTimeFormat().resolvedOptions().timeZone

# Tell the datetime object that it's in UTC time zone since 
# datetime objects are 'naive' by default
utc = utc.replace(tzinfo=from_zone)

# Convert time zone
local = utc.astimezone(to_zone)

# get in readable format
local = local.strftime("%b %d, %Y %H:%M:%S")

print(local)

Comments has been added with each line for explanation. You can check its real-world example in a URL shortener app we created in Python.

How to fix CORS error in FastAPI Python

If you are developing an application and getting CORS error in Python FastAPI, then you can fix it by first importing the CORS middleware from FastAPI module. Then you need to add that middleware in your FastAPI “app” instance. Allow all origins, all credentials, and all methods and headers.

from fastapi import FastAPI

from fastapi.middleware.cors import CORSMiddleware

app = FastAPI()

app.add_middleware(
	CORSMiddleware,
	allow_origins=["*"],
	allow_credentials=True,
	allow_methods=["*"],
	allow_headers=["*"]
)

It will fix CORS error in your Python FastAPI. Learn how to create a URL shortener app in Python.

Create middleware for specific route – Python

If you are creating an API in Python, and came across a problem where you have to create a middleware but for only specific route. For example, you are creating a user authentication system and want to create a middleware that checks if the user is logged-in. But you want to use that middleware for only few routes, not for all routes. Then this tutorial is for you.

This can be done by creating subapps in Python. To create a subapp in Python, first we need to create a file where we will save the global variable of our subapp.

Create a file, let’s say config.py, and write the following code in it.

# config.py

from fastapi import FastAPI

my_middleware_app = FastAPI()

Now create a file for our middleware, I am naming it my_middleware.py. Following will be the code of this file.

from fastapi import Request
from config import my_middleware_app

from fastapi.responses import JSONResponse
from fastapi.encoders import jsonable_encoder

@my_middleware_app.middleware("http")
async def my_func(request: Request, call_next):
	if "Authorization" in request.headers:
		print(request.headers["Authorization"])

		request.state.name = "Adnan"
		response = await call_next(request)
		return response
	else:
		return JSONResponse(content=jsonable_encoder("Authorization header not provided."))

Explanation:

  1. First, it imports the subapp “my_middleware_app” from “config” module.
  2. Then it imports “JSONResponse” and “jsonable_encoder” from “fastapi” modules. They will be required to send the response back to the client.
  3. Then we are creating a middleware using our subapp “my_middleware_app”.
  4. In this, we are checking if the request has “Authorization” header provided.
    • To learn more about authorization in Python, check our tutorial on user authentication.
  5. If not, then we are sending an error.
  6. If provided, then we are attaching a “name” variable with the request and pass it to the route.

Now let me show you, how the route can use this middleware and how route can access the “name” variable.

Following will be the content of our main.py file where the route will be created.

# main.py

from fastapi import FastAPI, Request
from config import my_middleware_app
import my_middleware

app = FastAPI()

@my_middleware_app.post("/my-route")
def my_route(request: Request):
	return request.state.name

app.mount("/", my_middleware_app)

We first imported the subapp module and the middleware.

Then we created an instance of FastAPI (the main app).

After that, we are creating a post route using our subapp. In this route, we are using the “name” variable we created in our middleware.

To send value from middleware to route, we can use request.state object.

And lastly, we are mounting the subapp to our main app.

Creating a middleware and using it just for specific route in Python is a bit confusing sometimes. So if you face any problem in following this, please do not hesitate to get in touch with me.

Create global variable between modules – Python

In this tutorial, we will show you how you can create global variable and access them in different modules in Python.

First, you need to create a file, let’s say “config.py“. And write all your global variables in it.

# config.py

my_name = "Adnan"

Here, I have created a global variable my_name. In order to access it in any other module, simply import it. Then you can use them as normal variables.

# any_other_module.py

# method 1

from config import my_name

print(my_name)

There is another method to import the module.

# any_other_module.py

# method 2

import config

print(config.my_name)

That is how you can create global variable and use it in multiple modules in Python. Kindly let me know if you face any problem in following this.

Create a URL shortener app in Vue JS, Python, Mongo DB

In this tutorial, we will create a URL shortener app in Vue JS, Python and Mongo DB. We will use Vue JS as frontend, Python as backend and Mongo DB as database.

We will be creating a single page application in Vue JS 3, FastAPI for creating APIs in Python and standard Mongo DB for storing data.

User will enter a URL and the app will create a shorter URL of it. User can share that short URL on social media. Whenever someone access that short URL, we will show ads to him for 5 seconds. Then he will be able to move to the actual URL.

User can see how many people have clicked on his shorten URL and how many have accessed the real URL.

We will create the frontend in Vue JS 3, it will be a single page application (SPA). The backend will be in Python, we will be using FastAPI.

Add URL – Vue JS

The first step is to show user a form where he can enter his URL to shorten. So go ahead and create a folder anywhere in your computer (I have created on desktop). And inside that folder, create 2 more folders named “web” and “api”.

All our frontend code will go in “web” and all our backend code will go in “api”. Now open your command prompt (CMD) or terminal in your “web” folder and run the following command to install Vue JS.

> npm install -g @vue/cli

Then we will create an SPA in that folder.

> vue create .

If asked for Vue JS version, select Vue JS 3. Then run the following command to start Vue JS on localhost.

> npm run serve

You can access your app from http://localhost:8080/

Now go in your “web/src/components” and delete the “HelloWorld.vue” file. And create a file named “HomeComponent.vue”. Following will be the content of that file:

<template>
	HomeComponent
</template>

<script>
	export default {
		name: "HomeComponent"
	}
</script>

Open “src/main.js” and remove the “HelloWorld” component occurrences from there too.

In your components folder, create a folder named “layouts” and create 2 files in it: “AppHeader.vue” and “AppFooter.vue”. Following will be the content of these files:

// AppHeader.vue

<template>
	AppHeader
</template>

<script>
	export default {
		name: "AppHeader"
	}
</script>

// AppFooter.vue
<template>
	AppFooter
</template>

<script>
	export default {
		name: "AppFooter"
	}
</script>

Then run the following command to install “vue-router” that will be used for navigation, “sweetalert2” for displaying popups and “axios” for making AJAX calls.

npm install vue-router sweetalert2 axios

Then in your “main.js”, initialize the vue-router module.

import { createRouter, createWebHistory } from "vue-router"
import HomeComponent from "./components/HomeComponent.vue"

const app = createApp(App)

const routes = [
	{ path: "/", component: HomeComponent }
]

const router = createRouter({
	history: createWebHistory(),
	routes
})

app.use(router)
app.mount('#app')

Open your “web/src/App.vue” and replace the existing content with the following.

<template>
  <app-header />
    <router-view />
  <app-footer />
</template>

<script>

import AppHeader from "./components/layouts/AppHeader.vue"
import AppFooter from "./components/layouts/AppFooter.vue"

export default {
  name: 'App',
  components: {
    AppHeader,
    AppFooter
  }
}
</script>

After that, download Bootstrap 5 and paste the CSS and JS files in your “web/src/assets” folder. Then include them in your AppHeader component.

import "../../assets/css/bootstrap.css"
import "../../assets/js/jquery.js"
import "../../assets/js/bootstrap.js"

If you get any error regarding popper, just run the following commands.

> npm install @popperjs/core
> npm remove @vue/cli-plugin-eslint

Learn more about them in here.

Then open your HomeComponent and create a form inside <template> tag. The form simply have 1 field to enter the URL and a submit button.

<div class="container">
	<div class="row">
		<div class="offset-md-3 col-md-6">
			<form v-on:submit.prevent="shorten_url">
				<div class="form-group">
					<label class="form-label">Enter URL</label>
					<input type="url" name="url" placeholder="Enter URL" class="form-control" required />
				</div>

				<input type="submit" class="btn btn-primary" style="margin-top: 10px;" value="Shorten" />
			</form>

			<!-- [table goes here] -->
		</div>
	</div>
</div>

Then create a function “shorten_url” in your <script> tag in HomeComponent.

import axios from "axios"
import swal from "sweetalert2"

export default {
	name: "HomeComponent",

	methods: {
		async shorten_url() {
			const form = event.target
			const formData = new FormData(form)
			formData.append("timezone", Intl.DateTimeFormat().resolvedOptions().timeZone)

			try {
				const response = await axios.post(
					this.$api_url + "/shorten-url",
					formData
				)

				if (response.data.status == "success") {
					// [on url shortened success]
				} else {
					swal.fire("Error", response.data.message, "error")
				}
			} catch (exp) {
				console.log(exp)
			}
		}
	}
}

In your “main.js” add the following line that defines the URL of our Python API.

app.config.globalProperties.$api_url = "http://127.0.0.1:8000"

In the above function, we are sending form data to the server. We are also sending current timezone, so the server can return the time (in local timezone) when the URL was added.

Add URL – Python, Mongo DB

So the view is created, now we need to create our backend API that will handle this request.

Making sure you have installed Python 3 in your system, run the following commands in your “api” folder.

pip3 install fastapi uvicorn pymongo python-multipart

Create a file named api.py and write the following code in it:

import random, string
from fastapi import FastAPI, Form
from typing_extensions import Annotated
from fastapi.middleware.cors import CORSMiddleware
from pymongo import MongoClient
from bson.objectid import ObjectId
from datetime import datetime, timezone as timezone_module
from dateutil import tz

MONGO_CONNECTING_STRING = "mongodb://localhost:27017"
client = MongoClient(MONGO_CONNECTING_STRING)
db_name = "url_shortener"
db = client[db_name]

app = FastAPI()

app.add_middleware(
	CORSMiddleware,
	allow_origins=["*"]
)

@app.post("/shorten-url")
def shorten_url(url: Annotated[str, Form()], timezone: Annotated[str, Form()]):

	while True:
		random_characters = "".join(random.choice(string.ascii_lowercase) for _ in range(8))
		url_obj = db["urls"].find_one({
			"hash": random_characters
		})

		if (url_obj == None):
			break

	inserted_doc = {
		"_id": ObjectId(),
		"url": url,
		"hash": random_characters,
		"views": 0,
		"clicks": 0,
		"created_at": datetime.now(timezone_module.utc)
	}

	db["urls"].insert_one(inserted_doc)
	inserted_doc["_id"] = str(inserted_doc["_id"])
	inserted_doc["created_at"] = convert_utc_to_local(timezone, inserted_doc["created_at"])

	return {
		"status": "success",
		"message": "URL has been shortened.",
		"url": inserted_doc
	}

def convert_utc_to_local(timezone, utc):
	# Hardcode zones:
	from_zone = tz.gettz('UTC')
	to_zone = tz.gettz(timezone)

	# Tell the datetime object that it's in UTC time zone since 
	# datetime objects are 'naive' by default
	utc = utc.replace(tzinfo=from_zone)

	# Convert time zone
	utc = utc.astimezone(to_zone).strftime("%b %d, %Y %H:%M:%S")

	return utc

To start the API, run the following command in your “api” folder:

uvicorn api:app --reload

You can access it from here:

http://127.0.0.1:8000

You might see it blank and that’s okay. Because it will be accessed via AJAX calls.

Explanation:

First, we are making connection with Mongo DB. Then we are initializing FastAPI and setting CORS middleware to prevent CORS error.

After that, we are creating a function that will handle the request. It accepts URL and timezone.

It will generate random 8 characters and make sure they are unique in database using do-while loop.

Then it will insert the record in database. And in order to return the inserted document to the client side, we need to convert the ObjectId to string.

Date & time will be stored in UTC in database. But to return to client side, we have to convert UTC to user’s local timezone. So we have created a separate function “convert_utc_to_local” for that.

Show all added URLs – Vue JS

In your HomeComponent, write the following code in [table goes here] section.

<table class="table table-bordered" style="margin-top: 50px;">
	<thead>
		<tr>
			<th>URL</th>
			<th>Views</th>
			<th>Clicks</th>
			<th>Created at</th>
		</tr>
	</thead>

	<tbody>
		<tr v-for="(url, index) in urls">
			<td>
				<router-link v-bind:to="'/url/' + url.hash" v-text="url.hash"></router-link>
			</td>
			<td v-text="url.views"></td>
			<td v-text="url.clicks"></td>
			<td v-text="url.created_at"></td>
		</tr>
	</tbody>
</table>

Then in your <script> tag, initialize an empty array.

data() {
	return {
		urls: []
	}
},

And write the following code at [on url shortened success] section:

this.urls.unshift(response.data.url)

Add a “mounted” event in your Vue JS object.

mounted() {
	this.get_data()
}

After that, create the following method inside your “methods” object.

async get_data() {
	const formData = new FormData()
	formData.append("timezone", Intl.DateTimeFormat().resolvedOptions().timeZone)

	try {
		const response = await axios.post(
			this.$api_url + "/fetch-urls",
			formData
		)

		if (response.data.status == "success") {
			this.urls = response.data.urls
		} else {
			swal.fire("Error", response.data.message, "error")
		}
	} catch (exp) {
		console.log(exp)
	}
}

Fetch all URLs – Python, Mongo DB

Now we need to create an API in Python that will fetch all URLs from Mongo DB. Write the following code in your “api/api.py” file.

@app.post("/fetch-urls")
def fetch_urls(timezone: Annotated[str, Form()]):
	urls = db["urls"].find().sort("created_at", -1)

	url_arr = []
	for url in urls:
		url["_id"] = str(url["_id"])
		url["created_at"] = convert_utc_to_local(timezone, url["created_at"])

		url_arr.append(url)

	return {
		"status": "success",
		"message": "Data has been fetched.",
		"urls": url_arr
	}

Test the app now and you will see all your added URLs. Now whenever a URL is clicked, we will show a new page where user will have to wait for 5 seconds to access the real URL.

Access the URL – Vue JS

In your “web/src/components” folder, create a file named “URLComponent.vue” and write the following code in it:

<template>
	URLComponent
</template>

<script>

	export default {
		name: "URLComponent"
	}
</script>

Register it in your “main.js” file.

import URLComponent from "./components/URLComponent.vue"

And add it in “routes” array too.

{ path: "/url/:url", component: URLComponent }

Back to your URLComponent, write the following code inside <template> tag.

<div class="container">
	<div class="row">
		<div class="col-md-12">
			<div class="float-end" style="padding: 15px;
			    border-radius: 5px;
			    background-color: lightblue;
			    cursor: pointer;">
			    <span v-if="remaining_seconds > 0">
			    	Redirecting in <span v-text="remaining_seconds"></span> seconds
			    </span>
				
			    <span v-else v-on:click="goto_website">Go to website</span>
			</div>
		</div>
	</div>
</div>

This will show a text that will show the number of seconds remaining till user has to wait. When the time is over, it will show a clickable text which when clicked, should move the user to the actual URL.

import axios from "axios"
import swal from "sweetalert2"

export default {
	name: "URLComponent",

	data() {
		return {
			url: this.$route.params.url,
			remaining_seconds: 5,
			url_obj: null,
			interval: null
		}
	},

	methods: {
		async goto_website() {
			if (this.url_obj == null) {
				return
			}

			window.location.href = this.url_obj.url
		},

		async get_data() {
			const formData = new FormData()
			formData.append("url", this.url)

			try {
				const response = await axios.post(
					this.$api_url + "/get-url",
					formData
				)

				if (response.data.status == "success") {
					this.url_obj = response.data.url
				} else {
					swal.fire("Error", response.data.message, "error")
				}
			} catch (exp) {
				console.log(exp)
			}
		}
	},

	mounted() {
		const self = this
		this.get_data()

		setTimeout(function () {
			self.interval = setInterval(function () {
				self.remaining_seconds--

				if (self.remaining_seconds <= 0) {
					clearInterval(self.interval)
				}
			}, 1000)
		}, 500)
	}
}

When this component is mounted, we will call “get_data” function that will fetch the single URL data from Python API.

Also, it will start a countdown timer from 5. Once timer hits 0, you can click the button and go to your actual URL.

Fetch single URL – Python, Mongo DB

Create the following API in your “api/api.py” file.

@app.post("/get-url")
def get_url(url: Annotated[str, Form()]):

	url = db["urls"].find_one({
		"hash": url
	})

	if (url == None):
		return {
			"status": "error",
			"message": "URL not found."
		}

	url["_id"] = str(url["_id"])

	return {
		"status": "success",
		"message": "Data has been fetched.",
		"url": url
	}

This will fetch the single URL from Python API.

Number of clicks on Shorten URL

When you share the shorten URL with your friends, you might want to know how many have clicked the shorten URL and how many clicked the actual URL.

To increment number of clicks on shorten URL, we will simply go to “api.py” function “get_url” and add the following code before converting ObjectId “_id” to string.

db["urls"].find_one_and_update({
	"_id": url["_id"]
}, {
	"$inc": {
		"views": 1
	}
})

Test now and you will see whenever someone access your shorten URL page, your “views” gets incremented in HomeComponent.

Number of clicks on actual URL

In order to see how many has clicked on your actual URL, you need to open your “URLComponent.vue” file. Add the following lines in your “goto_website” function before the “window.location.href” line.

const formData = new FormData()
formData.append("url", this.url)
window.navigator.sendBeacon((this.$api_url + "/url-clicked"), formData)

Then create its API in Python that will handle this request.

@app.post("/url-clicked")
def url_clicked(url: Annotated[str, Form()]):
	db["urls"].find_one_and_update({
		"hash": url
	}, {
		"$inc": {
			"clicks": 1
		}
	})

Now whenever someone visit the actual URL, the “clicks” counter gets incremented.

Header and Footer

Write the following code insde <template> tag of your AppHeader component.

<nav class="navbar navbar-expand-lg navbar-light bg-light">
  <div class="container-fluid">
    <router-link class="navbar-brand" to="/">URL Shortener</router-link>
    <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
      <span class="navbar-toggler-icon"></span>
    </button>
    <div class="collapse navbar-collapse" id="navbarSupportedContent">
      <ul class="navbar-nav me-auto mb-2 mb-lg-0">
        <li class="nav-item">
          <router-link class="nav-link active" aria-current="page" to="/">Home</router-link>
        </li>
      </ul>
    </div>
  </div>
</nav>

And change your AppFooter component to the following.

<template>
	<footer class="container-fluid" style="margin-top: 50px; background-color: #e9e9e9; padding: 25px;">
		<p class="text-center" style="margin-bottom: 0px;">
			&copy;<span v-text="year"></span>&nbsp;
			adnan-tech.com
		</p>
	</footer>
</template>

<script>
	export default {
		name: "AppFooter",

		data() {
			return {
				year: new Date().getFullYear()
			}
		}
	}
</script>

So this is how you can create a URL shortener app using Vue JS as frontend, Python as backend and Mongo DB as database. If you face any problem in following this, kindly do let me know.

Python API development

In this article, we will talk about basic Python API development.

Python API development

Install python3. Download from its official website and install.

Create API by first installing following modules:

pip3 install fastapi
pip3 install uvicorn

Create a file named api.py and write the following code in it:

from fastapi import FastAPI
app = FastAPI()

@app.get("/my-first-api")
def hello():
	return ("Hello world !")

if __name__ == "__main__":
	uvicorn.run(app, port=8000, host="127.0.0.1")

Run the following command in terminal to start the API:

uvicorn api:app --reload

Access it from browser:

http://127.0.0.1:8000/my-first-api

CORS error

If you are having CORS error, you can make the following changes in your code:

from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

app = FastAPI()

app.add_middleware(
	CORSMiddleware,
	allow_origins=["*"]
)

Connect Python with Mongo DB

To connect your Python application with Mongo DB, first install pymongo in your server by running the following command:

> pip3 install pymongo

Then you need to import it in your file:

from pymongo import MongoClient

MONGO_CONNECTING_STRING = "mongodb://localhost:27017"
client = MongoClient(MONGO_CONNECTING_STRING)
db = client["your_database_name"]

To insert a document in collection, write the following line:

db["your_collection"].insert_one({
	"name": "Adnan"
})

Form data

Let’s say you have a Javascript code that sends an AJAX request to your Python server.

const formData = new FormData()
formData.append("website", "adnan-tech.com")

Then, in order to get it in your Python API, first you need to run the following command to install “python-multipart” module:

pip3 install python-multipart

Then include the “Form” and “Annotated” module.

from fastapi import FastAPI, Form
from typing_extensions import Annotated

Then in your post API method parameter, define each form data value and its type.

@app.post("/my-api")
async def my_api(website: Annotated[str, Form()]):

	print(url)

Installing Django framework

For Python API development you can also use Django framework. First, you need to install Django framework in your project’s root directory:

pip3 install django

Then you can verify it by checking the version:

python3 -m django --version

You can also verify the version from following command as well:

django-admin --version

Then we will create our django application:

django-admin startproject ecommerce-website

A new folder will be created named “ecommerce-website”. If you go inside this folder, you will find files named “manage.py” and other files along with a directory named same as “ecommerce-website”.

Now enter in the directory “ecommerce-website” and run the following command:

python3 manage.py startapp ecommerce

It will create a directory named “ecommerce”. Now run the following command to start the server:

python3 manage.py runserver

Now you can access your website by running the following URL in the browser:

http://127.0.0.1:8000/

You can access admin panel from:

http://127.0.0.1:8000/admin

It will ask for username and password. You can set it by first running the migration:

python3 manage.py migrate

Then you can create a super user.

python3 manage.py createsuperuser

Create app in Django

Run the following command at the root of your project:

python3 manage.py startapp pages

This will create a folder named “pages”.

Now open “ecommerce/settings.py” and add our app to the “INSTALLED_APPS” array.

INSTALLED_APPS = [
    ...
    "pages"
]

You can get your app name by opening the file “pages/apps.py”.

To create a view, open “pages/views.py” and add the following lines in it:

from django.shortcuts import render
from django.http import HttpResponse

# Create your views here.

def index(request):
	return HttpResponse("<h1>Hello world</h1>")

To configure the URL, create a file named “urls.py” inside “pages” folder and write the following code in it:

from django.urls import path
from . import views

urlpatterns = [
	path("", views.index, name="index")
]

Now open your project’s root “ecommerce/urls.py” and add the following line in it:

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path("", include("pages.urls")),
    path('admin/', admin.site.urls),
]

If you check your browser now at: http://127.0.0.1:8000/, you will see your message “Hello world” in it.

Creating models in Django

To create a model, open your app’s “models.py” file. In my case, it is “pages/models.py”. And write the following code in it:

class Page(models.Model):
	title = models.CharField(max_length = 255)
	content = models.TextField("Content", blank = True)

	def __str__(self):
		return self.title

It will create 2 fields (title and content). The “__str__” function is created to display the page title on admin panel where page listing is displayed.

Then you have to create its migration and migrate it. So run the following commands one-by-one:

python3 manage.py makemigrations pages
python3 manage.py migrate

Then in order to display it on admin panel, open your “pages/admin.py” file and add the following code in it:

from .models import Page

class PageAdmin(admin.ModelAdmin):
	list_display = ("title", "content",)
	ordering = ("title",)
	search_fields = ("title", "content",)

# Register your models here.
admin.site.register(Page, PageAdmin)

This will first import our Page model. Then it will create a class to handle it on admin panel. We will display 2 columns (title and content) on admin panel listing.

The ordering will be done by title field only.

And a search field will be displayed, from where user can search pages by their title or content.

At the end, we are registering both of these classes (Page and PageAdmin) to the admin panel.

Now if you go to your admin panel, you will see an option to manage pages.

Templating

First create a folder named “templates” in your “myEcommerce” folder.

Then goto your project’s “settings.py” file and first import the os module at the top of it.

import os

Then search for array “TEMPLATES”. Add your templates folder path in the DIRS array:

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, "myEcommerce/templates")],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

Also, add the following array after the STATIC_URL variable:

STATICFILES_DIRS = [
    os.path.join(BASE_DIR, "myEcommerce/static")
]

In your templates folder, create a file named “base.html”.

Write the following code in your base.html file:

{% load static %}

<link rel="stylesheet" type="text/css" href="{% static 'main.css' %}" />

<h1>My template loaded</h1>

Then in your “myEcommerce/static” folder, create a filed named “main.css” and write the following code in it:

h1 {
	color: red;
}

And finally, change your “def index(request)” function inside “pages/views.py” to the following:

def index(request):
	return render(request, "base.html")

If you run the browser now, you will see your content from base.html file. And also it will load css from main.css file.

Template inheritance

You can create child template that extends from parent template. This will be helpful while creating header, footers or sidebars etc.

For that, add the following code in your “base.html” file:

{% block content %}

{% endblock content %}

You can set any name to your block. Now create a folder named “pages” inside “pages/templates” folder. This is necessary because Django will search for your files inside the “templates” folder.

Then create a file named “index.html” in your “pages/templates/pages” folder. Following will be the code of this file:

{% extends "base.html" %}

{% block content %}

<p>Hi</p>

{% endblock content %}

It first extends from base template. So the content of “base.html” will be display on top and “block content” will be displayed where it is mentioned in “base.html” file.

Finally, in your “pages/views.py” make the following changes:

# return render(request, "base.html")
return render(request, "pages/index.html")

If you refresh your page now, you will first see the content of base template. Then of your “pages/index.html” file.

Model to view (Overriding the view)

To fetch data from model and pass it to view, first goto “pages/urls.py” and comment out the previous path() function we created earlier in this post.

And add the following 2 paths, one for home page and one for other pages appending in the URL.

path("", views.index, {
	"pagename": 1
}, name="home"),
path("<str:pagename>", views.index, name="index")

This will pass variable named “pagename” to the view from the URL. So we need to catch that variable.

Open “pages/views.py” and change your index function to the following:

from django.shortcuts import render
from django.http import HttpResponse
from . models import Page

# Create your views here.

def index(request, pagename):
	page = Page.objects.get(id = pagename)
	context = {
		"title": page.title,
		"content": page.content
	}
	return render(request, "pages/index.html", context)

We have added “pagename” as an argument in the index function definition. Then we are getting the record from Page model using ID. And finally we are passing the page object from database to our view render function.

Then in our “pages/templates/pages/index.html”, we can display these values:

<h2>{{ title }}</h2>

<p>{{ content }}</p>

If your content contains HTML tags, then Django by default will escape them to prevent you from attacker’s attempts to inject executable code into your website.

You can render HTML tags by disabling the auto-escaping like this:

{% autoescape off %}

<p>{{ content }}</p>

{% endautoescape %}

If you run “http://127.0.0.1:8000” in your browser now, you will see the first page. Because its ID is 1.

But if you try “http://127.0.0.1:8000/2”, you will see second page. Because now it matches with ID.

Creating menus

To display all pages as menu hyperlinks, first we need to fetch all pages from database. So in your “pages/views.py”, change the context variable to the following:

context = {
	"title": page.title,
	"content": page.content,
	"pages": Page.objects.all()
}

Then in your “myEcommerce/templates/base.html” file, create a block where the child will render it:

{% block pages %}

{% endblock pages %}

And finally in your “pages/templates/pages/index.html”, you can render them as following:

{% block pages %}

<ul>
	{% for page in pages %}

		<li>
			<a href="{{ page.id }}">
				{{ page.title }}
			</a>
		</li>

	{% endfor %}
</ul>

{% endblock pages %}

If you refresh the browser now, you will see a list of all pages created from admin panel. On clicking any, will display the content of that page.

So these are all the basics for Python API development. You can move advance from here. But this is enough to get you started in API development using Python.

For frontend, you can use Vue JS. You can get our list of tutorials on Vue JS as well.