Django form without model not appearing in template when rendered - django

I have a form without an associated model, just a contact form for sending a message.
I have some experience with django forms by now, so I thought I had done everything correctly, but nothing ends up rendering when the page is viewed in a browser at all, nor are there any errors to troubleshoot.
My forms.py:
from django import forms
class ContactForm(forms.Form):
class Meta:
fields = ['full_name', 'phone', 'email', 'message']
full_name = forms.CharField(max_length=20)
phone = forms.CharField(max_length=20)
email = forms.CharField(max_length=30)
message = forms.CharField(max_length=400)
And my view that turns the form into something useful:
def contact_view(request):
full_name = request.POST.get('full_name', False)
phone = request.POST.get('phone', False)
email = request.POST.get('email', False)
message = request.POST.get('message', False)
form = ContactForm()
if request.method == 'POST':
form = ContactForm(request.POST)
if form.is_valid():
# send_emails(first_name, last_name, email)
template = loader.get_template('/myapp/mysite/main_page/templates/main_page/thankyoumsg.html')
return HttpResponse(template.render({}, request))
template = loader.get_template('/myapp/mysite/main_page/templates/main_page/contact.html')
return HttpResponse(template.render({}, request))
And my template:
<form class="leave-comment" action="." method="post">
{% csrf_token %}
{{form.as_p}}
<button type="submit">Submit</button>
</form>
But nothing is displaying, and I am unsure why. How can I troubleshoot this?

You're not including the form in the response at the last line. This should (probably) do the trick:
def contact_view(request):
...
return HttpResponse(template.render({'form': form}, request))
I also believe you need to add the fields directly to the form class, not in the Meta-class.
from django import forms
class ContactForm(forms.Form):
# Move out the fields here instead
full_name = forms.CharField(max_length=20)
phone = forms.CharField(max_length=20)
email = forms.CharField(max_length=30)
message = forms.CharField(max_length=400)
class Meta:
# This may still be there but may also be a bit redundant since
# you're choosing to show all applied fields.
fields = ['full_name', 'phone', 'email', 'message']

class Meta is only used when you have a model. If you only need to render a form without a specific model use it this way. for more information please visit official documentation:
https://docs.djangoproject.com/en/2.1/topics/forms/
forms.py
class ContactForm(forms.Form):
full_name = forms.CharField(max_length=20)
phone = forms.CharField(max_length=20)
email = forms.CharField(max_length=30)
message = forms.CharField(max_length=400)
views.py
def contact_view(request):
if request.method == 'POST':
form = ContactForm(request.POST)
if form.is_valid():
full_name = form.cleaned_data['full_name']
phone = form.cleaned_data['phone']
email = form.cleaned_data['email']
message = form.cleaned_data['message']
template = loader.get_template('/myapp/mysite/main_page/templates/main_page/thankyoumsg.html')
return HttpResponse(template.render({'form': form}, request))
template = loader.get_template('/myapp/mysite/main_page/templates/main_page/thankyoumsg.html')
return HttpResponse(template.render({'form': form}, request))
form = ContactForm()
template = loader.get_template('/myapp/mysite/main_page/templates/main_page/contact.html')
return HttpResponse(template.render({'form': form}, request))

Related

Django derive model field based on other field value

I have a CustomUser model
class Account(AbstractBaseUser):
email = models.EmailField(verbose_name = "email", max_length = 60, unique = True)
username = models.CharField(max_length = 30, unique = True)
I am using a User creation form to register new users as follows,
class RegistrationForm(UserCreationForm):
email = forms.EmailField(max_length = 60, help_text = "This will be your login.")
class Meta:
model = Account
fields = ("email", "username", "password1", "password2")
What I want to do is remove the "username" from the form fields, so
fields = ("email", "password1", "password2")
And then when the user submits the form, I wish to insert a value into the username field based on the email provided by the user, for e.g. email = abc#xyz.com, then username = abc.
How do I do this?
form.py
class UserCreateForm(UserCreationForm):
password1 = forms.CharField(widget=forms.PasswordInput(attrs={'class':'form-control'}))
password2 = forms.CharField(widget=forms.PasswordInput(attrs={'class':'form-control'}))
class Meta:
model = User
fields = ['email','first_name','last_name','password1','password2']
exclude = ['username']
widgets = {
'username':forms.TextInput(attrs={'class':'form-control'}),
# 'first_name':forms.TextInput(attrs={'class':'form-control'}),
# 'last_name':forms.TextInput(attrs={'class':'form-control'}),
'email':forms.EmailInput(attrs={'class':'form-control'}),
}
view.py
def RegisterView(request):
if request.method == 'POST':
form = UserCreateForm(request.POST)
if form.is_valid():
email = form.cleaned_data['email']
fm = form.save(commit=False)
fm.username = email.split("#")[0]
fm.save()
messages.success(request,f'{email} Successfully Registred')
form = UserCreateForm()
return render(request, 'index.html', {'form': form})
else:
form = UserCreateForm()
context = {'form': form, }
return render(request, 'index.html', context)
HTML Code
<form action="" method="post">
{% csrf_token %}
{% for i in form %}
<p>{{i.label}} {{i}}</p>
{% endfor %}
<button type="submit">Add</button>
</form>
Webpage output (register form)
admin panel

