Django Template Form Render - django

My problem is not to show django form fields on template.It's silly but I just haven't found any solution.
class CommentForm(forms.ModelForm):
class Meta:
model = Comment
fields = ['name', 'email', 'text']
def __init__(self, content_type, id, *args, **kwargs):
super(CommentForm, self).__init__(*args, **kwargs)
self.content_type = content_type
self.id = id
def save(self, commit=True):
post_type = ContentType.objects.get_for_model(Post)
comment_type = ContentType.objects.get_for_model(Comment)
comment = super(CommentForm, self).save(commit=False)
if self.content_type == 'post':
comment.content_type = post_type
comment.post = self.id
else:
parent = Comment.objects.get(id=self.id)
comment.content_type = comment_type
comment.post = parent.post
comment.object_id = self.id
if commit:
comment.save()
return comment
my view:
def add_comment(request, content_type, id):
if request.method == 'POST':
data = request.POST.copy()
form = CommentForm(content_type, id, data)
if form.is_valid():
form.save()
return redirect(reverse('index'))
my add_comment template:
<form method="post" action="{% url 'add_comment' 'post' post.id %}">
{% csrf_token %}
{% if not user.is_authenticated %}
{{ form.name.label_tag }}
{{ form.name }}
{{ form.email.label_tag }}
{{ form.email }}
{% endif %}
{{ form.text.label_tag }}
{{ form.text }}<br>
<input type="submit" value="Comment" />
</form>
and I included like:
<button id="button" type="button">Add Comment</button>
<div id="post_comment_form">{% include 'articles/add_comment.html' %}</div>
</article> <!-- .post.hentry -->
why not django rendered form fields,despite of showing buttons?
EDIT:
I'm rendering form in post view.
def post(request, slug):
post = get_object_or_404(Post, slug=slug)
comments = Comment.objects.filter(post=post.id)
return render(request,
'articles/post.html',
{'post': post,
'form': CommentForm,
'comments': comments,
# 'child_comments': child_comments
}
)

You forgot to instantiate the form, change this line:
'form': CommentForm,
to this
'form': CommentForm(),

In your view, you're not sending any context variables to the template, so your 'form' object isn't available for your template to process.
For example, the following return statement will render your .html and pass along all local variables, this isn't necessarily the best option (how much do you want your template to have access to), but is simple:
from django.shortcuts import render
...
return render(request, "template.html", locals())
you can also pass a dictionary instead of all local variables. Here's the documentation for render

Related

Why does form.is_valid return false. Please advice

