5

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

Sunderam Dubey
8,84812 gold badges26 silver badges43 bronze badges
asked Feb 16, 2022 at 16:51
3
  • 1
    return render(request, 'contact.html') You aren't passing form in the template context. Commented Feb 16, 2022 at 16:57
  • Thanks, how would I do that? Commented Feb 16, 2022 at 17:15
  • @BlueDogRanch tell me one thing it works without giving default url that is path('', include ("contactform.urls"))? or giving after this? Commented Feb 26, 2022 at 16:39

4 Answers 4

4

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
 })
answered Feb 16, 2022 at 17:02
Sign up to request clarification or add additional context in comments.

30 Comments

Thanks, that goes in views.py and replaces return render(request, 'contact.html')? I get SyntaxError: 'return' outside function
I guess this is a problem with indentation.
Instead of using form = ContactForm() inside the else condition, you can use this statement before the if condition in your contact view.
@BlueDogRanch, your problem is very simple. You just need to replace this line of your view: return render(request, 'contact.html') with return render(request, 'contact.html', { "form": form }). That's it. This answer is correct (which is why I don't give this as my own), although the essential point can be lost in a bunch of extraneous detail - which I assume came from your subsequent complaints, which I guess are due to changing the indentation in some strange way. You just need to add that dictionary as a third argument to your return statement - nothing else.
@BlueDogRanch, maybe the answer is in the answer already given by @onapte. Try return HttpResponseRedirect(reverse('contactform:thanks')), or building on the comment by @AMG, return redirect('contactform:thanks').
|
1
+50

Your form action needs to point to

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

or better

<form action="{% url 'contactform:contact' %}" ...)
answered Feb 25, 2022 at 19:24

Comments

1

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.

answered Feb 25, 2022 at 16:29

4 Comments

Thanks! This works. I do see a warning in debug "WARNINGS: ?: (urls.W005) URL namespace 'contactform' isn't unique. You may not be able to reverse all URLs in this namespace" and I don't know how serious that is.
And what is the difference between the two urlpatterns = blocks in /contact/contact/urls.py ?
It includes the urls of contactform by default, i.e, any path which you type in url if it is blank then its next urls will be decided through that particular app, like in your case it is contactform. But, what is the issue you are facing right now?
I get the error warning in debug "WARNINGS: ?: (urls.W005) URL namespace 'contactform' isn't unique. You may not be able to reverse all URLs in this namespace" Razenstein's answer works with the original views.
-2

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__' 
answered Feb 16, 2022 at 17:56

11 Comments

"ValueError at /contact/contact/ The view contactform.views.contact didn't return an HttpResponse object. It returned None instead."
I edited my questing. try now. you was using return HttpResponseRedirect(reverse('contactform:contact')) but it should be return HttpResponseRedirect('contactform:contact')
Still doesn't show the form
are you getting any error ? can you access the contact page now?
No errors; I only see the "Send" button, not the form fields.
|

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.