Yesterday I wrapped up OOP. Today I covered the remaining Python topics I needed before diving into Django properly: modules and packages, exception handling, file I/O and JSON, and virtual environments. These aren't as heavy as functions or OOP, but they're the practical glue that holds real projects together. At the end, I looked at how a Django project is actually structured — and realized everything I learned today shows up directly in it.
Modules and Packages
What is a Module?
A module is just a Python file. Any .py file you create is a module that can be imported elsewhere.
# math_utils.py
def add(a, b):
return a + b
def subtract(a, b):
return a - b
# main.py
import math_utils
print(math_utils.add(5, 3)) # 8
print(math_utils.subtract(5, 3)) # 2
You can also import specific things:
from math_utils import add
print(add(5, 3)) # 8
What is a Package?
A package is a folder containing multiple modules, with a special __init__.py file inside it. That file can be empty; its presence is what tells Python "this folder is a package."
myproject/
__init__.py
math_utils.py
string_utils.py
from myproject import math_utils
from myproject.string_utils import capitalize
This is exactly how Django apps are structured; every app folder is a package.
Import Styles
import os # import entire module
from os import path # import specific thing
from os import path as p # import with alias
from os import * # import everything (avoid this)
Exception Handling
Exceptions are errors that occur at runtime. Without handling them, your program crashes. With handling them, you control what happens instead.
try / except
try:
result = 10 / 0
except ZeroDivisionError:
print("Can't divide by zero")
except with multiple exceptions
try:
value = int("abc")
except (ValueError, TypeError) as e:
print(f"Error: {e}")
else and finally
try:
file = open("data.txt", "r")
except FileNotFoundError:
print("File not found")
else:
print("File opened successfully") # runs only if no exception
file.close()
finally:
print("This always runs") # runs no matter what
Raising Exceptions
def set_age(age):
if age < 0:
raise ValueError("Age cannot be negative")
return age
Custom Exceptions
class InsufficientFundsError(Exception):
def __init__(self, amount):
self.amount = amount
super().__init__(f"Insufficient funds: need {amount} more")
raise InsufficientFundsError(500)
File I/O and JSON
Reading and Writing Files
# writing to a file
with open("notes.txt", "w") as f:
f.write("Day 65 of 100 Days of Code")
# reading from a file
with open("notes.txt", "r") as f:
content = f.read()
print(content)
The with statement automatically closes the file when done — always use it.
File modes:
-
"r"— read -
"w"— write (overwrites existing content) -
"a"— append -
"r+"— read and write
JSON in Python
JSON is how data is exchanged between a backend and frontend, stored in config files, and consumed from APIs. Python has a built-in json module for this.
import json
# Python dict to JSON string
data = {"name": "Haris", "day": 65, "languages": ["Python", "JavaScript"]}
json_string = json.dumps(data, indent=2)
print(json_string)
# JSON string back to Python dict
parsed = json.loads(json_string)
print(parsed["name"]) # Haris
Reading and Writing JSON Files
import json
# write to JSON file
with open("data.json", "w") as f:
json.dump(data, f, indent=2)
# read from JSON file
with open("data.json", "r") as f:
loaded = json.load(f)
print(loaded["day"]) # 65
Key methods:
-
json.dumps()— dict to JSON string -
json.loads()— JSON string to dict -
json.dump()— dict to JSON file -
json.load()— JSON file to dict
Virtual Environments and pip
What is a Virtual Environment?
When you install a Python package globally, it's available everywhere on your system. That sounds convenient, but it causes problems. Different projects need different versions of the same package, which can conflict.
A virtual environment is an isolated Python environment for a specific project. Packages installed inside it don't affect anything outside it.
Creating and Using One
# create
python -m venv env
# activate (Mac/Linux)
source env/bin/activate
# activate (Windows)
env\Scripts\activate
# deactivate
deactivate
Once activated, your terminal shows the env name as a prefix. Any package you install with pip now goes into that environment only.
pip Basics
pip install django
pip install django==4.2
pip uninstall django
pip list # see installed packages
pip freeze > requirements.txt # save all dependencies
pip install -r requirements.txt # install from file
requirements.txt is how you share your project's dependencies with others. Always generate one.
Project Structure in Django
Now everything above shows up directly in a real Django project. When you run:
python -m venv env
source env/bin/activate
pip install django
django-admin startproject mysite
You get this structure:
mysite/
manage.py
mysite/
__init__.py
settings.py
urls.py
asgi.py
wsgi.py
Let's break it down:
manage.py
A command-line utility to interact with your project. You've already seen it:
python manage.py runserver
python manage.py migrate
python manage.py startapp posts
It's just a Python file — no magic.
mysite/ (inner folder)
This is your project's Python package. The __init__.py makes it a package — exactly what you learned today.
settings.py
The configuration file for your entire project. It's pure Python — dictionaries, lists, variables, imports. Things like:
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'posts', # your app
]
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}
urls.py
Maps URLs to views. This is where incoming requests get routed to the right place in your app.
wsgi.py and asgi.py
Entry points for deploying your Django app to a server. You don't touch these much in development.
Adding an App to the Project
Once you create an app with python manage.py startapp posts, your project looks like this:
mysite/
manage.py
mysite/
__init__.py
settings.py
urls.py
posts/ ← new app (a package)
__init__.py
models.py
views.py
urls.py
admin.py
apps.py
migrations/
Every app is a package; it has __init__.py. Every file inside is a module. This is Python's module system working directly inside Django.
Wrapping Up
Today's Python topics weren't as deep as functions or OOP, but they're everywhere in real projects. Virtual environments, before installing anything, exception handling in views, JSON for APIs, and modules/packages as the backbone of Django's structure, all connect.
Day 65 of 100. Python foundation done. Django starts tomorrow.
Top comments (0)