Passing hardcoded template select field value to django model in parallel with modelform fields

I have a contact model class and its respective modelForm:
# models.py
class Contact(models.Model):
name = models.CharField(max_length=32, blank=False)
email = models.EmailField()
subject = models.CharField(max_length=32, blank=False)
message = models.TextField(max_length=256, blank=False)
def __str__(self):
return self.email
# forms.py
class ContactForm(forms.modelForm):
class Meta:
model = Contact
fields = ('name', 'email', 'message',)
I have a respective views.py and template from where I am successfully submitting and saving the form data in my Contact model.
# views.py
def contact(request):
if request.method == 'POST':
form = ContactForm(request.POST)
if form.is_valid():
form.save()
email_subject = f'New contact {form.cleaned_data["email_address"]}: {form.cleaned_data["name"]}'
email_message = form.cleaned_data['message']
send_mail(email_subject, email_message, settings.CONTACT_EMAIL, settings.ADMIN_EMAIL)
return redirect('home')
form = ContactForm()
context = {'form': form}
return render(request, 'web_page/contact_page.html', context)
However, as my subject field is hardcoded and consists of many values from html select tag with name="subject" and few dozens of options, I want to post it together with my modelForm fileds and save respective value in my Contact table. Is this possible anyway? I just want to avoid bringing all this existing records in forms.py as a CHOICE of my subject field.
I am on learning curve so forgive me if I am asking something stupid on top of I know already should work...

How to save the information of a form so that it appears in the Admin Site Panel?

