首页 > 解决方案 > Django 联系电子邮件表单未在模板 home.html 中呈现/显示

问题描述

Django项目结构

父目录:personal_portfolio_project 主子目录(包含设置):personal_portfolio 应用:portfolio、blog

整个项目及其所有应用程序的目录结构(通过tree在控制台中打印出来):

├── personal_portfolio_project
│   ├── blog
│   │   ├── __init__.py
│   │   ├── __pycache__
│   │   │   ├── __init__.cpython-39.pyc
│   │   │   ├── admin.cpython-39.pyc
│   │   │   ├── models.cpython-39.pyc
│   │   │   ├── urls.cpython-39.pyc
│   │   │   └── views.cpython-39.pyc
│   │   ├── admin.py
│   │   ├── apps.py
│   │   ├── migrations
│   │   │   ├── 0001_initial.py
│   │   │   ├── 0002_auto_20210117_1306.py
│   │   │   ├── 0003_auto_20210117_1309.py
│   │   │   ├── 0004_auto_20210117_1432.py
│   │   │   ├── __init__.py
│   │   │   └── __pycache__
│   │   │       ├── 0001_initial.cpython-39.pyc
│   │   │       ├── 0002_auto_20210117_1306.cpython-39.pyc
│   │   │       ├── 0003_auto_20210117_1309.cpython-39.pyc
│   │   │       ├── 0004_auto_20210117_1432.cpython-39.pyc
│   │   │       └── __init__.cpython-39.pyc
│   │   ├── models.py
│   │   ├── templates
│   │   │   └── blog
│   │   │       ├── all_blogs.html
│   │   │       └── detail.html
│   │   ├── tests.py
│   │   ├── urls.py
│   │   └── views.py
│   ├── db.sqlite3
│   ├── manage.py
│   ├── media
│   │   └── portfolio
│   │       └── images
│   │           ├── DSC_0004a.jpg
│   │           └── DSC_0010a.jpg
│   ├── personal_portfolio
│   │   ├── __init__.py
│   │   ├── __pycache__
│   │   │   ├── __init__.cpython-39.pyc
│   │   │   ├── settings.cpython-39.pyc
│   │   │   ├── urls.cpython-39.pyc
│   │   │   └── wsgi.cpython-39.pyc
│   │   ├── asgi.py
│   │   ├── settings.py
│   │   ├── urls.py
│   │   └── wsgi.py
│   ├── portfolio
│   │   ├── __init__.py
│   │   ├── __pycache__
│   │   │   ├── __init__.cpython-39.pyc
│   │   │   ├── admin.cpython-39.pyc
│   │   │   ├── forms.cpython-39.pyc
│   │   │   ├── models.cpython-39.pyc
│   │   │   └── views.cpython-39.pyc
│   │   ├── admin.py
│   │   ├── apps.py
│   │   ├── forms.py
│   │   ├── migrations
│   │   │   ├── 0001_initial.py
│   │   │   ├── __init__.py
│   │   │   └── __pycache__
│   │   │       ├── 0001_initial.cpython-39.pyc
│   │   │       └── __init__.cpython-39.pyc
│   │   ├── models.py
│   │   ├── static
│   │   │   └── portfolio
│   │   │       ├── CV_Andreas_Luckert.pdf
│   │   │       ├── DSC_0010a.jpg
│   │   │       ├── Logo_Andreas_Luckert.png
│   │   │       ├── Logo_ZappyCode_DjangoCourse.png
│   │   │       ├── custom.css
│   │   │       └── main.js
│   │   ├── templates
│   │   │   └── portfolio
│   │   │       ├── about.html
│   │   │       ├── base.html
│   │   │       └── home.html
│   │   ├── tests.py
│   │   └── views.py
│   └── test_sendgrid.py

故事线

portfolio/forms.py在“投资组合”-应用程序中有一个文件,其中包含以下内容:

from django import forms

class ContactForm(forms.Form):
    from_email = forms.EmailField(required=True)
    subject = forms.CharField(required=True)
    message = forms.CharField(widget=forms.Textarea, required=True)
    # From docs: https://docs.djangoproject.com/en/3.1/topics/forms/#more-on-fields
    cc_myself = forms.BooleanField(required=False)

portfolio/views.py我有以下相关部分:

from .forms import ContactForm  # import module from same parent folder as this script
import General.Misc.general_tools as tools  # custom module to import special-print function

def contactView(request, admin_email='blaa@blaaa.com'):

    if request.method == 'GET':
        sendemail_form = ContactForm()
    else:
        sendemail_form = ContactForm(request.POST)

        if sendemail_form.is_valid():
            # * Retrieve data and set up e-mail (subject, sender, message)
            subject = sendemail_form.cleaned_data['subject']
            from_email = sendemail_form.cleaned_data['from_email']
            message = sendemail_form.cleaned_data['message']
            # From docs: https://docs.djangoproject.com/en/3.1/topics/forms/#more-on-fields
            cc_myself = sendemail_form.cleaned_data['cc_myself']

            recipients = [admin_email]
            if cc_myself:
                recipients.append(from_email)

            # * Send email
            try:
                # General Django docs: https://docs.djangoproject.com/en/3.1/topics/email/#send-mail
                # NOTE on passed list as 4th parameter: recipient-list

                ## i) How to set up an email contact form - docs: https://learndjango.com/tutorials/django-email-contact-form
                send_mail(subject,
                          message,
                          from_email,
                          recipients,
                          fail_silently=False)

            # * Exceptions * #
            # NOTE on scope: security
            except BadHeaderError:
                return HttpResponse('Invalid header found.')
            # General exception to be printed out
            except Exception as e:
                tools.except_print(f"ERROR:\n{e}")

            # Return success (if this code is reached)
            return redirect('success')

    # Send the completed (filled-in) form to the homepage - HTML - document
    return render(request, "portfolio/home.html",
                  {'sendemail_form': sendemail_form})


