The Priority
model has three values, for each of them values I'm returning an inlineform
which allows the user to set a score for each priority & then save with the Project.
This is what it currently looks like: Current view
My problem is: how can I automatically show all the priority values and allow the user to enter the score but not have to pick the Priority
. Is it possible to show it like the image below?
What I'm trying to do.
Views.py
class ProjectCreateview(LoginRequiredMixin, CreateView):
model = Project
form_class = ProjectCreationForm
login_url = "/login/"
success_url = '/'
def get_context_data(self, **kwargs):
PriorityChildFormset = inlineformset_factory(
Project, ProjectPriority, fields=('project', 'priority', 'score'), can_delete=False, extra=Priority.objects.count(),
)
data = super().get_context_data(**kwargs)
if self.request.POST:
data['priorities'] = PriorityChildFormset(self.request.POST)
else:
data['priorities'] = PriorityChildFormset()
return data
def form_valid(self, form):
context = self.get_context_data()
prioritycriteria = context["priorities"]
form.instance.creator = self.request.user
self.object = form.save()
prioritycriteria.instance = self.object
if prioritycriteria.is_valid():
prioritycriteria.save()
return HttpResponseRedirect(self.get_success_url())
Models.py
class Priority(models.Model):
title = models.CharField(verbose_name="Priority Name", max_length=250)
def __str__(self):
return self.title
class Project(models.Model):
name = models.CharField(verbose_name="Name", max_length=100)
details = models.TextField(verbose_name="Details/Description", blank=False)
creator = models.ForeignKey(User, on_delete=models.CASCADE)
class ProjectPriority(models.Model):
project = models.ForeignKey(Project, on_delete=models.CASCADE)
priority = models.ForeignKey(Priority, on_delete=models.CASCADE)
score = models.CharField(max_length=1000, choices=priority_choices)
class Meta:
verbose_name = "Priority"
verbose_name_plural = "Priorities"
Template
<table class="table table-light">
<tbody>
{{ priorities.management_form }}
{% for priority in priorities.forms %}
<tr>
{% for field in priority.visible_fields %}
<td>
{{ field.errors.as_ul }}
{{ field }}
</td>
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>
You can do this by using initial
data with your formset (see the Django documentation here).
In your views.py code you can add this line to generate some initial
values for the priority
fields:
initial = [{'priority': priority} for priority in Priority.objects.all()]
And then pass it to your formset:
data['priorities'] = PriorityChildFormset(initial=initial)
Note that initial
expects a list of the same length as the formset you created, which is defined by the extra
parameter. This works because both of these parameters have been defined using the same base queryset (i.e. Priority.objects
). If a filter were applied - it would need to apply in both places.
In addition, if you want to prevent the priority
fields from being changed by the user using the dropdown menu, you can pass a widgets
keyword argument to inlineformset_factory
to set a disabled
attribute on the <select>
element that gets generated e.g.:
from django import forms
...
widgets={'priority': forms.Select(attrs={'disabled': True})}
If you want the field to show only text - this is more difficult. The string representation of the related object that we want is buried in the field choices that are used to generate each <option>
. If you want to do this, you can dig out each field manually:
{% for priority in priorities.forms %}
<tr>
<td>
{{ priority.priority.errors.as_ul }}
{% for value, name in priority.priority.field.choices %}
{% if value == priority.priority.value %}
{{ name }}
{% endif %}
{% endfor %}
{{ priority.priority.as_hidden }}
</td>
<td>
{{ priority.score.errors.as_ul }}
{{ priority.score }}
</td>
</tr>
{% endfor %}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With