Reputation: 575
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
:
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:
/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:
Upvotes: 5
Views: 3308
Reputation: 3717
Your form action needs to point to
<form action="/contact/contact/"....
or better
<form action="{% url 'contactform:contact' %}" ...)
Upvotes: 1
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
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
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