BlueDogRanch
BlueDogRanch

Reputation: 575

Django form doesn't display

I'm trying to develop a simple Django app of a contact form and a thanks page. I'm not using Django 'admin' at all; no database, either. Django 3.2.12. I'm working on localhost using python manage.py runserver

I can't get the actual form to display at http://127.0.0.1:8000/contact/contact; all I see is the submit button from /contact/contactform/templates/contact.html:

enter image description here

Static files load OK: http://127.0.0.1:8000/static/css/bootstrap.css

The thanks.html page loads OK: http://127.0.0.1:8000/contact/thanks

This is the directory structure:

enter image description here

/contact/contact/settings.py

import os
from pathlib import Path
from dotenv import load_dotenv
load_dotenv()

DEBUG=True

BASE_DIR = Path(__file__).resolve().parent.parent

ALLOWED_HOSTS = ['127.0.0.1'] + os.getenv('REMOTE_HOST').split(',')

SECRET_KEY = os.getenv('SECRET_KEY')
EMAIL_USE_TLS = os.getenv('EMAIL_USE_TLS')
EMAIL_HOST = os.getenv('EMAIL_HOST')
EMAIL_PORT = os.getenv('EMAIL_PORT')
EMAIL_HOST_USER = os.getenv('EMAIL_HOST_USER')
EMAIL_HOST_PASSWORD = os.getenv('EMAIL_HOST_PASSWORD')


INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

    'contactform.apps.ContactformConfig',
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

ROOT_URLCONF = 'contact.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

WSGI_APPLICATION = 'contact.wsgi.application'


AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]



LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_L10N = True

USE_TZ = True


STATIC_URL = '/static/'
STATIC_ROOT = BASE_DIR / 'static/'

DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'

/contact/contact/urls.py

from django.contrib import admin
from django.urls import path

urlpatterns = [
    path('admin/', admin.site.urls),
]

from django.urls import include
urlpatterns += [
    path('contact/', include('contactform.urls')),
]

from django.conf import settings
from django.conf.urls.static import static

urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)

/contact/contactform/urls.py

from django.urls import path
from . import views

app_name = 'contactform'

urlpatterns = [
    path('thanks/', views.thanks, name='thanks'),
    path('contact/', views.contact, name='contact'),
]

/contact/contactform/views.py

import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText

from django.http import HttpResponseRedirect
from django.shortcuts import render, get_object_or_404

from contactform.forms import ContactForm
from contact.settings import EMAIL_HOST_USER, EMAIL_PORT, EMAIL_HOST_PASSWORD, EMAIL_HOST

def thanks(request):
    return render(request, 'thanks.html', {})

def contact(request):
    if request.method == 'POST':
        form = ContactForm(request.POST)
        if form.is_valid():
            form_data = form.cleaned_data
            msg = MIMEMultipart()
            msg['From'] = EMAIL_HOST_USER
            msg['To'] = EMAIL_HOST_USER
            msg['Subject'] = f'Personal site: {form_data["subject"]}'
            message = f'Name: {form_data["name"]}\n' \
                      f'Email address: {form_data["email_address"]}\n\n' \
                      f'{form_data["message"]}'
            msg.attach(MIMEText(message))
            with smtplib.SMTP(EMAIL_HOST, EMAIL_PORT) as server:
                server.ehlo()
                server.starttls()
                server.login(EMAIL_HOST_USER, EMAIL_HOST_PASSWORD)
                server.sendmail(EMAIL_HOST_USER, EMAIL_HOST_USER, msg.as_string())
            return HttpResponseRedirect('/thanks')
    else:
        form = ContactForm()

    return render(request, 'contact.html')

/contact/contactform/models.py

from django.urls import reverse

/contact/contactform/apps.py

from django.apps import AppConfig

class ContactformConfig(AppConfig):
    default_auto_field = 'django.db.models.BigAutoField'
    name = 'contactform'

/contact/contactform/forms.py

from django import forms

class ContactForm(forms.Form):
    name = forms.CharField(required=True, widget=forms.TextInput(
        attrs={'class': 'form-control', 'maxlength': '100'}
    ))
    email_address = forms.EmailField(required=True, widget=forms.EmailInput(
        attrs={'class': 'form-control', 'maxlength': '100'}
    ))
    subject = forms.CharField(required=True, widget=forms.TextInput(
        attrs={'class': 'form-control', 'maxlength': '100'}
    ))
    message = forms.CharField(required=True, widget=forms.Textarea(
        attrs={'class': 'form-control', 'maxlength': '1000', 'rows': 8}
    ))

/contact/contactform/templates/contact.html

<h2>Form</h2>
    <form action="/contact/" method="post">
        {% csrf_token %}
        {{ form.as_p }}
        <button type="submit">Send</button>
    </form>

Update 2/20/22

This views.py now works and shows the contact form; the remaining issuse is when the form is completed, the redirect to the thanks page throws a 404.

import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText

from django.shortcuts import redirect
from django.shortcuts import render, get_object_or_404

from contactform.forms import ContactForm
from contact.settings import EMAIL_HOST_USER, EMAIL_PORT, EMAIL_HOST_PASSWORD, EMAIL_HOST

def thanks(request):
    return render(request, 'thanks.html', {})