I am making a web page and there is a contact section in which I am looking for people to leave a message and then I contact them, I want the information entered in the form to be stored in the database so that later I can see it in the Django Admin Page.
# models.py
from django.db import models
class Contact(models.Model):
name = models.CharField(max_length = 100, verbose_name = "Nombre")
email = models.CharField(max_length = 100, verbose_name = "Email")
issue = models.CharField(max_length = 200, verbose_name = "Asunto")
text = models.TextField(verbose_name = "Mensaje")
# forms.py
from django import forms
class ContactForm(forms.Form):
name = forms.CharField(max_length = 100, label = "Nombre")
email = forms.EmailField(label = "Correo electrónico")
issue = forms.CharField(max_length = 200, label = "Asunto")
text = forms.CharField(label = "Mensaje")
# views.py
from django.views.generic import TemplateView
from contact.forms import ContactForm
from django.shortcuts import render
class Contact(TemplateView):
template_name = 'contact/contact.html'
def get(self, request):
form = ContactForm
return render(request, self.template_name, {'form': form})
def post(self, request):
form = ContactForm(request.POST)
if form.is_valid():
name = form.cleaned_data['name']
email = form.cleaned_data['email']
issue = form.cleaned_data['issue']
text = form.cleaned_data['text']
form = ContactForm()
args = {
'form': form,
'name': name,
'email': email,
'issue': issue,
'text': text,
}
return render(request, self.template_name, args)
<!-- And this is the form -->
<div class="page-section contact-page">
<div class="contact-warp">
<div class="row">
<div class="col-xl-6 p-0">
<div class="contact-text">
<span>¡Hola!</span>
<h2>Contáctame</h2>
<form class="contact-form" method="post">
{% csrf_token %}
{{ form.as_p }}
<button class="site-btn">Enviar mensaje</button>
</form>
</div>
</div>
</div>
</div>
</div>
I have made several attempts but I can not get the information to appear in the admin, (I have already registered the model in the admin).
Please, help me :(
Well, as you are not using ModelForm, then you need to save those values manually in the View. Like this:
def post(self, request):
form = ContactForm(request.POST)
if form.is_valid():
name = form.cleaned_data['name']
email = form.cleaned_data['email']
issue = form.cleaned_data['issue']
text = form.cleaned_data['text']
args = {
'form': form,
'name': name,
'email': email,
'issue': issue,
'text': text,
}
Contact.objects.create(**args) # <-- saving to DB
# rest of the code
I am not sure why you are using TemplateView, because FormView is much more appropriate for handling form. For example:
class ContactView(FormView):
form_class = ContactForm
template_name = 'contact/contact.html'
success_url= '/'
def form_valid(self, form):
name = form.cleaned_data['name']
email = form.cleaned_data['email']
issue = form.cleaned_data['issue']
text = form.cleaned_data['text']
args = {
'form': form,
'name': name,
'email': email,
'issue': issue,
'text': text,
}
Contact.objects.create(**args)
return super(ContactView).form_valid(form)
Also, if you use ModelForm, then you can simply store data like this:
class ContactForm(forms.ModelForm):
class Meta:
model = Contact
fields = "__all__"
# usage
if form.is_valid():
form.save()
# rest of the code
You need to call form.save() so your data gets saved. It's not being saved currently. Call it inside form.is_valid(): block.
Also, you don't need to pass the form values. You can access them using form.data.field_name.

Read-only field with pre-populated data in django form

I have following snippets,
# models.py
class Test(models.Model):
username = models.CharField(max_length=100)
email = models.EmailField()
# forms.py
class TestForm(forms.ModelForm):
username = forms.CharField()
email = forms.EmailField()
class Meta:
model = Test
fields = ('username', 'email')
# views.py
def test(request):
email = "example#example.com"
"""
How to pass and show the 'email' in django form/template?
"""
if request.method == 'POST':
form = TestForm(request.POST)
if form.is_valid():
form.save()
return redirect('home')
else:
form = TestForm()
return render(request, 'test.html', {"form": form})
How can I show and re-use the value of email variable (ie,example#example.com) in Django form/template as a read-only field?
try to do this way:
class TestForm(forms.ModelForm):
.....
email = forms.EmailField(initial='{{ context.email }}', disabled=True)
.....
context, passed from view, should have 'email'

modelform fails is_valid w/o setting form.errors

I'm using a modelform to display only a subset of the fields in the model. When the form is submitted it fails form.is_valid() but form.errors is empty. I'd rather not display all my code here, but below is a sample:
Model and Form
class Videofiles(models.Model):
active = models.CharField(max_length=9)
filenamebase = models.CharField(max_length=180, primary_key=True, db_column='FilenameBase')
program = models.CharField(max_length=60, db_column='Program')
displayname = models.CharField(max_length=150, db_column='DisplayName')
description = models.TextField(db_column='Description', blank=True)
tagskeywords = models.TextField(db_column='TagsKeywords', blank=True)
class Meta:
db_table = u'legacyTable'
class VideoFilesForm(ModelForm):
filenamebase = forms.CharField(max_length=30)
displayname = forms.CharField(max_length=30)
description = forms.CharField(max_length=30, required=False)
tagskeywords = forms.CharField(max_length=60, required=False)
class Meta:
model=Videofiles
fields=['filenamebase','displayname','description','tagskeywords']
View
def editClip(request, clipId):
clip = Videofiles.objects.get(filenamebase=clipId)
form = VideoFilesForm(instance=clip)
if request.method == 'POST':
if 'save' in request.POST:
if form.is_valid():
form.save()
else:
print form.errors
return render_to_response('legacyDB/edit_clip.html',locals())
Your form is unbound, because you are not passing any data to it. Calling is_valid on an unbound form will always return False, with empty errors (see the form api docs).
Your view should be something like the following:
def editClip(request, clipId):
clip = Videofiles.objects.get(filenamebase=clipId)
if request.method == 'POST':
# create bound form with input from request.POST
form = VideoFilesForm(request.POST, instance=clip)
if 'save' in request.POST:
if form.is_valid():
form.save()
else:
print form.errors
else:
# create unbound form to display in template
form = VideoFilesForm(instance=clip)
return render_to_response('legacyDB/edit_clip.html',locals())