I have a project where one books a room online then is directed to the checkout page where you input a phone which is required in the backend. Code is as below:
forms.py
from django import forms
class AvailabilityForm(forms.Form):
check_in = forms.DateTimeField(input_formats=['%Y-%m-%dT%H:%M'], required=True)
check_out = forms.DateTimeField(input_formats=['%Y-%m-%dT%H:%M'], required=True)
class PhoneNoForm(forms.Form):
phone_no = forms.IntegerField(required=True)
views.py
class RoomDetailView(View):
def get(self, request, *args, **kwargs):
category = self.kwargs.get('category', None)
got_category = get_room_category(category)
print(category)
print(got_category)
form = AvailabilityForm()
if got_category is not None:
context = {
'category':got_category,
'form':form
}
return render(request, 'detail.html', context)
else:
return HttpResponse("Category Nyet!")
def post(self, request, *args, **kwargs):
category = self.kwargs.get('category', None)
form = AvailabilityForm(request.POST)
if form.is_valid():
data = form.cleaned_data
available_rooms = get_available_rooms(category, data['check_in'], data['check_out'] )
if available_rooms is not None:
room = available_rooms[0]
context = {
'room':room
}
return render(request, 'booking/checkout.html', context)
else:
return HttpResponse("We're out of those rooms" )
else:
return HttpResponse('Form invlid')
class CheckoutView(TemplateView):
template_name = 'booking/checkout.html'
def get_phone(request):
if request.POST:
phone_no = request.POST.get('PhoneNo', None)
print(phone_no)
cl = MpesaClient()
# Use a Safaricom phone number that you have access to, for you to be able to view the prompt
phone_number = phone_no
amount = 1
account_reference = 'reference'
transaction_desc = 'Description'
callback_url = 'https://darajambili.herokuapp.com/express-payment'
# callback_url = request.build_absolute_uri(reverse('booking:mpesa_stk_push_callback'))
response = cl.stk_push(phone_number, amount, account_reference, transaction_desc, callback_url)
return HttpResponse(response.text)
else:
return HttpResponse('This is else')
checkout.html
<div>
<form action="" method="POST">
{% csrf_token %}
<label for="Input No.">Input Phone No. :</label>
<input type="number" name="id_PhoneNo" id="PhoneNo">
<input type="submit" value="Proceed">
</form>
</div>
detail.html
<form id="booking-form" action="" method="POST">
{% csrf_token %}
<div class="input-div">
<label for="id_check_in">Check In : </label>
<input type="datetime-local" id="id_check_in" name="check_in">
</div>
<div class="input-div">
<label for="id_check_out">Check Out : </label>
<input type="datetime-local" id="id_check_out" name="check_out">
</div>
<div class="input-div">
<button type="submit">Book the Room</button>
</div>
</form>
form.is_valid returns False. I have tried using GET method but i need the phone number for more processing hence my insistence on using POST. If possible, help me fast. Where is the problem? Sorry if it's too much code.
You need to return the errors to the HTML pages to see why the error is occurring. So, if the form is not valid, send that to HTML page by:
def post(self, request, *args, **kwargs):
category = self.kwargs.get('category', None)
form = AvailabilityForm(request.POST)
if form.is_valid():
...
else:
category = self.kwargs.get('category', None)
got_category = get_room_category(category)
context = {
'category':got_category,
'form':form
}
return render(request, 'detail.html', context)
And render the errors like this(as per documentation):
{% for field in form %}
<div class="fieldWrapper">
{{ field.errors }}
{{ field.label_tag }} {{ field }}
{% if field.help_text %}
<p class="help">{{ field.help_text|safe }}</p>
{% endif %}
</div>
{% endfor %}
FYI, rather than directly subclassing the View, you should use FormView. Here is an example code on how to use:
class RoomDetailView(FormView):
form_class = AvailabilityForm
def get_context_data(self, *args, **kwargs):
context = super().get_context_data(*args, **kwargs)
category = self.kwargs.get('category', None)
got_category = get_room_category(category)
if got_category is not None:
context.update({
'category':got_category,
})
return context
else:
raise Http404("Category does not exist")
def form_valid(self, form):
data = form.cleaned_data
available_rooms = get_available_rooms(category, data['check_in'], data['check_out'] )
if available_rooms is not None: # this part should be in a separate view
room = available_rooms[0]
context = {
'room':room
}
return render(request, 'booking/checkout.html', context)
else:
return HttpResponse("We're out of those rooms" )

How to render a bound Django model form as HTML-safe?