def contact(request):
    if request.method == 'POST':
        form = ContactForm(request.POST)
        if form.is_valid():
            form_data = form.cleaned_data
            msg = MIMEMultipart()
            msg['From'] = EMAIL_HOST_USER
            msg['To'] = EMAIL_HOST_USER
            msg['Subject'] = f'Site Email'
            message = f'Name: {form_data["name"]}\n' \
                      f'Email address: {form_data["email_address"]}\n\n' \
                      f'{form_data["message"]}'
            msg.attach(MIMEText(message))
            with smtplib.SMTP(EMAIL_HOST, EMAIL_PORT) as server:
                server.ehlo()
                server.starttls()
                server.login(EMAIL_HOST_USER, EMAIL_HOST_PASSWORD)
                server.sendmail(EMAIL_HOST_USER, EMAIL_HOST_USER, msg.as_string())
            return redirect('contactform:thanks')
    else:
        form = ContactForm()

    return render(request, 'contact.html', { "form": form })

Error screen:

enter image description here

Upvotes: 5

Views: 3308

Answers (4)

Razenstein
Razenstein

Reputation: 3717

Your form action needs to point to

<form action="/contact/contact/"....

or better

<form action="{% url 'contactform:contact' %}" ...)

Upvotes: 1

Sunderam Dubey
Sunderam Dubey

Reputation: 8837

After, you updated the project on Update 2/20/22

You forgot to register the default path for contactform app in url_patterns list.

your /contact/contact/urls.py

from django.contrib import admin
from django.urls import path

urlpatterns = [
    path('admin/', admin.site.urls),
]

from django.urls import include
urlpatterns += [
    path('contact/', include('contactform.urls')),
]

from django.conf import settings
from django.conf.urls.static import static

urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)

It should be :

from django.contrib import admin
from django.urls import path,include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('contactform.urls'))
]

from django.urls import include
urlpatterns += [
    path('contact/', include('contactform.urls')),
]

from django.conf import settings
from django.conf.urls.static import static

urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)

Try this and tell if it works?

you have to add path('', include('contactform.urls')) in urls.py of main project.

As, if we remove all things by testing it very simply and updating views.py through following code:

/contact/contactform/views.py

from contactform.forms import ContactForm
from django.http import HttpResponseRedirect
from django.shortcuts import render

def contact(request):
    if request.method == 'POST':
        form = ContactForm(request.POST)
        if form.is_valid():
            form_data = form.cleaned_data

            return HttpResponseRedirect('/thanks/')
    else:
        form = ContactForm()
    return render(request, 'contact.html', {'form': form})


def thanks(req):
    return render(req, 'thanks.html')

The above code worked very efficiently.So, i drew the conclusion that it will work.

Try it.

And one thing, i would like to focus on is, always use the following pattern while making templates file.

Appname/templates/Appname/anyfile.html

Like in your case:

contactform/templates/contactform/contact.html

You have missed the third step after templates, well its not necessary, but if you do it is a good practice.

You have forgot / too while redirecting in your views.py.

It should be return HttpResponseRedirect('/thanks/') rather than return HttpResponseRedirect ('/thanks')

Also, remove the action attribute of form so that it can redirect through HttpResponseRedirect () method.

Upvotes: 1

boyenec
boyenec

Reputation: 1617

Your Django form doesn't display because you are not passing the form to your html template. you have to pass it.

return render(request, 'contact.html','form':form)

try this and it should be work:

def contact(request):
    form = ContactForm()
    if request.method == 'POST':
        form = ContactForm(request.POST)
        if form.is_valid():
            form_data = form.cleaned_data
            msg = MIMEMultipart()
            msg['From'] = EMAIL_HOST_USER
            msg['To'] = EMAIL_HOST_USER
            msg['Subject'] = f'Personal site {form_data["subject"]}'
            message = f'Name: {form_data["name"]}\n' \
                  f'Email address: {form_data["email_address"]}\n\n' \
                  f'{form_data["message"]}'
            msg.attach(MIMEText(message))
            with smtplib.SMTP(EMAIL_HOST, EMAIL_PORT) as server:
                server.ehlo()
                server.starttls()
                server.login(EMAIL_HOST_USER, EMAIL_HOST_PASSWORD)
                server.sendmail(EMAIL_HOST_USER, EMAIL_HOST_USER, msg.as_string())
            return HttpResponseRedirect('/thanks')
        else:
            return HttpResponseRedirect('contactform:contact')

    return render(request, 'contact.html','form':form)

forms.py

from django import forms
from .models import *

class ContactForm(forms.ModelForm):
      class Meta:
        model = your_model_name
        fields = '__all__' 

Upvotes: -2

onapte
onapte

Reputation: 267

The form does not display as you are not passing it into your template. You can do this instead in the contact view:

return render(request, 'contact.html', {
     'form': form
})

EDIT:
If you are getting 'return' outside function error, you can do this in your contact view.

def contact(request):
    form = ContactForm() # Before if condition

You can remove the else condition.

EDIT 2:
This should be your contact view.

def contact(request):
    form = ContactForm()
    if request.method == 'POST':
        form = ContactForm(request.POST)
        if form.is_valid():
            form_data = form.cleaned_data
            msg = MIMEMultipart()
            msg['From'] = EMAIL_HOST_USER
            msg['To'] = EMAIL_HOST_USER
            msg['Subject'] = f'Personal site {form_data["subject"]}'
            message = f'Name: {form_data["name"]}\n' \
                  f'Email address: {form_data["email_address"]}\n\n' \
                  f'{form_data["message"]}'
            msg.attach(MIMEText(message))
            with smtplib.SMTP(EMAIL_HOST, EMAIL_PORT) as server:
                server.ehlo()
                server.starttls()
                server.login(EMAIL_HOST_USER, EMAIL_HOST_PASSWORD)
                server.sendmail(EMAIL_HOST_USER, EMAIL_HOST_USER, msg.as_string())
            return HttpResponseRedirect('/thanks')
        else:
            return HttpResponseRedirect(reverse('contactform:contact'))

    return render(request, 'contact.html', {
        'form': form
    })

Upvotes: 4

Related Questions