A contact form is an essential feature for any website, allowing users to communicate directly with the site owner. In a Django project, you can create a contact form using Django’s forms module, handle submissions with views, and send emails using Django’s email backend.
Creating a new app for the ContactForm in your Django blog project is a good practice, especially if you anticipate the contact functionality might grow in complexity or need to be reused across projects.
Follow these steps to create a contact form:
python manage.py startapp contact
INSTALLED_APPS
in settings.py
:# blog_project/settings.py
# Application definition
INSTALLED_APPS = [
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.sites",
"django.contrib.sitemaps",
"django.contrib.staticfiles",
"django.contrib.postgres",
# custom apps
"account",
"blog",
"core",
"contact", # Add the contact app to installed apps
]
# Email settings
EMAIL_HOST = "smtp.gmail.com"
EMAIL_PORT = 587
EMAIL_USE_TLS = True
EMAIL_HOST_USER = 'your-email@gmail.com'
EMAIL_HOST_PASSWORD = 'your-password'
# Default sender email
DEFAULT_FROM_EMAIL = "Doro's Python Life in Words"
# Contact recipient email
CONTACT_EMAIL = 'your-email@gmail.com'
contact/models.py
file:# contact/models.py
from django.db import models
from tinymce.models import HTMLField
class ContactRequest(models.Model):
first_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100, null=True, blank=True)
email = models.EmailField()
subject = models.CharField(max_length=200)
message = HTMLField()
submitted_at = models.DateTimeField(auto_now_add=True)
customer_feedback = models.BooleanField(default=False)
class Meta:
verbose_name = "Contact Request"
verbose_name_plural = "Contact Requests"
def __str__(self):
return f"Message from {self.first_name} {self.last_name} - {self.email}"
contact/forms.py
:# contact/forms.py
from django import forms
from django.conf import settings
from django.contrib.auth import get_user_model
from django.core.mail import send_mail
from contact.models import ContactRequest
UserModel = get_user_model()
class ContactRequestForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields["first_name"].widget.attrs.update(
{
"class": "form-control",
"placeholder": "Your First name",
"aria-label": "Your First name",
}
)
self.fields["last_name"].widget.attrs.update(
{
"class": "form-control",
"placeholder": "Your Last name",
"aria-label": "Your Last name",
}
)
self.fields["email"].widget.attrs.update(
{
"class": "form-control",
"placeholder": "Your Email Address",
"aria-label": "Your Email Address",
}
)
self.fields["subject"].widget.attrs.update(
{
"class": "form-control",
"placeholder": "What is your request about?",
"aria-label": "What is your request about?",
}
)
self.fields["message"].widget.attrs.update(
{
"class": "form-control",
"rows": 6,
"placeholder": "Your message",
"aria-label": "Your message",
}
)
class Meta:
model = ContactRequest
exclude = ["submitted_at", "customer_feedback"]
labels = {
"first_name": "",
"last_name": "",
"email": "",
"subject": "",
"message": "",
}
def send_email(self):
first_name = self.cleaned_data["first_name"]
last_name = self.cleaned_data.get(
"last_name", None
) # last_name is not mandatory
name = first_name if last_name is None else f"{first_name} {last_name}"
subject = self.cleaned_data["subject"]
email = self.cleaned_data["email"]
message = self.cleaned_data["message"]
create_message = f"""
Received a message from
Name: {name}
Email: {email}
with Subject: {subject}
----------------
{message}
"""
try:
send_mail(
subject=f"Contact Form submission: {settings.PROJECT_NAME}",
message=create_message,
from_email=settings.DEFAULT_FROM_EMAIL,
recipient_list=[settings.CONTACT_EMAIL.strip()],
)
except Exception as e:
print(
"--- ERROR - FAILED Contact Form submission---",
"email of sender: ",
email,
" ---> Error message: ",
e,
)
raise
contact/views.py
:# contact/views.py
from django.contrib.messages.views import SuccessMessageMixin
from django.http import HttpResponse
from django.urls import reverse_lazy
from django.views.generic import FormView
from contact.forms import ContactRequestForm
class ContactRequestFormView(SuccessMessageMixin, FormView):
form_class = ContactRequestForm
template_name = "contact_form/contact.html"
success_message = "Your message was sent."
success_url = reverse_lazy("blog:post_list")
def form_valid(self, form):
try:
form.send_email()
except Exception as e:
print("-- View error - Contact Form --", e)
return HttpResponse("An error occurred in ContactRequestFormView")
return super().form_valid(form)
contact/urls.py
:# contact/urls.py
from django.urls import path
from contact.views import ContactRequestFormView
app_name = "contact"
urlpatterns = [
path("", ContactRequestFormView.as_view(), name="contact_me"),
]
urls.py
:# blog_project/urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path("admin/", admin.site.urls),
path("contact/", include("contact.urls", namespace="contact")),
]
<!-- contact/templates/contact_form/contact.html -->
{% extends "base.html" %}
{% block title %} - Contact Me {% endblock %}
<!-- Contact Form Content - Start -->
{% block content %}
<div class="mx-4 mb-4 content-page">
<div class="col-md-12 blog-post">
<h1>Contact <span class="main-color">me</span></h1>
<p class="mb-4">
Have any questions, feedback, or just want to say hello? Fill out the form below, and I’ll
get back to you as soon as possible. I look forward to hearing from you!
</p>
<!-- Contact Form - Start -->
<form method="post">
{% csrf_token %}
<div class="row">
<div class="col-sm-6">
<div class="form-group">
{{ form.first_name }}
</div>
</div>
<div class="col-sm-6">
<div class="form-group">
{{ form.last_name }}
</div>
</div>
</div>
<div class="row">
<div class="col-sm-6">
<div class="form-group">
{{ form.email }}
</div>
</div>
</div>
<div class="row">
<div class="col-sm-9">
<div class="form-group">
{{ form.subject }}
</div>
</div>
</div>
<div class="row">
<div class="col-sm-12">
<div class="form-group">
{{ form.message }}
</div>
</div>
</div>
<button type="submit" class="btn btn-secondary" onclick="window.location.href='{% url 'blog:post_list' %}'">Cancel</button>
<button type="submit" class="btn btn-primary">Send E-mail</button>
</form>
<!-- Contact Form - End -->
</div>
</div>
{% endblock %}
<!-- Contact Form Content - End -->
By creating a dedicated app, your codebase will remain clean and organized, and you'll have flexibility for future enhancements.