Форма Django не отображается

Я пытаюсь разработать простое приложение Django, состоящее из контактной формы и страницы благодарности, но я не могу заставить фактическую форму отображаться на /contact/contact; все, что я вижу, это кнопку отправки.

enter image description here

Я вообще не использую Django 'admin'; базы данных тоже нет. Я работаю на locolhost, используя python manage.py runserver

Почему моя форма не отображается?

Нужна ли мне модель формы?

Такова структура каталога:

enter image description here

/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>

Представление form не отображается, поскольку вы не передаете его в свой шаблон. Вы можете сделать это вместо этого в представлении contact:

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

РЕДАКТИРОВАНИЕ:
Если вы получаете 'return' outside function ошибку, вы можете сделать это в вашем contact представлении.

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

Вы можете удалить условие else.

ОТРЕДАКТИРУЙТЕ 2:
Это должно быть ваше представление contact.

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')

Ваша форма Django не отображается, потому что вы не передаете форму в ваш html шаблон. вы должны передать ее.

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

попробуйте это и это должно работать:

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)

После этого вы обновили проект на Update 2/20/22

Вы забыли зарегистрировать приложение по умолчанию path для contactform в url_patterns списке.

ваш /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)

Должно быть :

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)

Попробуйте и скажите, работает ли это?

вы должны добавить path('', include('contactform.urls')) в urls.py основного проекта.

А если мы удалим все вещи, протестировав его очень просто и обновив views.py через следующий код:

/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')

Приведенный выше код работал очень эффективно, поэтому я сделал вывод, что он будет работать.

Попробуйте.

И еще одна вещь, на которой я хотел бы заострить внимание - всегда используйте следующий шаблон при создании файла шаблонов.

Appname/templates/Appname/anyfile.html

Как в вашем случае:

contactform/templates/contactform/contact.html

Вы пропустили третий шаг после templates, ну это не обязательно, но если вы это сделаете, то это будет хорошей практикой.

Вы тоже забыли / при перенаправлении в вашем views.py.

Это должно быть return HttpResponseRedirect('/thanks/') а не return HttpResponseRedirect ('/thanks')

Действие вашей формы должно указывать на

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

или лучше

<form action="{% url 'contactform:contact' %}" ...)
Вернуться на верх