def successView(request):
    return HttpResponse('Success! Thank you for your message.')

这是我在最后包含的联系表格portfolio/templates/portfolio/home.html(其余的HTML工作非常好,并且在显示-webpage时通常Django不会在控制台中显示任何错误):localhost

<!-- ** E-Mail contact form **
Docs: https://learndjango.com/tutorials/django-email-contact-form-->

{% if sendemail_form %}
    <h2 class="mt-5">Contact Me</h2>
    <hr>
    <form method="post">
        {% csrf_token %}
        <!-- NOTE on ".as_p": https://docs.djangoproject.com/en/3.1/topics/forms/#form-rendering-options
        Possible attributes: as_table, as_p, as_ul -->
        {{ sendemail_form.as_p }}
        <div class="form-actions">
            <button type="submit">Send</button>
        </div>
    </form>
{% endif %}

我的内容personal_portfolio/urls.py如下:

from django.contrib import admin
from django.urls import path, include
from django.conf.urls.static import static
from django.conf import settings  # get info from the settings.py - file
from portfolio import views  # other views could also be imported (e.g. from the blog-app)

urlpatterns = [
    path("", views.home, name="home"),

    # Docs: https://learndjango.com/tutorials/django-email-contact-form
    path("contact/", views.contactView, name='contact'),
    path("success/", views.successView, name='success'),

    # Add "About me" for additonal info about the creator of the webpage
    path("about/", views.about, name="about"),

    # Standard admin page
    path('admin/', admin.site.urls),

    # NOTE on include: forwarding all /blog/ - related requests to the blog-app
    path('blog/', include('blog.urls')),
]

# * Add a static link to the MEDIA - files * #
# NOTE on processing: import certain variables defined in the settings.py of this project
# Docs: google django images (or media (folder)) etc.
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

我尝试在 中portfolio/admin.py定义的类中注册表单portfolio/models.py,但首先我不知道这是否有必要,其次由于 ,它甚至无法正常工作TypeError: 'DeclarativeFieldsMetaclass' object is not iterable,因此我从portfolio/admin.py之后删除了以下代码:

from django.contrib import admin
# !!! CAUTON: TypeError: 'DeclarativeFieldsMetaclass' object is not iterable
from .forms import ContactForm

# NOTE on registering form: doesn't work due to the following error:
# TypeError: 'DeclarativeFieldsMetaclass' object is not iterable
admin.site.register(ContactForm)

总的来说,我对如何使表单最终出现在我的portfolio/templates/portfolio/home.html. 当{% if sendemail_form %}扫描non-None要传递的表单时,这表明表单没有正确传递。


测试contactView()以检查views.py调用联系表单的函数是否已通过打印输出到达:

$ python manage.py runserver
Watching for file changes with StatReloader
Performing system checks...

System check identified no issues (0 silenced).
January 19, 2021 - 14:16:37
Django version 3.1.5, using settings 'personal_portfolio.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
[19/Jan/2021 14:16:42] "GET / HTTP/1.1" 200 31617
[19/Jan/2021 14:16:42] "GET /static/portfolio/custom.css HTTP/1.1" 304 0
[19/Jan/2021 14:16:42] "GET /static/portfolio/main.js HTTP/1.1" 304 0
[19/Jan/2021 14:16:43] "GET /static/portfolio/Logo_ZappyCode_DjangoCourse.png HTTP/1.1" 200 442438

--> 根据控制台,它没有到达,因为打印输出没有出现。

标签: pythondjangoformsdjango-viewsdjango-forms

解决方案


您需要ContactForm在呈现主页的主页视图中创建。我们需要这样做,因为表单出现在主页模板中;如果我们不在此视图中添加表单,那么模板的联系表单部分将永远无法工作,因为它接收None.

def home(request):
    ... your code here ...

    # send empty contact form to template
    sendemail_form = ContactForm()

    return render(
        request,
        "portfolio/home.html",
        {'sendemail_form': sendemail_form})

然后不contactView应该渲染模板,只是重定向。的工作contactView是获取 POST 数据并对其进行处理,然后重定向到不同的视图;它永远不应该呈现模板。

def contactView(request, admin_email='blaa@blaaa.com'):
    if request.method == 'POST':
        sendemail_form = ContactForm(request.POST)

        if sendemail_form.is_valid():
            subject = sendemail_form.cleaned_data['subject']
            from_email = sendemail_form.cleaned_data['from_email']
            message = sendemail_form.cleaned_data['message']
            cc_myself = sendemail_form.cleaned_data['cc_myself']

            recipients = [admin_email]
            if cc_myself:
                recipients.append(from_email)

            try:
                send_mail(subject,
                          message,
                          from_email,
                          recipients,
                          fail_silently=False)
            except BadHeaderError:
                return HttpResponse('Invalid header found.')
            except Exception as e:
                tools.except_print(f"ERROR:\n{e}")
                return HttpResponse('errors.')

            # Return success (if this code is reached)
            return redirect('success')

    # return to home page
    return redirect('home')

此外,将您的联系表格(位于主页模板中)指向正确的 URL(这是联系 URL,而不是主页 URL);你可以改变:

{% if sendemail_form %}
    ...
    <form method="post">
    ...
{% endif %}

{% if sendemail_form %}
    ...
    <form method="post" action="{% url 'contact' %}">
    ...
{% endif %}

推荐阅读