I am trying to return a bound form that has been modified and has some arbitrary text and HTML inserted into it. I have done some research and have been able to successfully insert some arbitrary text into a bound form but I haven't found any way to render the injected HTML as HTML. It renders as plain text. How can I achieve my goal?
Here is the code:
# views.py
def multi_text(request):
if request.method == 'POST':
data = request.POST.copy()
form = MultilineForm(data=data)
if form.is_valid():
cd = form.cleaned_data
form.data['text'] = '<i>Hello hello</i>'
return render(request, 'multi_text.html', {'form': form})
else:
form = MultilineForm()
return render(request, 'multi_text.html', {'form': form})
# forms.py
class MultilineForm(ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['text'].widget.attrs.update({'class': 'form-control'}, verbose_name='Text', placeholder='Type your text here...')
self.data['text'] = '...'
class Meta:
model = Multiline
fields = ['text']
widgets = {
'text': Textarea(attrs={}),
}
# template.html
<form method="post" action="" class="form">
{% csrf_token %}
{{ form.text.as_widget }}
<span class="input-group-btn">
<input type="submit" value="Check" class="form-control btn btn-primary">
</span>
</form>

Django dropdown form submission invalid

Hey i am trying to use modelchoicefield to get a dropdown list in html. But the submission of form yields a invalid form. My code is given below.
views.py
class SubjectSelectFormView(View):
form_class = SubjectSelectForm
template_name = 'study/select_subject.html'
def get(self, request):
form = self.form_class(user=request.user)
return render(request, self.template_name, {'form':form})
def post(self, request):
form = self.form_class(request.POST)
if form.is_valid():
subject = models.Subject.objects.get(name=form['name'])
return HttpResponseRedirect('study:quiz', subject.subject_id)
else:
return HttpResponse('<h1>Failed</h1>')
forms.py
class SubjectSelectForm(forms.Form):
name = forms.ModelChoiceField(queryset=Subject.objects.all().order_by('name'), widget=forms.Select())
def __init__(self, *args, **kwargs):
user = kwargs.pop('user', None)
super(SubjectSelectForm,self).__init__(*args, **kwargs)
self.fields['name'].queryset = Subject.objects.filter(user_id=user)
html
{% extends 'basic_home_app/base.html' %}
{% block content %}
<br>
<form class="form-horizontal" action="" method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Start">
</form>
{% endblock %}
First you should always render the same template with the bound form when a posted form is found to not be valid, this way you can display errors to the user:
def post(self, request):
form = ...
if form.is_valid():
...
else:
return render(request, self.template_name, {'form':form})
Inside your template, you can display errors using either:
{{ form.errors }} # all form errors
{{ form.non_field_errors }} # form errors that aren't for one specific field, use this if you're displaying the field errors separately
or
{{ form.name.errors }} # just the errors for one specific field
Second, I assume you want to initialise your form the same way when it's posted as when it's first displayed (empty) to the user via the get() request:
def post(self, request):
form = self.form_class(request.POST, user=request.user) # note the user
Otherwise your form.__init__() method will set as queryset only Subject objects where user_id is None.

inlineformset_factory create new objects and edit objects after created

In the django docs, there's an example of using inlineformset_factory to edit already created objects
https://docs.djangoproject.com/en/dev/topics/forms/modelforms/#using-an-inline-formset-in-a-view
I changed the example to be this way:
def manage_books(request):
author = Author()
BookInlineFormSet = inlineformset_factory(Author, Book, fields=('title',))
if request.method == "POST":
formset = BookInlineFormSet(request.POST, request.FILES, instance=author)
if formset.is_valid():
formset.save()
return HttpResponseRedirect(author.get_absolute_url())
else:
formset = BookInlineFormSet(instance=author)
return render_to_response("manage_books.html", {
"formset": formset,
})
With the above, it renders only the inline model without the parent model.
To create a new object, say Author, with multiple Books associated to, using inlineformset_factory, what's the approach?
An example using the above Author Book model from django docs will be helpful. The django docs only provided example of how to edit already created object using inlineformset_factory but not to create new one
I've done that using Django Class-Based Views.
Here's my approach:
models.py
from django.db import models
class Author(models.Model):
name = models.CharField(max_length=100)
class Book(models.Model):
author = models.ForeignKey(Author)
title = models.CharField(max_length=100)
forms.py
from django.forms import ModelForm
from django.forms.models import inlineformset_factory
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Layout, Fieldset
from .models import Author, Book
class AuthorForm(ModelForm):
class Meta:
model = Author
fields = ('name', )
#property
def helper(self):
helper = FormHelper()
helper.form_tag = False # This is crucial.
helper.layout = Layout(
Fieldset('Create new author', 'name'),
)
return helper
class BookFormHelper(FormHelper):
def __init__(self, *args, **kwargs):
super(BookFormHelper, self).__init__(*args, **kwargs)
self.form_tag = False
self.layout = Layout(
Fieldset("Add author's book", 'title'),
)
BookFormset = inlineformset_factory(
Author,
Book,
fields=('title', ),
extra=2,
can_delete=False,
)
views.py
from django.views.generic import CreateView
from django.http import HttpResponseRedirect
from .forms import AuthorForm, BookFormset, BookFormHelper
from .models import Book, Author
class AuthorCreateView(CreateView):
form_class = AuthorForm
template_name = 'library/manage_books.html'
model = Author
success_url = '/'
def get(self, request, *args, **kwargs):
self.object = None
form_class = self.get_form_class()
form = self.get_form(form_class)
book_form = BookFormset()
book_formhelper = BookFormHelper()
return self.render_to_response(
self.get_context_data(form=form, book_form=book_form)
)
def post(self, request, *args, **kwargs):
self.object = None
form_class = self.get_form_class()
form = self.get_form(form_class)
book_form = BookFormset(self.request.POST)
if (form.is_valid() and book_form.is_valid()):
return self.form_valid(form, book_form)
return self.form_invalid(form, book_form)
def form_valid(self, form, book_form):
"""
Called if all forms are valid. Creates a Author instance along
with associated books and then redirects to a success page.
"""
self.object = form.save()
book_form.instance = self.object
book_form.save()
return HttpResponseRedirect(self.get_success_url())
def form_invalid(self, form, book_form):
"""
Called if whether a form is invalid. Re-renders the context
data with the data-filled forms and errors.
"""
return self.render_to_response(
self.get_context_data(form=form, book_form=book_form)
)
def get_context_data(self, **kwargs):
""" Add formset and formhelper to the context_data. """
ctx = super(AuthorCreateView, self).get_context_data(**kwargs)
book_formhelper = BookFormHelper()
if self.request.POST:
ctx['form'] = AuthorForm(self.request.POST)
ctx['book_form'] = BookFormset(self.request.POST)
ctx['book_formhelper'] = book_formhelper
else:
ctx['form'] = AuthorForm()
ctx['book_form'] = BookFormset()
ctx['book_formhelper'] = book_formhelper
return ctx
urls.py
from django.conf.urls import patterns, url
from django.views.generic import TemplateView
from library.views import AuthorCreateView
urlpatterns = patterns('',
url(r'^author/manage$', AuthorCreateView.as_view(), name='handle-books'),
url(r'^$', TemplateView.as_view(template_name='home.html'), name='home'),
)
manage_books.html
{% load crispy_forms_tags %}
<head>
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet"
href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css">
</head>
<div class='container'>
<form method='post'>
{% crispy form %}
{{ book_form.management_form }}
{{ book_form.non_form_errors }}
{% crispy book_form book_formhelper %}
<input class='btn btn-primary' type='submit' value='Save'>
</form>
<div>
Notice:
This is a simple runable example that use the inlineformset_factory
feature and Django generic Class-Based Views
I'm assumming django-crispy-forms is installed, and it's properly
configured.
Code repository is hosted at: https://bitbucket.org/slackmart/library_example
I know it's more code that the showed solutions, but start to using Django Class-Based Views is great.
I didn't read your question properly at first. You need to also render the the form for the parent model. I haven't tested this, I'm going off what I've done before and the previously linked answer, but it should work.
UPDATE
If you're using the view to both and edit, you should check for an Author ID first. If there's no ID, it'll render both forms as a new instance, whereas with an ID it'll, fill them with the existing data. Then you can check if there was a POST request.
def manage_books(request, id):
if id:
author = Author.objects.get(pk=author_id) # if this is an edit form, replace the author instance with the existing one
else:
author = Author()
author_form = AuthorModelForm(instance=author) # setup a form for the parent
BookInlineFormSet = inlineformset_factory(Author, Book, fields=('title',))
formset = BookInlineFormSet(instance=author)
if request.method == "POST":
author_form = AuthorModelForm(request.POST)
if id:
author_form = AuthorModelForm(request.POST, instance=author)
formset = BookInlineFormSet(request.POST, request.FILES)
if author_form.is_valid():
created_author = author_form.save(commit=False)
formset = BookInlineFormSet(request.POST, request.FILES, instance=created_author)
if formset.is_valid():
created_author.save()
formset.save()
return HttpResponseRedirect(created_author.get_absolute_url())
return render_to_response("manage_books.html", {
"author_form": author_form,
"formset": formset,
})
I am posting my final solutions, as per extensive assistant given by Onyeka.
Below I post the Add and Edit solutions of using inlineformset_factory of Django using the Author and Book example found in the Django Docs.
First, the Adding of Author object, with 3 extras of Book object to be appended.
Obviously, this goes into your views.py
def add_author(request):
'''This function creates a brand new Author object with related Book objects using inlineformset_factory'''
author = Author()
author_form = AuthorModelForm(instance=author) # setup a form for the parent
BookInlineFormSet = inlineformset_factory(Author, Book, fields=('title',))
if request.method == "POST":
author_form = AuthorModelForm(request.POST)
formset = BookInlineFormSet(request.POST, request.FILES)
if author_form.is_valid():
created_author = author_form.save(commit=False)
formset = BookInlineFormSet(request.POST, request.FILES, instance=created_author)
if formset.is_valid():
created_author.save()
formset.save()
return HttpResponseRedirect(created_author.get_absolute_url())
else:
author_form = AuthorModelForm(instance=author)
formset = BookInlineFormSet()
return render(request, "add_author.html", {
"author_form": author_form,
"formset": formset,
})
def edit_author(request, author_id):
'''This function edits an Author object and its related Book objects using inlineformset_factory'''
if id:
author = Author.objects.get(pk=author_id) # if this is an edit form, replace the author instance with the existing one
else:
author = Author()
author_form = AuthorModelForm(instance=author) # setup a form for the parent
BookInlineFormSet = inlineformset_factory(Author, Book, fields=('title',))
formset = BookInlineFormSet(instance=author)
if request.method == "POST":
author_form = AuthorModelForm(request.POST)
if id:
author_form = AuthorModelForm(request.POST, instance=author)
formset = BookInlineFormSet(request.POST, request.FILES)
if author_form.is_valid():
created_author = author_form.save(commit=False)
formset = BookInlineFormSet(request.POST, request.FILES, instance=created_author)
if formset.is_valid():
created_author.save()
formset.save()
return HttpResponseRedirect(created_author.get_absolute_url())
return render(request, "edit_author.html", {
"author_id": author_id, # This author_id is referenced
# in template for constructing the posting url via {% url %} tag
"author_form": author_form,
"formset": formset,
})
This part goes into your urls.py, assuming views have been imported, and urlpatterns constructed already.
...
url(r'^add/book/$', views.add_author, name='add_author'),
url(r'^edit/(?P<author_id>[\d]+)$', views.edit_author, name='edit_author'),
...
Now to the templates part. The edit Author object template (edit_author.html) looks like this (no styling applied)
<form action="{% url 'edit_book' author_id %}" method="POST" >
<!-- See above: We're using the author_id that was passed to template via views render of the edit_author(...) function -->
{% csrf_token %} <!-- You're dealing with forms. csrf_token must come -->
{{ author_form.as_p }}
{{ formset.as_p }}
<input type="submit" value="submit">
</form>
To add a brand new Author object via template (add_author.html):
<form action="." method="POST" >{% csrf_token %}
{{ author_form.as_p }}
{{ formset.as_p }}
<input type="submit" value="submit">
</form>
NOTE:
Using the action='.' might appear to be a cheap way of constructing the url, whereby the form posts the form data to the same page. With this example, using the action='.' for the edit_author.html template always got the form posted to /edit/ instead of /edit/1 or /edit/2
Constructing the url using the {% url 'edit_author' author_id %} ensures the form always posts to the right url. Failing to do use the {% url %} cost me lots of hours and trouble.
Big thanks to Onyeka.
i did exactly what you are trying :
https://github.com/yakoub/django_training/tree/master/article
you need to create a separate form using the prefix attribute .
then when you save you need to iterate over all books and associate them with the author you just created .
This is my first django inline_formset view for create a invoice with list of invoice_item_set.
In models.py there are three models
Customer
it has customer data like name, mobile_no, his_address etc..
Invoice
it has invoice data like customer_primary_key(required), delivery_address, billed_date etc..
total of the invoice item can be achieved by getting all "invoiceitem_set.all()" as items and from that sum of all add(items.item_subtotal)
InvoiceItem
it has invoiceitem data like invoice_primary_key(required), item_name, quantity, price etc..
the total is calculated before the model is saves
models.py
class Customer(models.Model):
pass
class Invoice(models.Model):
customer_id = models.ForeignKey(Customer, on_delete=models.PROTECT) # many - to - on relationship
invoice_id = models.CharField(....)
bill_note = models.TextField(....)
cash_pay = models.DecimalField(....)
upi_pay = models.DecimalField(....)
#property
def total_amount(self):
bill_total = 0
items = self.invoiceitem_set.all()
for item in items:
bill_total += item.item_subtotal
return bill_total
class InvoiceItem(models.Model):
invoice = models.ForeignKey(Invoice) # many - to - one relationship
item_name = models.CharField(....)
item_quantity = models.DecimalField(....)
item_price = models.DecimalField(....)
item_subtotal = models.DecimalField(....)
def save(self, *args, **kwargs):
self.item_subtotal = self.item_quantity * self.item_price
super(InvoiceItem, self).save(*args, **kwargs)
views.py (CreateView)
from django.db import transaction
from django.contrib import messages
from django.contrib.auth.mixins import LoginRequiredMixin
from django.http import HttpResponse, HttpResponseRedirect
class InvoiceCreateView(LoginRequiredMixin, CreateView):
model = Invoice
form_class = InvoiceForm
template_name = 'billingsite/create_invoice.html'
def get_context_data(self, **kwargs):
context = super(InvoiceCreateView, self).get_context_data(**kwargs)
context['custom_title'] = "New Invoice"
temp = dict()
temp['customer_id'] = 0
if self.request.POST:
customer_id = int(self.request.POST.get('customer_id')) or False # custom clean method.
if customer_id:
customer_object = Customer.objects.get(pk=customer_id)
invoice_object = Invoice.objects.filter(customer_id=customer_object).order_by('-created_time').first()
temp = {
"customer_id": customer_id, "mobile_no": customer_object.mobile_no,
"searched_mobile_no": customer_object.raw_mobile_no,
"customer_name": customer_object.name, "gst_no": customer_object.goods_tax_id,
"pre_bal": customer_object.pending_balance, "purchased_date": "No Bills",
"created_date": customer_object.created_date.strftime(CUSTOM_DATE_FORMAT)
}
context['formset'] = InvoiceFormSet(self.request.POST)
else:
context['formset'] = InvoiceFormSet()
context['temp'] = temp
return context
def post(self, request, *args, **kwargs):
self.object = None
context = self.get_context_data()
customer_id = int(self.request.POST.get('customer_id')) # custom clean method.
if customer_id and customer_id != 0:
customer_object = Customer.objects.get(pk=customer_id)
form_class = self.get_form_class()
form = self.get_form(form_class)
formsets = context['formset']
with transaction.atomic():
form.instance.customer_id = customer_object
form.save(commit=False)
if form.is_valid() and formsets.is_valid():
self.object = form.save()
messages.success(self.request, f'Invoice is Submitted.')
return self.form_valid(form, formsets)
else:
return self.form_invalid(form, formsets)
return reverse_lazy('InvoiceList')
return self.render_to_response(context)
def form_valid(self, form, formsets):
formsets = formsets.save(commit=False)
for formset in formsets:
formset.invoice = self.object
formset.save()
return HttpResponseRedirect(self.get_success_url(self.object.pk))
def form_invalid(self, form, formsets):
return self.render_to_response(
self.get_context_data(form=form, formset=formsets))
def get_success_url(self, pk):
return reverse_lazy('ViewInvoice', kwargs={'pk': pk})
urls.py
urlpatterns = [
path('invoice/create/', views.InvoiceCreateView.as_view(), name='AddInvoice'),
]
forms.py
class InvoiceItemForm(forms.ModelForm):
item_name = forms.CharField(label=_('Product Name'))
item_subtotal = forms.IntegerField(required=False, label=_('Sub Total'))
class Meta:
model = InvoiceItem
fields = ['item_name', 'item_quantity', 'item_price', 'item_subtotal']
exclude = ()
widgets = {
"item_quantity": widgets.NumberInput(attrs={'step': '0.25'}),
"item_price": widgets.NumberInput(attrs={'step': '0.25'})
}
def __init__(self, *args, **kwargs):
super(InvoiceItemForm, self).__init__(*args, **kwargs)
self.fields['item_name'].widget.attrs['placeholder'] = 'Enter the food name'
self.fields['item_quantity'].widget.attrs['placeholder'] = 'Pieces'
self.fields['item_price'].widget.attrs['placeholder'] = 'in ₹'
self.fields['item_subtotal'].widget.attrs['readonly'] = True
self.fields['item_subtotal'].widget.attrs['tabindex'] = -1
for field in self.fields.values():
field.widget.attrs['class'] = 'form-control'
class InlineFormSet(forms.BaseInlineFormSet):
def __init__(self, *args, **kwargs):
super(InlineFormSet, self).__init__(*args, **kwargs)
for form in self.forms:
form.empty_permitted = False
InvoiceFormSet = forms.inlineformset_factory(
Invoice, InvoiceItem, fields=('__all__'),
form=InvoiceItemForm, formset = InlineFormSet,
extra=0, min_num=1, can_delete=True
)
create_invoice.html
<fieldset>
<div class="text-dark py-4 table-responsive">
<div class="inline-formset inline-group" id="{{ formset.prefix }}-group" data-inline-type="tabular"
data-inline-formset="{
"name": "#{{ formset.prefix }}",
"options": {
"prefix": "{{ formset.prefix }}",
"addText": "Add+",
"deleteText": "<i class='bi bi-x'></i>",
"formCssClass": "dynamic-{{ formset.prefix }}",
}
}">
{% csrf_token %}
<div class="tabular inline-related">
{{ formset.management_form }}
<table id="invoice-table" class="as-table table table-xl table-hover caption">
<div class="d-block invalid-feedback">{{ formset.non_form_errors }}</div>
<caption>Add list of items.</caption>
{% for form in formset.forms %}
{% if forloop.first %}
<thead class="text-light">
<tr class="text-center">
<th scope="col">#</th>
{% for field in form.visible_fields %}
<th scope="col">{{ field.label|capfirst }}</th>
{% endfor %}
</tr>
</thead>
<tbody>
{% endif %}
<tr scope="row" class="form-row" id="{{ formset.prefix }}-{{ forloop.counter0 }}">
<th class="original">
<div class="index">{{ forloop.counter1 }}</div>
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
</th>
{% for field in form.visible_fields %}
<td class="field-{{ field.name }}">
{% if field.name != "DELETE" %}
{% if field.errors %}
{{ field|addCls:"is-invalid" }}
{% else %}
{{ field }}
{% endif %}
{% if field.errors %}
<div class="invalid-feedback">{{ field.errors }}</div>
{% endif %}
{% else %}
{{ field }}
{% endif %}
</td>
{% endfor %}
</tr>
{% endfor %}
<tr scope="row" class="form-row empty-row" id="{{ formset.prefix }}-empty">
<th class="original">
<div class="index">__prefix__</div>
{% for field in formset.empty_form.hidden_fields %}
{{ field }}
{% endfor %}
</th>
{% for field in formset.empty_form.visible_fields %}
<td class="field-{{ field.name }}">
{% if field.name != "DELETE" %}
{{ field }}
{% endif %}
</td>
{% endfor %}
</tr>
</tbody>
</table>
</div>
</div>
</div>
</fieldset>

