I'd like to display a row with a label, a textfield and a checkbox for each item in a database. I've managed to do this except for the checkbox that's on a new line. I wan't:
<tr>
<td>Label</td>
<td>Input</td>
<td>Checkbox</td>
<tr>
But all I get is:
<tr>
<td>Label</td>
<td>Input</td>
</tr>
<tr>
<td>Checkbox</td>
</tr>
Anyone knows how to do this?
EDIT:
To generate the form I do:
forms.py
class AttributeForm(forms.Form):
def __init__(self, *args, **kwargs):
extra = kwargs.pop('extra')
super(AttributeForm, self).__init__(*args, **kwargs)
for key in extra:
self.fields[key] = forms.CharField(label=key, initial=extra[key], required=False)
self.fields['delete_'+key] = forms.BooleanField(label='', required=False)
views.py
attribute_form = AttributeForm(extra=user)
return render_to_response('user.html', {'username': username, 'attribute_form': attribute_form})
template (user.html)
<form action="" method="post">
<table>{{ attribute_form.as_table }}</table>
<input type="submit" value="Save attributes">
</form>
EDIT 2:
My template ended up like this:
<form action="" method="post">
<table>
<tr>
{% for field in attribute_form %}
{% cycle '<th>' '' %}{% cycle field.label_tag '' %}{% cycle '</th>' '' %}
<td>{{ field }}{{ attribute_form.field.errors }}</td>
{% if not forloop.last %}{% cycle '' '</tr><tr>' %}{% endif %}
{% endfor %}
</tr>
</table>
<input type="submit" value="Save attributes">
</form>
.as_table renders each form field in seperate table row. You should render the form manually.
Related
I am making a Django application (for the first time in my life). As part of the application, a timetable needs to be implemented. Loading data (from the databse) into the timetable works fine:
Timetable view
The thing is that the data should be editable. So users need to be able to change the time or the yes/no parameter. I've created a POST handler in views.py, but when I press save, the page quickly reloads and the old values are back. What am I doing wrong?
models.py
class timeTable(models.Model):
key = models.CharField(max_length=200, unique=True, null=True)
value = models.CharField(max_length=200, null=True)
def __str__(self):
return self.key
views.py
#login_required(login_url='login')
def timetable(request):
timeTableFormset = modelformset_factory(timeTable, fields='__all__' ,extra=0)
timetableform = timeTableFormset(queryset=timeTable.objects.all())
if request.method == 'POST':
form = timeTableFormset(request.POST)
if form.is_valid():
form.save()
return render(request, 'VulnManager/timetable.html', {'timetableform': timetableform})
timetable.html:
<form method="POST">
{% csrf_token %}
<table id="tablePreview" class="table table-borderless table-hover">
<!--Table head-->
<thead>
<tr>
<th></th>
<th>Monday</th>
<th>Tuesday</th>
<th>Wednesday</th>
<th>Thursday</th>
<th>Friday</th>
<th>Saturday</th>
<th>Sunday</th>
</tr>
</thead>
<!--Table head-->
<!--Table body-->
<tbody>
<tr>
<th scope="row">Scan?</th>
{{ timetableform.management_form }}
{% for timeTableValue in timetableform.forms %}
{% if forloop.counter <= 7 %}
<td><select class="form-control" id="{{ timeTableValue.key.value }}" disabled="true">
<option>{{ timeTableValue.value.value }}</option>
<option>
{% if timeTableValue.value.value == "true" %}
false
{% elif timeTableValue.value.value == "false" %}
true
{% endif %}
</option>
</select></td>
{% if forloop.counter == 7 %}
</tr>
<tr>
<th scope="row">Time begin</th>
{% endif %}
{% elif forloop.counter >= 8 and forloop.counter <= 14 %}
<td><input type="text" id="{{ timeTableValue.key.value }}" onchange="validateHhMm(this);" value="{{ timeTableValue.value.value }}" readonly /></td>
{% if forloop.counter == 14 %}
</tr>
<tr>
<th scope="row">Time end</th>
{% endif %}
{% elif forloop.counter >= 15 and forloop.counter <= 21 %}
<td><input type="text" id="{{ timeTableValue.key.value }}" onchange="validateHhMm(this);" value="{{ timeTableValue.value.value }}" readonly /></td>
{% endif %}
{% endfor %}
</tr>
</tbody>
<!--Table body-->
</table>
<input type="button" class="btn-primary" id="edit" value="Edit" />
<input type="submit" class="btn-primary" id="save" value="Save" />
</form>
Your "form" variable has the formset in it, but you have to loop through the forms in the formset individually:
if form.is_valid():
for form_line in form:
form_line.save()
Your view is always rendering the "get" form for lack of a better term.
I think if you keep your variable names the same, it'll make things a bit simpler and consistent. So to explain this;
views.py
#login_required(login_url='login')
def timetable(request):
timeTableFormset = modelformset_factory(timeTable, fields='__all__' ,extra=0)
timetableform = timeTableFormset(queryset=timeTable.objects.all())
if request.method == 'POST':
form = timeTableFormset(request.POST) # This form just gets left in this block
if form.is_valid():
form.save()
return render(
request,
'VulnManager/timetable.html',
{'timetableform': timetableform} # The context includes the fresh new form, with no post data
)
What you should do, is just call it formset, because it makes life easier;
from django.contrib import messages
#login_required(login_url='login')
def timetable(request):
timeTableFormset = modelformset_factory(timeTable, fields='__all__' ,extra=0)
formset = timeTableFormset(queryset=timeTable.objects.all())
if request.method == 'POST':
formset = timeTableFormset(data=request.POST, queryset=timeTable.objects.all())
if formset.is_valid():
formset.save()
# Do something here to reassure the user it saved. Redirect or add a message
messages.success(request, 'Form saved.')
return render(
request,
'VulnManager/timetable.html',
{'timetableform': formset}
)
There's an article here which may provide some worthy reading for you; https://medium.com/#MicroPyramid/understanding-djangos-model-fromsets-in-detail-and-their-advanced-usage-131dfe66853d
I have an inline formset and 2 different forms within a create view of one of the forms.
All my fields in the model are blank=False and the inline formset has a minimum validation of 1.
If I try to send the form without any fields from the create view form, it displays the classic message "Please fill out this field" without rerendering the page. I want to achieve the same thing when the formset is not filled correctly. Also the same for the second form (this form is only displayed when the formset is filled based on the choice).
I am able to get the error messages re rendering the form but I'd like to do it before sending it to the server. Is it possible changing something in the model or I need to do it via js on the front?
Many thanks.
Views:
class SolicitacionReferenciaCreate(CreateView):
template_name = 'microcredito/solicitacion_form.html'
model = ContactoInfo
fields = ['nombre', 'destinoPrestamo', 'apellido']
success_url = reverse_lazy('accounts/login')
def get_context_data(self, **kwargs):
data = super(SolicitacionReferenciaCreate, self).get_context_data(**kwargs)
referencias_form_1 = ReferenciaForm()
data['referencias_form_1'] = referencias_form_1
if self.request.POST:
data['plataformas'] = IngresosFormSet(self.request.POST)
else:
data['plataformas'] = IngresosFormSet()
return data
def form_valid(self, form):
context = self.get_context_data()
plataformas = context['plataformas']
with transaction.atomic():
#ContactoInfo form
if plataformas.is_valid() and form.is_valid():
print("VALID")
self.object = form.save()
plataformas.instance = self.object
cuposPlataformas = []
for f in plataformas:
cd = f.cleaned_data
try:
score = ScorePersonas.objects.filter(idPlataforma=cd.get('idPlataforma'), numberPlataforma=cd.get('number_plataforma'),
aprobado=1)[0]
cuposPlataformas.append(score.cupo)
except:
try:
score = ScorePersonas.objects.filter(idPlataforma=cd.get('idPlataforma'), numberPlataforma=cd.get('number_plataforma'),
aprobado=0)[0]
cuposPlataformas.append(0)
except:
pass
plataformas.save()
self.object.save()
referenciaCreado1 = Referencia.objects.create_Referencia(self.object, plataformaObjeto, rt_referenciado_1, celular_referenciado_1,
nombre_referencia, apellido_referencia)
referenciaCreado1.save()
else:
#messages.error(request, "Error")
return self.render_to_response(self.get_context_data(form=form))
return render(self.request, 'microcredito/solicitacion_form.html', context)
Template:
<form action="" method="post" id="contactForm">
{% csrf_token %}
{{ form.non_field_errors }}
{{ form.source.errors }}
{{ form.source }}
{{ form.nombre.errors }}
{{ form.nombre|as_crispy_field }}
<table class="table">
{{ plataformas.management_form }}
{% for form in plataformas.forms %}
{% if forloop.first %}
<thead>
<tr>
{% for field in form.visible_fields %}
<th>{{ field.label|capfirst }}</th>
{% endfor %}
</tr>
</thead>
{% endif %}
<tr class="{% cycle row1 row2 %} formset_row">
{% for field in form.visible_fields %}
<td>
{# Include the hidden fields in the form #}
{% if forloop.first %}
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
{% endif %}
{{ field.errors.as_ul }}
{{ field }}
</td>
{% endfor %}
</tr>
{% endfor %}
</table>
<div class="form-row hide-element-form" id="ref_div_id_1">
<div class="form-group col-md-6 mb-0">
{{ referencias_form_1.numberPlataforma_referencia|as_crispy_field }}
</div>
</div>
<input onsubmit="formSent" id="form_button" type="submit" value="Save"/>
</form>
Formset:
IngresosFormSet = inlineformset_factory(ContactoInfo, IngresosPersonas,
form=IngresosForm, extra=1, min_num=1, max_num=8, validate_min=True)
I am trying to create an Inventory Management System in which i can create/add stock through a form(WTForms) and have it displayed in a table on a separate page. Currently, i am stuck on the stated error. I have looked everywhere for an answer to no avail. I am supposed to add stock through 'createGPU.html' and be directed to 'retrieveGPU.html'
Clicking the submit button in createGPU results in jinja2.exceptions.UndefinedError: 'GPUs.GPUs object' has no attribute 'GPUName'
Main Program
from flask import Flask, render_template, request, redirect, url_for
from Forms import CreateGPUForm
import shelve, GPUs
#app.route("/createGPU", methods=['GET', 'POST'])
def createGPU():
createGPUForm = CreateGPUForm(request.form)
if request.method == 'POST' and createGPUForm.validate():
gpuDict = {}
db = shelve.open('storage.db', 'c')
try:
gpuDict = db['GPU']
except:
print('Error in retrieving GPUs from storage.db.')
gpu = GPUs.GPUs(createGPUForm.GPUName.data, createGPUForm.GPUUnitPrice.data, createGPUForm.GPUStock.data,createGPUForm.GPUSales.data)
gpuDict[gpu.get_GPUNo()] = gpu
db['GPU'] = gpuDict
db.close()
return redirect(url_for('retrieveGPU'))
return render_template('createGPU.html', form=createGPUForm)
if __name__ == '__main__':
app.run()
#app.route('/retrieveGPU')
def retrieveGPU():
gpuDict = {}
db = shelve.open('storage.db', 'r')
gpuDict = db['GPU']
db.close()
gpuList = []
for key in gpuDict:
gpu = gpuDict.get(key)
gpuList.append(gpu)
return render_template('retrieveGPU.html',gpuList=gpuList, count=len(gpuList))
createGPU
{% extends "base.html" %}
{% block title %}GPU-Assist - Add Graphics Card{% endblock %}
{% block content %}
{% from "includes/_formhelper.html" import render_field %}
<h1 class="display-4">Add Graphics Card</h1>
<form method="POST" action="">
<div class="form-group">
{{ render_field(form.GPUName, class="form-control") }}
</div>
<div class="form-group">
{{ render_field(form.GPUStock, class="form-control") }}
</div>
<div class="form-group">
{{ render_field(form.GPUUnitPrice, class="form-control") }}
</div>
<div class="form-group">
{{ render_field(form.GPUSales, class="form-control") }}
</div>
<input type="submit" value="Submit" class="btn btn-primary"/>
</form>
{% endblock %}
retrieveGPU
{% extends "base.html" %}
{% block title %}GPU-Assist - View GPU-Cart{% endblock %}
{% block content %}
<h1 class="display-4">View GPU</h1>
<div>
{% if count == 0 %}
<p>No GPU in recorded in inventory.</p>
{% elif count == 1 %}
<p>There is 1 GPU recorded in the inventory.</p>
{% else %}
<p>There are {{ count }} GPUs recorded in the inventory.</p>
{% endif %}
</div> <!--End of display number of users div-->
<div>
<table class="table table-striped">
<thead>
<tr>
<th>Name</th>
<th>Stock</th>
<th>Unit Price</th>
<th>Sales</th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
{% for gpu in gpuList %}
<tr>
<td>{{ gpu.GPUName() }}</td>
<td>{{ gpu.GPUStock() }}</td>
<td>{{ gpu.GPUUnitPrice() }}</td>
<td>{{ gpu.GPUSales() }}</td>
<td>Update</td>
<td>
<form action="" method="POST">
<input type="submit" value="Delete" class="btn btn-danger">
</form>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endblock %}
GPUs.py
class GPUs:
countID = 0
def __init__(self,GPUName,GPUStock,GPUUnitPrice,GPUSales):
GPUs.countID += 1
self.__GPUName = GPUName
self.__GPUStock = GPUStock
self.__GPUUnitPrice = GPUUnitPrice
self.__GPUSales = GPUSales
self.__GPUNo=GPUs.countID
'''
One obvious limitation it has is that every time you restart the web application, the countID resets to 0.
Once the countID resets, the next newly created Users’s userID will start from 1 again and overwrite any User
that previously had __userID = 1. (Must figure out an alternative)
'''
#Getter or Accessor
def get_GPUNo(self):
return self.__GPUNo
def get_GPUName(self):
return self.__GPUName
def get_GPUStock(self):
return self.__GPUStock
def get_GPUUnitPrice(self):
return self.__GPUUnitPrice
def get_GPUSales(self):
return self.__GPUSales
#Settor or Mutator
def set_GPUNo(self, GPUNo):
self.__GPUNo = GPUNo
def set_GPUName(self, GPUName):
self.__GPUName = GPUName
def set_GPUStock(self, GPUStock):
self.__GPUStock = GPUStock
def set_GPUUnitPrice(self, GPUUnitPrice):
self.__GPUUnitPrice = GPUUnitPrice
def set_GPUSales(self, GPUSales):
self.__GPUSales = GPUSales
When Jinja2 processes
<td>{{ gpu.GPUName() }}</td>
it expects that gpu will have a callable member function named GPUName. The way you've coded things up, get_GPUName is what you want instead.
The Pythonic way were be to drop the getters and setters entirely, removed the double-underscore prefixes, and have the template go directly for the named instance variable.
<td>{{ gpu.GPUName }}</td>
Title is pretty self-explanatory the thing is when I try to submit a new entry django deletes the previous one. I think that the problem is in the delete function because when I disable it I can sumbit as many entries as I want. Here are my files:
Form.py
class FinancesForm(forms.Form):
description = forms.CharField(max_length = 50)
value = forms.DecimalField(max_digits = 10, decimal_places = 2)
Models.py
class Finances(models.Model):
date = models.DateField(auto_now = True)
description = models.CharField(max_length = 50)
value = models.DecimalField(max_digits = 10, decimal_places = 2)
total = models.DecimalField(max_digits = 10, decimal_places = 2, null = True)
Views.py
#login_required
def finances(request):
if request.method == 'POST':
form = FinancesForm(request.POST)
if form.is_valid():
newEntry = Finances()
newEntry.description = form.cleaned_data['description']
newEntry.value = form.cleaned_data['value']
if Finances.objects.all().aggregate(Sum('value')).values()[0] == None:
newEntry.total = newEntry.value;
else:
newEntry.total = Finances.objects.all().aggregate(Sum('value')).values()[0] + newEntry.value
newEntry.save()
return HttpResponseRedirect(reverse('finances'))
form = Finances()
entries = Finances.objects.all()
total = Finances.objects.all().aggregate(Sum('value')).values()[0]
return render(request, 'coop/finances.html', {'entries': entries, 'form':form, 'total': total})
#login_required
def fdelete(request):
if request.method != 'POST':
raise HTTP404
entryId = request.POST.get('entry', None)
entToDel = get_object_or_404(Finances, pk = entryId)
entToDel.delete()
return HttpResponseRedirect(reverse('finances'))
Finances.html
<tbody>
{% if entries %}
{% for entry in entries %}
{% if forloop.last %}
<tr>
<td>{{ entry.date }}</td>
<td>{{ entry.description }}</td>
{% if entry.value >= 0 %}
<td class="positive">{{ entry.value }}</td>
{% else %}
<td class="negative">{{ entry.value}}</td>
{% endif %}
<td>{{entry.total}}</td>
<td>
<form action="{% url "fdelete" %}" method="post" enctype="multipart/form-data">
{% csrf_token %}
<input type="hidden" name="entry" value="{{ entry.pk }}"/>
<input class="btn btn-primary" type="submit" value="Eliminar"/>
</td>
</tr>
{% else %}
<tr>
<td>{{ entry.date }}</td>
<td>{{ entry.description }}</td>
{% if entry.value >= 0 %}
<td class="positive">{{ entry.value }}</td>
{% else %}
<td class="negative">{{ entry.value}}</td>
{% endif %}
<td>{{entry.total}}</td>
<td></td>
</tr>
{% endif %}
{% endfor %}
{% endif %}
<tr>
<td></td>
<form class="input-group" action="{% url "finances" %}" method="post" enctype="multipart/form-data">
{% csrf_token %}
<td><input class="form-control" type="text" placeholder="Concepte" name="description"/></td>
<td><input class="form-control" type="text" placeholder="Quantitat €" name="value" onkeydown="if (event.keyCode == 13) { this.form.submit(); return false; }"/></td>
</form>
<td></td>
<td></td>
</tbody>
Thanks for yout time
You have not closed your first form
<td>
<form action="{% url "fdelete" %}" method="post" enctype="multipart/form-data">
{% csrf_token %}
<input type="hidden" name="entry" value="{{ entry.pk }}"/>
<input class="btn btn-primary" type="submit" value="Eliminar"/>
</td>
Add closing </form> tag
I'm trying to solve following issue:
I have a web page that can see only moderators.
Fields displayed on this page (after user have registered):
Username, First name+Last name, Email, Status, Relevance, etc.
I need to display table with information of all users stored in db with this fields, but two of fields have choices, so I want to make option that moderators can choose another option and after clicking on "Update" button this fields will be updated for selected user.
I can to display all choices of "status" and "relevance" fields, and after I choose new options from dropdown db is updated.
I want to display dropdowns and option stored in db should be selected.
I've tried a lot of options, I googled a lot of my time, and searched for answer or for right direction in StackOverFlow too, but didn't find anything.
Sorry for my bad english and thank you in advance for help!
Below is part of my code:
models.py:
class Profile(models.Model):
user = models.OneToOneField(User)
status = models.IntegerField(choices=((1, _("Not relevant")),
(2, _("Review")),
(3, _("Maybe relevant")),
(4, _("Relevant")),
(5, _("Leading candidate"))),
default=1)
relevance = models.IntegerField(choices=((1, _("Unread")),
(2, _("Read"))),
default=1)
forms.py:
class CViewerForm(forms.Form):
status = forms.ChoiceField(label="",
initial='',
widget=forms.Select(),
required=True)
relevance = forms.ChoiceField(widget=forms.Select(),
required=True)
views.py:
#group_required('Managers')
#render_to('reader/view.html')
def admins_view(request):
users_list = Profile.objects.select_related('user').all()
users_dict = dict()
if request.method and request.method == 'POST':
form = CViewerForm(request.POST)
if form.is_valid():
d = form.cleaned_data
# get all selected choices
status_list = request.POST.getlist('status')
relevance_list = request.POST.getlist('relevance')
# get all usernames viewed on page
users_list = request.POST.getlist('username')
# create dict from all those lists
users_dict = zip([user for user in users_list], [status for status in status_list], [rel for rel in relevance_list])
# run through dict and do bulk update
for user_dict in users_dict:
Profile.objects.filter(user__username=user_dict[0]).update(status=user_dict[1], relevance=user_dict[2])
return HttpResponseRedirect(reverse('reader:admins_view'))
else:
form = CViewerForm()
return {'users_list': users_list,
'user': request.user,
'form': form}
template:
<form class="form-horizontal" action="" method="post" name="update-form" class="well form-inline" id="view_form">
{% csrf_token %}
{{ form.non_field_errors }}
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
{% if user.is_staff %}
<div>
<table class="table table-striped table-condensed">
<thead>
<tr>
<th>{% trans 'Username' %} </th>
<th>{% trans 'E-mail' %} </th>
<th>{% trans 'Status' %} </th>
<th>{% trans 'Relevance' %} </th>
</tr>
</thead>
<tbody>
{% for user in users_list %}
<tr>
<td><input type="text" READONLY name="username" value="{{ user.user.username }}"></td>
<td>{{ user.user.first_name }}</td>
<td>{{ user.user.last_name }}</td>
<td>{{ user.user.email }}</td>
<td>{{ user.get_status_display }}</td>
<td>{{ user.get_relevance_display }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endif %}
<br>
{% endif %}
<div class="form-actions">
<input type="hidden" name="_cmd_personal">
<input type="submit" class="btn btn-info" value="{% trans 'Update' %}" name="update" class="default">
</div>
</form>
Below is a solution:
forms.py (as #Liarez wrote).
template:
<form class="form-horizontal" action="" method="post" name="update-form" class="well form-inline" id="view_form">
{% csrf_token %}
{% if user.is_staff %}
{% if users_list %}
<div>
<table class="table table-striped table-condensed">
<thead>
<tr>
<th>{% trans 'Username' %} </th>
<th>{% trans 'First name' %} </th>
<th>{% trans 'Last name' %} </th>
<th>{% trans 'E-mail' %} </th>
<th>{% trans 'CV Status' %} </th>
<th>{% trans 'CV Relevance' %} </th>
</tr>
</thead>
<tbody>
{% for user in users_list %}
<tr>
<td><input type="text" READONLY name="username" value="{{ user.user.username }}"></td>
<td>{{ user.user.first_name }}</td>
<td>{{ user.user.last_name }}</td>
<td>{{ user.user.email }}</td>
<td>
<select name="cv_status">
{% for key, status in status_choices %}
{% ifequal user.get_cv_status_display status %}
<option value="{{ user.cv_status }}" selected>{{ user.get_cv_status_display }}</option>
{% else %}
<option value="{{ key }}">{{ status }}</option>
{% endifequal %}
{% endfor %}
</select>
</td>
<td>
<select name="cv_signal">
{% for key, signal in signal_choices %}
{% ifequal user.get_cv_signal_display signal %}
<option value="{{ user.cv_signal }}" selected>{{ user.get_cv_signal_display }}</option>
{% else %}
<option value="{{ key }}">{{ signal }}</option>
{% endifequal %}
{% endfor %}
</select>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endif %}
<br>
{% endif %}
<div class="form-actions">
<input type="submit" class="btn btn-info" value="{% trans 'Update' %}" name="update" class="default">
</div>
First I recommend you as #ChrisHuang-Leaver suggested to define a new file with all the choices you need it there, like choices.py:
STATUS_CHOICES = (
(1, _("Not relevant")),
(2, _("Review")),
(3, _("Maybe relevant")),
(4, _("Relevant")),
(5, _("Leading candidate"))
)
RELEVANCE_CHOICES = (
(1, _("Unread")),
(2, _("Read"))
)
Now you need to import them on the models, so the code is easy to understand like this(models.py):
from myApp.choices import *
class Profile(models.Model):
user = models.OneToOneField(User)
status = models.IntegerField(choices=STATUS_CHOICES, default=1)
relevance = models.IntegerField(choices=RELEVANCE_CHOICES, default=1)
And you have to import the choices in the forms.py too:
forms.py:
from myApp.choices import *
class CViewerForm(forms.Form):
status = forms.ChoiceField(choices = STATUS_CHOICES, label="", initial='', widget=forms.Select(), required=True)
relevance = forms.ChoiceField(choices = RELEVANCE_CHOICES, required=True)
Anyway you have an issue with your template, because you're not using any {{form.field}}, you generate a table but there is no inputs only hidden_fields.
When the user is staff you should generate as many input fields as users you can manage. I think django form is not the best solution for your situation.
I think it will be better for you to use html form, so you can generate as many inputs using the boucle: {% for user in users_list %} and you generate input with an ID related to the user, and you can manage all of them in the view.
Better Way to Provide Choice inside a django Model :
from django.db import models
class Student(models.Model):
FRESHMAN = 'FR'
SOPHOMORE = 'SO'
JUNIOR = 'JR'
SENIOR = 'SR'
GRADUATE = 'GR'
YEAR_IN_SCHOOL_CHOICES = [
(FRESHMAN, 'Freshman'),
(SOPHOMORE, 'Sophomore'),
(JUNIOR, 'Junior'),
(SENIOR, 'Senior'),
(GRADUATE, 'Graduate'),
]
year_in_school = models.CharField(
max_length=2,
choices=YEAR_IN_SCHOOL_CHOICES,
default=FRESHMAN,
)
New method in Django 3
you can use Field.choices Enumeration Types new update in django3 like this :
from django.db import models
class Status(models.TextChoices):
UNPUBLISHED = 'UN', 'Unpublished'
PUBLISHED = 'PB', 'Published'
class Book(models.Model):
status = models.CharField(
max_length=2,
choices=Status.choices,
default=Status.UNPUBLISHED,
)
django docs
If your choices are not pre-decided or they are coming from some other source, you can generate them in your view and pass it to the form .
Example:
views.py:
def my_view(request, interview_pk):
interview = Interview.objects.get(pk=interview_pk)
all_rounds = interview.round_set.order_by('created_at')
all_round_names = [rnd.name for rnd in all_rounds]
form = forms.AddRatingForRound(all_round_names)
return render(request, 'add_rating.html', {'form': form, 'interview': interview, 'rounds': all_rounds})
forms.py
class AddRatingForRound(forms.ModelForm):
def __init__(self, round_list, *args, **kwargs):
super(AddRatingForRound, self).__init__(*args, **kwargs)
self.fields['name'] = forms.ChoiceField(choices=tuple([(name, name) for name in round_list]))
class Meta:
model = models.RatingSheet
fields = ('name', )
template:
<form method="post">
{% csrf_token %}
{% if interview %}
{{ interview }}
{% endif %}
{% if rounds %}
<hr>
{{ form.as_p }}
<input type="submit" value="Submit" />
{% else %}
<h3>No rounds found</h3>
{% endif %}
</form>