How I Designed a Personal Portfolio Website with Django – Part 4

We are already done with designing a portfolio website using the Django web framework. If you would like to learn how it was designed, you do well to check it out. We have also deployed it to a production server. The practical project was fun. It’s nice to have a website to call your own. However, there’s something missing.

As mentioned in the first part of this series, a portfolio website is created to show off what we are capable of doing as web developers, and to increase our chances of getting a job. Employers rate a developer’s skills and level of experience based on what he’s capable of doing.

So, when an employer goes through a developer’s portfolio, and finds him or her suitable for the job, and wants to contact him for further assessment, how can he do so if the website has no contact form? Can you now see what we failed to add to our portfolio website? Well, it’s never too late!

In this fourth part series, we will add a contact form so that employers can easily contact us for further assessment of our skills and expertise in web development, and to see if we can land that dream job we desire.

Creating a Contact form

There are different ways to create a contact form. Ours will be a simple one. Start by creating a Contact class in the models.py file.

class Contact(models.Model):
    name = models.CharField(max_length=50)
    email = models.EmailField(max_length=70)
    subject = models.CharField(max_length=200)
    message = models.TextField()
    date_submittted = models.DateTimeField(default=datetime.now)

Next is to perform migrations. Afterward, create a forms.py file to create the contact form.

from .models import Contact

class ContactForm(forms.ModelForm):
    name = forms.CharField(widget=forms.TextInput(attrs={'placeholder': 'Name'}))
    email = forms.EmailField(widget=forms.TextInput(attrs={'placeholder': 'Email'}))
    subject = forms.CharField(widget=forms.TextInput(attrs={'placeholder': 'Subject'}))
    message = forms.CharField(widget=forms.Textarea(attrs={'placeholder': 'Message'}))

    class Meta:
        model = Contact
        fields = ('name', 'email', 'subject', 'message')

The form looks similar to Django Model fields. It extends the forms.ModelForm class which has all the form features. With the forms.ModelForm class, it reduces the amount of code we have to write to create the form from scratch.

Creating Views for the Contact Form

Let us now create a view function to handle all the requests coming from the contact form.

from django.views.generic import CreateView
from django.contrib.messages.views import SuccessMessageMixin
from .forms import ContactForm
from django.contrib import messages
from django.http import HttpResponseRedirect

class ContactView(SuccessMessageMixin, CreateView):
    form_class = ContactForm
    success_url = reverse_lazy('index')
    template_name = 'contact.html'
    success_message = 'Your message was submitted successfully'

    def form_invalid(self, form):
        message.error(self.request, 'An unknown error has occurred!')
        return HttpResponseRedirect('')

The ContactView inherits from the SuccessMessageMixin and CreateView classes. It then calls the ContactForm class and specifies where the users (employers) will be redirected upon successful request. We want them to be redirected to the home page. If the form is submitted successfully, a success message will be displayed.

We use reverse_lazy to ensure that it will not execute the URL until the form is successfully submitted. The method defines what will happen if an error occurs. Then, an error message will be displayed and the user will be redirected back to the empty form.

The template_name refers to the name of the contact template we will soon create.

Let’s now create the endpoint in the urls.py file.

from .views import ContactView

urlpatterns = [
    …
    path('contact', ContactView.as_view(), name='contact'),
]

Rendering the Form as a Paragraph

To render the form as a paragraph, we have to create a template file. Create a contact.html in your templates folder.

{% load crispy_forms_tags %}

{% block content %}

<div class="col-md-8 card mb-4 mt-3">
      <h1 align="center">Contact Form</h1>
      <hr>
      <h4>Contact me for more information</h4>
      <hr>
      <br>
      <form method="post">
        {% csrf_token %}
        {{ form | crispy }}
        <button type="submit" class="btn btn-primary btn-lg">Submit</button>
     </form>
 </div>
{% endblock %}

We are using Django crispy form to give it a nice appearance. So, install django-crispy-forms and crispy-bootstrap4, and add them to the INSTALLED_APPS.

INSTALLED_APPS = [
    …
    # third-party app
    'crispy_forms',
    ‘crispy_bootstrap4',
]
CRISPY_TEMPLATE_PACK = 'bootstrap4'

Next, start the local server.

Creating the Admin Interface

To see the contact information sent by employees, we have to create an admin panel. In your admin.py file, write this:

from .models import Contact


@admin.register(Contact)
class ContactAdmin(admin.ModelAdmin):
    list_display = ('name', 'email', 'subject', 'message')

We use a Python decorator to register the Contact model in the admin. Also, we use list_display to specify what we want to appear in the admin dashboard.

Next, create a superuser account to access the admin.

The Contact model is now visible in the admin dashboard. Let’s take the role of an employer and fill out the form to see if we can see it in the admin panel.

We can see that the form is working. Let’s now update the full_view.html file to include a link to the contact form.

{% extends "base.html" %}
{% block content %}
<h1 style="color:red; text-align:center;">{{ project.title }}</h1>
<div class="row">
    <div class="col-md-8">
        <img src="{{ project.image.url }}" alt="" width="50%">
    </div>
    <div class="col-md-4">
        <h5>About the project:</h5>
        <p>{{ project.description }}</p>
        <br>
        <h5>Date Created:</h5>
        <p>{{ project.date_pub }}</p>
        <br>
        <h5>Technology used:</h5>
        <p>{{ project.technology }}</p>
        <p><a href="{% url 'contact' %}">Interesting in hiring?</a></p>
    </div>
</div>
{% endblock %}

Using the name attribute we specified in urls.py makes it easy to add a link to the contact form.

Updating the Production Server

Let us update these changes in the production server. Assuming you have the repo4 already cloned on your system, let’s commit the changes and push them to GitHub.

git add .
git commit -m ‘initial commit’
git push 

Once you are done with this stage, log in to your dashboard on PythonAnywhere.

Click on the Bash console. Then, activate the virtual environment. Next, move into the portfolio_website folder.

Run git pull to pull changes from GitHub. Using pip, install django-crispy-forms and crispy-bootstrap4. Run migration to update the database if required.

Next, go back to your dashboard and click on Web. Then reload your website.

Finally, navigate to your address to view the contact form at PythonAnywhere. Mine is shown below.

Conclusion

We have successfully created a contact form for our portfolio website and have it running on a production server. Now, employers can easily contact us if they want to hire us.

At the same time, we have learned a thing or two from this project to add to our knowledge. If you want to learn more, check out how to create a blog using Django.