Doro's Python Life in Words Journal

Creating a Contact Form in Django


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.

Why create a new app?

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. 

Adding a ContactForm to the project

Follow these steps to create a contact form:

    • Create the App: Run the following command in your project directory:
python manage.py startapp contact
    • Register the App: Add the app to your 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'
    • Define the Contact Form Model: Create your model in the 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}"
    • Create a Form: In 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
    • Set Up Views: In 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)
    • Configure URLs: In 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"),
]
    • Include this in your project's 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")),
]
    • Create the Template:
<!-- 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.


Designed by BootstrapMade and modified by DoriDoro