Welcome Back to Day 2!
Yesterday, you built the foundation of your Django job application system. Today, we’re adding the crucial functionality that transforms your form from a simple interface into a complete, production-ready application.
What You’ll Build Today
By the end of Day 2, your application will:
✅ Store form submissions in the database
✅ Send automated email notifications to applicants
✅ Display success messages dynamically
✅ Feature a powerful admin panel for managing applications
✅ Include custom admin features (search, filters, ordering)
✅ Have multiple pages with responsive navigation
Let’s dive in!
Part 1: Saving Form Data to Database
Step 1: Update Your View to Store Data
Currently, your view only prints form data to the console. Let’s modify it to save data to the database.
Update job_application/views.py:
from django.shortcuts import render
from .forms import ContactForm
from .models import Form
from django.contrib import messages
def index(request):
"""
Handle form submission and save to database
"""
if request.method == 'POST':
form = ContactForm(request.POST)
if form.is_valid():
# Extract cleaned data
first_name = form.cleaned_data['first_name']
last_name = form.cleaned_data['last_name']
email = form.cleaned_data['email']
date = form.cleaned_data['date']
occupation = form.cleaned_data['occupation']
# Save to database using create()
Form.objects.create(
first_name=first_name,
last_name=last_name,
email=email,
date=date,
occupation=occupation
)
# Display success message
messages.success(request, "Form Submitted Successfully!")
return render(request, "index.html")
Understanding the Code
New Imports:
from .models import Form: Access your database modelfrom django.contrib import messages: Django’s messaging framework
Key Methods:
Form.objects.create(): Creates a new database recordmessages.success(): Displays a success message to the user
How Django ORM Works:
# Django ORM (Object-Relational Mapping)
Form.objects.create(first_name="John", last_name="Doe", ...)
# Translates to SQL:
# INSERT INTO job_application_form
# (first_name, last_name, email, date, occupation)
# VALUES ('John', 'Doe', ...)
Step 2: Understanding Django Messages Framework
Django’s messages framework allows you to display one-time notifications.
Available Message Types:
messages.success(request, "Form Submitted Successfully!") # Green
messages.info(request, "Info message") # Blue
messages.warning(request, "Warning message") # Yellow
messages.error(request, "Error message") # Red
Message Display:
Your index.html already includes the message display code:
{% if messages %}
<div class="alert alert-success">
{% for message in messages %}
{{ message }}
{% endfor %}
</div>
{% endif %}
Step 3: Test Database Storage
- Run your server:
python manage.py runserver - Submit the form at
http://127.0.0.1:8000/ - Check the database:
# Open Django shell
python manage.py shell
# Query all form submissions
from job_application.models import Form
Form.objects.all()
# Count total submissions
Form.objects.count()
# Get latest submission
Form.objects.last()
Pro Tip: You can also use DB Browser for SQLite to view your db.sqlite3 file graphically.
Understanding Form Reload vs Resubmit
⚠️ Important Distinction:
- Reload the form: Select URL and press Enter (won’t resubmit data)
- Resubmit the form: Press F5 or browser reload button (resubmits data)
Always redirect after POST to prevent duplicate submissions (we’ll cover this in production tips).
Part 2: Sending Email Notifications
Step 4: Configure Email Settings
Django includes a high-level email API that works with SMTP. We’ll use Gmail for this tutorial.
Add to the bottom of mysite/settings.py:
# Email Configuration
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_PORT = 587
EMAIL_USE_TLS = True
EMAIL_HOST_USER = 'your-email@gmail.com' # Your Gmail address
EMAIL_HOST_PASSWORD = 'your-app-password' # Gmail App Password (not regular password)
Step 5: Generate Gmail App Password
For security, Gmail requires app-specific passwords for third-party applications.
Follow these steps:
- Go to your Google Account: myaccount.google.com
- Navigate to Security (left sidebar)
- Enable 2-Step Verification (required for app passwords)
- Find “App Passwords” in the Security section
- Select app: Choose “Mail”
- Select device: Choose “Other (Custom name)”
- Enter name: “Django Job App”
- Generate: Google creates a 16-character password
- Copy this password to
EMAIL_HOST_PASSWORDin settings.py
⚠️ Security Note: Never commit your actual password to version control. Use environment variables in production:
import os
EMAIL_HOST_PASSWORD = os.environ.get('EMAIL_PASSWORD')
Step 6: Implement Email Functionality
Update job_application/views.py:
from django.shortcuts import render
from .forms import ContactForm
from .models import Form
from django.contrib import messages
from django.core.mail import EmailMessage
def index(request):
"""
Handle form submission, save to database, and send email
"""
if request.method == 'POST':
form = ContactForm(request.POST)
if form.is_valid():
# Extract cleaned data
first_name = form.cleaned_data['first_name']
last_name = form.cleaned_data['last_name']
email = form.cleaned_data['email']
date = form.cleaned_data['date']
occupation = form.cleaned_data['occupation']
# Save to database
Form.objects.create(
first_name=first_name,
last_name=last_name,
email=email,
date=date,
occupation=occupation
)
# Send confirmation email
msg_body = f"A new job application was submitted.\nThank You {first_name}!"
email_msg = EmailMessage(
"Form Submission Confirmation", # Subject
msg_body, # Body
to=[email] # Recipient
)
email_msg.send()
# Display success message
messages.success(request, "Form Submitted Successfully!")
return render(request, "index.html")
Understanding EmailMessage Class
EmailMessage is Django’s high-level email class (built on Python’s SMTP library):
EmailMessage(
subject="Email Subject",
body="Email body content",
from_email="sender@example.com", # Optional (uses EMAIL_HOST_USER)
to=["recipient@example.com"], # List of recipients
cc=["cc@example.com"], # Optional CC
bcc=["bcc@example.com"], # Optional BCC
)
Advanced Email Features:
# HTML emails
email_msg.content_subtype = "html"
email_msg.body = "<h1>Welcome!</h1><p>Thanks for applying!</p>"
# Attachments
email_msg.attach_file('/path/to/file.pdf')
# Multiple recipients
email_msg.to = ['applicant@email.com', 'hr@company.com']
Step 7: Test Email Functionality
- Fill out the form with a valid email address
- Submit the form
- Check your email inbox for the confirmation
Troubleshooting Email Issues:
# Test email in Django shell
python manage.py shell
from django.core.mail import send_mail
send_mail(
'Test Subject',
'Test message.',
'from@example.com',
['to@example.com'],
fail_silently=False,
)
Part 3: Building the Admin Interface
Django’s admin interface is one of its most powerful features – a fully functional admin panel with zero configuration!
Step 8: Create Superuser Account
python manage.py createsuperuser
Enter the following details:
- Username: admin (or your preferred username)
- Email: your-email@gmail.com
- Password: (enter secure password – it won’t display as you type)
- Password (again): (confirm password)
Example:
Username: RPM
Email address: djangorephel@gmail.com
Password: ***
Password (again): ***
Superuser created successfully.
Step 9: Register Your Model in Admin
Edit job_application/admin.py:
from django.contrib import admin
from .models import Form
# Register your models here.
admin.site.register(Form)
Step 10: Access Admin Interface
- Run server:
python manage.py runserver - Navigate to:
http://127.0.0.1:8000/admin/ - Login with your superuser credentials
- Explore the interface!
What You Can Do:
✅ View all form submissions
✅ Add new entries manually
✅ Edit existing submissions
✅ Delete records
✅ Search and filter data
Part 4: Customizing the Admin Interface
The default admin is powerful, but customization makes it production-ready.
Step 11: Create Custom Admin Class
Update job_application/admin.py:
from django.contrib import admin
from .models import Form
class FormAdmin(admin.ModelAdmin):
"""
Customized admin interface for Form model
"""
# Display these fields in the list view
list_display = ("first_name", "last_name", "email")
# Add search functionality
search_fields = ("first_name", "email")
# Add filter sidebar
list_filter = ("date", "occupation")
# Default ordering (use - for descending)
ordering = ("first_name",)
# Make specific fields read-only
readonly_fields = ("occupation",)
# Register model with custom admin class
admin.site.register(Form, FormAdmin)
Understanding Admin Customization Options
list_display
Controls which fields appear in the list view:
list_display = ("first_name", "last_name", "email", "date")
search_fields
Enables search box for specified fields:
search_fields = ("first_name", "last_name", "email")
Pro Tip: Use ^ for starts-with search:
search_fields = ("^first_name",) # Faster for large databases
list_filter
Adds filter sidebar for specified fields:
list_filter = ("date", "occupation")
ordering
Default sort order (tuple required even for single field):
ordering = ("first_name",) # Ascending A-Z
ordering = ("-date",) # Descending (newest first)
ordering = ("last_name", "first_name") # Multiple fields
readonly_fields
Makes fields non-editable:
readonly_fields = ("occupation", "date")
Additional Customization Options
class FormAdmin(admin.ModelAdmin):
list_display = ("first_name", "last_name", "email", "date")
search_fields = ("first_name", "email")
list_filter = ("date", "occupation")
ordering = ("-date",)
readonly_fields = ("occupation",)
# Items per page
list_per_page = 25
# Enable date hierarchy navigation
date_hierarchy = 'date'
# Fieldset grouping in edit form
fieldsets = (
('Personal Information', {
'fields': ('first_name', 'last_name', 'email')
}),
('Employment Details', {
'fields': ('occupation', 'date')
}),
)
# Actions dropdown customization
actions_on_top = True
actions_on_bottom = False
Step 12: Test Your Custom Admin
- Refresh the admin page
- Notice the new features:
- Column headers are now clickable for sorting
- Search box appears at the top
- Filter sidebar on the right
- Organized, professional layout
Part 5: Adding Multiple Pages and Navigation
Let’s create an “About” page and add navigation between pages.
Step 13: Create About Page
Create job_application/templates/about.html:
{% extends 'base.html' %}
{% block content %}
<h1 class="mt-4 mb-4">About Us</h1>
<div class="card">
<div class="card-body">
<h5 class="card-title">Welcome to Our Job Application Portal</h5>
<p class="card-text">
We are committed to finding the best talent for our organization.
Our streamlined application process ensures that your information
is securely stored and promptly reviewed by our HR team.
</p>
<h6 class="mt-4">What Makes Us Different?</h6>
<ul>
<li>Fast application processing</li>
<li>Immediate email confirmation</li>
<li>Secure data handling</li>
<li>Transparent hiring process</li>
</ul>
<a href="{% url 'index' %}" class="btn btn-primary mt-3">
Apply Now
</a>
</div>
</div>
{% endblock %}
Step 14: Create About View
Update job_application/views.py:
from django.shortcuts import render
from .forms import ContactForm
from .models import Form
from django.contrib import messages
from django.core.mail import EmailMessage
def index(request):
"""Handle form submission"""
if request.method == 'POST':
form = ContactForm(request.POST)
if form.is_valid():
first_name = form.cleaned_data['first_name']
last_name = form.cleaned_data['last_name']
email = form.cleaned_data['email']
date = form.cleaned_data['date']
occupation = form.cleaned_data['occupation']
Form.objects.create(
first_name=first_name,
last_name=last_name,
email=email,
date=date,
occupation=occupation
)
msg_body = f"A new job application was submitted.\nThank You {first_name}!"
email_msg = EmailMessage(
"Form Submission Confirmation",
msg_body,
to=[email]
)
email_msg.send()
messages.success(request, "Form Submitted Successfully!")
return render(request, "index.html")
def about(request):
"""Render about page"""
return render(request, "about.html")
Step 15: Add URL Route for About Page
Update job_application/urls.py:
from django.urls import path
from . import views
urlpatterns = [
path('', views.index, name='index'),
path('about/', views.about, name='about'),
]
Step 16: Add Navigation Bar
Update job_application/templates/base.html:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>Job Application Portal</title>
<link rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css">
</head>
<body>
<!-- Responsive Navigation Bar -->
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<div class="container-fluid">
<a class="navbar-brand" href="{% url 'index' %}">Job Portal</a>
<button class="navbar-toggler" type="button"
data-bs-toggle="collapse" data-bs-target="#navbarNav">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav ms-auto">
<li class="nav-item">
<a class="nav-link" href="{% url 'index' %}">Home</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{% url 'about' %}">About</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/admin/" target="_blank">Admin</a>
</li>
</ul>
</div>
</div>
</nav>
<!-- Main Content Container -->
<div class="container">
{% block content %}
{% endblock %}
</div>
<!-- Footer -->
<footer class="mt-5 py-4 bg-light text-center">
<div class="container">
<p class="mb-0">© 2025 Job Application Portal. All rights reserved.</p>
</div>
</footer>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>
Understanding Django URL Names
The {% url 'name' %} template tag generates URLs based on the name parameter in your URL patterns:
# urls.py
path('about/', views.about, name='about')
# In template
<a href="{% url 'about' %}">About</a>
# Renders as: <a href="/about/">About</a>
Benefits:
- Change URLs without updating templates
- No hardcoded paths
- Automatic URL resolution
Day 2 Complete: Your Application is Production-Ready!
Congratulations! You’ve built a complete, functional Django web application with:
✅ Database integration – Forms save to SQLite
✅ Email notifications – Automated confirmation emails
✅ User feedback – Success messages displayed dynamically
✅ Admin panel – Full CRUD operations with custom interface
✅ Multiple pages – Professional navigation structure
✅ Responsive design – Mobile-friendly Bootstrap layout
Complete Project Structure
mysite/
├── mysite/
│ ├── __init__.py
│ ├── settings.py # Email & app config
│ ├── urls.py # Project URL routing
│ ├── asgi.py
│ └── wsgi.py
├── job_application/
│ ├── migrations/
│ ├── templates/
│ │ ├── base.html # Base template with navbar
│ │ ├── index.html # Job application form
│ │ └── about.html # About page
│ ├── __init__.py
│ ├── admin.py # Custom admin interface
│ ├── apps.py
│ ├── forms.py # Form validation
│ ├── models.py # Database model
│ ├── urls.py # App URL routing
│ └── views.py # Business logic
├── db.sqlite3 # SQLite database
└── manage.py
Testing Checklist
Before considering your project complete, test these features:
- [ ] Form submission saves to database
- [ ] Email confirmation sent to applicant
- [ ] Success message displays after submission
- [ ] Admin login works with superuser credentials
- [ ] All form submissions visible in admin
- [ ] Search functionality works in admin
- [ ] Filter sidebar functions correctly
- [ ] Navigation links work on all pages
- [ ] Mobile responsive (test on different screen sizes)
- [ ] Form validation prevents empty submissions
Production Deployment Tips
Security Enhancements
- Use Environment Variables:
- Install python-decouple:
- Create
.envfile:
- Add to
.gitignore:
Database Migration
For production, migrate from SQLite to PostgreSQL:
Deployment Platforms
Popular Options:
- Heroku: Easy deployment, free tier available
- PythonAnywhere: Django-focused hosting
- DigitalOcean: Full control, affordable
- AWS Elastic Beanstalk: Scalable enterprise solution
- Railway: Modern, developer-friendly
Advanced Features to Explore Next
Now that you have a solid foundation, consider adding:
1. User Authentication
2. File Uploads
3. Django REST Framework
Build APIs for mobile apps or JavaScript frontends:
4. Celery for Background Tasks
Handle email sending asynchronously:
5. Django Allauth
Social authentication (Google, GitHub, etc.):
6. Form Validation Enhancement
7. AJAX Form Submission
Submit forms without page reload using JavaScript.
8. Unit Testing
Final Thoughts
You’ve completed a comprehensive Django tutorial covering:
Day 1:
- MVT architecture and Django setup
- Models, views, templates, and URLs
- Forms and template inheritance
Day 2:
- Database operations with Django ORM
- Email integration with Gmail
- Django admin customization
- Multi-page applications with navigation
Your application now includes:
- Professional UI with Bootstrap
- Data persistence with SQLite
- Automated email notifications
- Powerful admin interface
- Responsive navigation
Next Steps:
- Deploy your application to a hosting platform
- Add more features (file uploads, authentication)
- Build a REST API with Django REST Framework
- Learn about Django security best practices
- Contribute to open-source Django projects
Congratulations! 🎉
You’ve built a production-ready Django application from scratch. You now have the skills to:
✅ Create Django projects and apps
✅ Design database models with Django ORM
✅ Build forms with validation
✅ Send emails programmatically
✅ Customize the admin interface
✅ Create multi-page applications
✅ Deploy to production
Keep building, keep learning, and welcome to the Django community!
Happy coding! 🚀
https://github.com/REPHEL-0101/Django1
Step 1 : Clone
git clone https://github.com/REPHEL-0101/Django1.git
cd Django1
Step 2 : Create virtual env
python -m venv venv
Step 3 : Activate venv
Windows:
venv\Scripts\activate
Mac/Linux:
source venv/bin/activate
Step 4 : Install required packages
pip install django
Step 5 : Run migrations
python manage.py migrate
Step 6 : Run server
python manage.py runserver
Step 7 : Open Browser
http://127.0.0.1:8000
NOTE
If .env not there / database error comes → you must create env or sqlite auto works.
extra optional
create admin to login
python manage.py createsuperuser
Topics Covered: Django database integration, Django email functionality, Django admin customization, Django ORM tutorial, Django production deployment, Django best practices, send email Django, Django forms database, Django admin panel, Django multi-page app, Django navigation, Django Bootstrap integration, Django 2025 tutorial, Python web development