ModelForm is not displaying entry fields

I am struggling with displaying fields in my view in Django.
The submit button appears but the fields related to models do
not.
Here is my code:
Forms.py
from django.forms import ModelForm
from blog.models import Comments
class CommentForm(ModelForm):
class Meta:
model = Comments
Models.py
class Comments(models.Model):
entries_id = models.ForeignKey(Entries)
author = models.CharField(max_length=40)
text = models.TextField()
created_on = models.DateTimeField("date published")
Views.py
class CommentListView(ListView):
model = Comments
def get_context_data(self, **kwargs):
context = super(CommentListView, self).get_context_data(**kwargs)
context['now'] = timezone.now()
return context
def add_comment(self, request, *args, **kwargs):
if request.method == 'GET':
form = CommentForm()
elif request.method == 'POST':
form = CommentForm(request.POST.copy())
if form.is_valid():
context = dict(form = form)
return render_to_response('comments_list.html', context) # etc.
The template:
{% extends 'flatpages/default.html' %}
{% block body %}
{% for Comments in object_list reversed %}
<p>{{ Comments.text }} </p></br>
<p>{{ Comments.author }}</p>
{% empty %}
<p>No comments yet</li></p>
{% endfor %}
<div="form" >
<form method = 'post' action =''> {% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit" />
</form>
</div>
{% endblock %}
I would appreciate any help. Thank you.
You are not always giving a value to form. At least, I would do that:
def get_context_data(self, **kwargs):
context = super(CommentListView, self).get_context_data(**kwargs)
context['now'] = timezone.now()
context['form'] = CommentForm()
return context