I have a problem using Django forms while learning Django and adapting code from a variety of online courses and examples. As a result, the code may be “messy” – but if I can get it to work the way I need, I can improve my coding style later.
I wish to display a template that contains a form. Some of the data displayed in the page rendered in the template is read from one table/model, polls_CC_Questions, and I wish to write data input in the page into a related table, polls_CC_Resp_NoFK.
The models used are:
class CC_Questions(models.Model):
q_text = models.CharField('Question text', max_length=200)
C1_Type = models.CharField('Choice 1 Type', max_length=2)
Choice1_text = models.CharField('Choice 1 text', max_length=100)
C2_Type = models.CharField('Choice 2 Type', max_length=2)
Choice2_text = models.CharField('Choice 2 text', max_length=100)
#
def __str__(self):
return self.q_text[:20]
class CC_Resp_NoFK(models.Model):
Person_ID = models.IntegerField()
Test_date = models.DateTimeField('date test taken')
Q_ID = models.IntegerField()
Response_value = models.IntegerField(default=0,
validators=[MaxValueValidator(100), MinValueValidator(-100)])
#
def __str__(self):
return self.Person_ID
Now I can display the template containing valid data when I enter the url: http://localhost:8000/polls/p2vote/4/ This is processed in urls.py
app_name = 'polls'
urlpatterns = [
…..
……
# ex: /polls/p2vote/<q_id>
path('p2vote/<int:q_id>/', p2_views.p2vote, name='p2vote'),
…..
The views.py entry that is used:
def p2vote(request,q_id):
#next line has been copied from CC_quest view to GET Question data
CC_question = get_object_or_404(CC_Questions, pk=q_id)
#
if request.method == 'POST':
form = VoteForm(request.POST)
if form.is_valid():
form.save()
return redirect('/polls/p2')
else:
formV = VoteForm()
#context = {'form' : formV}
return render(request, 'pollapp2/vote.html', {'var_name':CC_question,'form' : VoteForm()})
in forms.py
class VoteForm(forms.ModelForm):
class Meta:
model = CC_Resp_NoFK
fields = ['Person_ID', 'Test_date', 'Q_ID','Response_value']
The template launched, uses data from the polls_CC_Questions model/table to create the labels of the input field. This works fine so my displayed page http://localhost:8000/polls/p2vote/5/ Displays data from the CC_Questions table, “carried in the variable varname” what the questions and their choices are. For example, the template displays the contents of {{ var_name.q_text }} and {{ var_name.Choice1_text }} , see below
Also, the page displayed containing the ModelForm is correctly displayed with labels. The template used :
<!-- vote.html based on create.html -->
<!-- 2022-02-17
Change text on page
Extracted data from CC_Question record passed as varname
-->
{% extends "pollapp2/base.html" %}
<!-- load widget tools to give me more control over layout of form in template -->
{% load widget_tweaks %}
<!-- block Title is the name in the tab -->
{% block title %}Vote on Question{% endblock %}
{% block main %}
<div >
<div >
<div >
<div >
<h3 >Select one from two choices</h3>
</div>
<form method="POST">
{% csrf_token %}
<div >
<div >
<div >
<div >
<label for="question">Question to answer</label>
{{ var_name.q_text }}
</div>
</div>
</div>
<div >
<div >
<div >
<label for="Choice1_text ">Choice 1</label>
{{ var_name.Choice1_text }}
</div>
</div>
<div >
<div >
<label for="option2">Choice 2</label>
{{ var_name.Choice2_text }}
</div>
</div>
</div>
<!-- Attempt at Input fields follow -->
<div >
<div >
<div >
<label for="Person_id">Person ID</label>
{% render_field form.Person_ID rows="1" %}<br>
<label for="Test_date">Test Date</label>
{% render_field form.Test_date rows="1" %}<br>
<label for="Q_ID">Question ID</label>
{% render_field form.Q_ID rows="1" %} <br>
<label for="Response_value">Response value</label>
{% render_field form.Response_value rows="1" %}
</div>
</div>
</div>
<div >
<hr />
<div >
<button type="submit" >Submit</button>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
{% endblock %}
To summarise. All the above “works” in the sense a page is displayed when url : http://localhost:8000/polls/p2vote/X/ is entered in the browser and “X” is the id of the question , extracting data from the model: CC_questions. Also, on the page are input boxes created by the form, VoteForm, that allow data to be entered into table/model CC_Resp_noFK. However, what I want to do is NOT offer Q_ID as an input field in the page, but instead populate it with the value from variable {{ var_name.id }}. I can’t work out whether I need to modify the vote.html template in some way, particularly the line:
<label for="Q_ID">Question ID</label>
{% render_field form.Q_ID rows="1" %} << change this ??
or the view, somewhere around form.save() ??
def p2vote(request,q_id):
#next line has been copied from CC_quest view to get Question data
CC_question = get_object_or_404(CC_Questions, pk=q_id)
#
if request.method == 'POST':
form = VoteForm(request.POST)
if form.is_valid():
form.save() << Somewhere around here ??
return redirect('/polls/p2')
else:
formV = VoteForm()
#context = {'form' : formV}
# return render(request, 'pollapp2/vote.html', context)
# following return tries to send question record into vote.html template
return render(request, 'pollapp2/vote.html', {'var_name':CC_question,'form' : VoteForm()})
CodePudding user response:
Step 1: Delete Q_ID from VoteForm.
class VoteForm(forms.ModelForm):
class Meta:
model = CC_Resp_NoFK
fields = ['Person_ID', 'Test_date', 'Response_value']
Step 2: Add Q_ID after check if the form is valid and before save the object.
def p2vote(request,q_id):
#next line has been copied from CC_quest view to get Question data
CC_question = get_object_or_404(CC_Questions, pk=q_id)
if request.method == 'POST':
form = VoteForm(request.POST)
if form.is_valid():
item = form.save(commit=False)
item.Q_ID = q_id
item.save()
return redirect('/polls/p2')