Estoy tratando de desarrollar una aplicación Django simple de un formulario de contacto y una página de agradecimiento. No estoy usando Django 'admin' en absoluto; ninguna base de datos, tampoco. Django 3.2.12. Estoy trabajando en localhost usando python manage.py runserver
No puedo mostrar el formulario real en http://127.0.0.1:8000/contact/contact
; todo lo que veo es el botón de envío de /contact/contactform/templates/contact.html
:
Los archivos estáticos se cargan correctamente: http://127.0.0.1:8000/static/css/bootstrap.css
La página thanks.html se carga correctamente: http://127.0.0.1:8000/contact/thanks
Esta es la estructura del directorio:
/contacto/contacto/configuraciones.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'
/contacto/contacto/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)
/contacto/formulario/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'), ]
/contacto/formulario de contacto/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')
/contacto/formulario/modelos.py
from django.urls import reverse
/contacto/formulario de contacto/apps.py
from django.apps import AppConfig class ContactformConfig(AppConfig): default_auto_field = 'django.db.models.BigAutoField' name = 'contactform'
/contacto/formulario/formularios.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} ))
/contacto/formulario/plantillas/contacto.html
<h2>Form</h2> <form action="/contact/" method="post"> {% csrf_token %} {{ form.as_p }} <button type="submit">Send</button> </form>
Actualización 20/02/22
Este views.py ahora funciona y muestra el formulario de contacto; el problema restante es cuando se completa el formulario, la redirección a la página de agradecimiento arroja un 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 })
Pantalla de errores:
El form
no se muestra porque no lo está pasando a su plantilla. En su lugar, puede hacer esto en la vista de contact
:
return render(request, 'contact.html', { 'form': form })
EDITAR:
Si obtiene un error 'return' outside function
, puede hacerlo en su vista de contact
.
def contact(request): form = ContactForm() # Before if condition
Puede eliminar la condición else
.
EDITAR 2:
Esta debería ser su vista 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', { 'form': form })
Su formulario de Django no se muestra porque no está pasando el formulario a su plantilla html. tienes que pasarlo.
return render(request, 'contact.html','form':form)
prueba esto y debería funcionar:
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)
formularios.py
from django import forms from .models import * class ContactForm(forms.ModelForm): class Meta: model = your_model_name fields = '__all__'
Después, actualizó el proyecto en la Actualización 20/02/22
Olvidó registrar la path
predeterminada para la aplicación de url_patterns
contactform
su /contacto/contacto/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)
Debería ser :
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)
Prueba esto y dime si funciona?
debe agregar path('', include('contactform.urls'))
en urls.py
del proyecto principal.
Como, si eliminamos todas las cosas probándolo de manera muy simple y actualizando views.py
a través del siguiente código:
/contacto/formulario de contacto/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')
El código anterior funcionó de manera muy eficiente. Entonces, llegué a la conclusión de que funcionará.
Intentalo.
Y una cosa en la que me gustaría centrarme es usar siempre el siguiente patrón al crear archivos de plantillas.
Nombre de la aplicación/plantillas/Nombre de la aplicación/cualquier archivo.html
Como en tu caso:
formulario de contacto/plantillas/formulario de contacto/contacto.html
Te has perdido el tercer paso después de templates
, bueno, no es necesario, pero si lo haces, es una buena práctica.
Ha olvidado /
también al redirigir en sus views.py
.
Debería return HttpResponseRedirect('/thanks/')
en lugar de return HttpResponseRedirect ('/thanks')
Además, elimine el atributo de action
del formulario para que pueda redirigir a través del método HttpResponseRedirect ().
Su acción de formulario debe apuntar a
<form action="/contact/contact/"....
o mejor
<form action="{% url 'contactform:contact' %}" ...)