我有2个与M2M关系链接的模型,我想构建一个表单,该表单不仅可以管理链接,还可以添加对所选值的控件。这在管理模板之外进行。
我设法定义了用于管理链接的表格,但是我无法考虑其他信息来定义有效性控制。
这是我的模特:
class EventGroup(models.Model):
company = models.ForeignKey(
Company, on_delete=models.CASCADE, verbose_name="société"
)
users = models.ManyToManyField(UserComp, verbose_name="utilisateurs", blank=True)
group_name = models.CharField("nom", max_length=100)
weight = models.IntegerField("poids", default=0)
class Event(models.Model):
company = models.ForeignKey(
Company, on_delete=models.CASCADE, verbose_name="société"
)
groups = models.ManyToManyField(EventGroup, verbose_name="groupes", blank=True)
rules = [("MAJ", "Majorité"), ("PROP", "Proportionnelle")]
event_name = models.CharField("nom", max_length=200)
event_date = models.DateField("date de l'événement")
slug = models.SlugField()
current = models.BooleanField("en cours", default=False)
quorum = models.IntegerField(default=33)
rule = models.CharField(
"mode de scrutin", max_length=5, choices=rules, default="MAJ"
)
表格:
class EventDetail(forms.ModelForm):
groups = forms.ModelMultipleChoiceField(
label = "Liste des groupes",
queryset = EventGroup.objects.none(),
widget = forms.CheckboxSelectMultiple,
required = False
)
class Meta:
model = Event
fields = ['event_name', 'event_date', 'quorum', 'rule', 'groups']
视图:
def event_detail(request, evt_id=0):
if evt_id > 0:
current_event = Event.objects.get(id=evt_id)
event_form = EventDetail(request.POST or None, instance=current_event)
else:
event_form = EventDetail(request.POST or None)
company = Company.get_company(request.session['comp_slug'])
event_form.fields['groups'].queryset = EventGroup.objects.\
filter(company=company).\
order_by('group_name')
if request.method == 'POST':
if event_form.is_valid():
event_form.save()
return render(request, "polls/event_detail.html", locals())
这可以毫无问题地添加或删除专用于所选事件或新事件的组,但是我需要添加组的权重信息并控制所选组的总权重正好为100。此外,我还将需要确保所选组中的每个用户仅列出一次。是否有人对如何实现这些控件有任何线索,或者至少如何显示其他信息以向用户提供相关的必要信息?
非常感谢您的建议。
在选项内显示组权重的最简单方法是更改EventGroup的__str__
方法。它看起来像这样:
class EventGroup(models.Model):
company = models.ForeignKey(
Company, on_delete=models.CASCADE, verbose_name="société"
)
users = models.ManyToManyField(UserComp, verbose_name="utilisateurs", blank=True)
group_name = models.CharField("nom", max_length=100)
weight = models.IntegerField("poids", default=0)
def __str__(self):
return f"{self.group_name} ({self.weight})"
因此权重为75的名为“组”的组将在选项列表上显示为“组(75)”]
如果要动态显示所选选项的总权重,则需要一些JavaScript。您需要一个单击任何选项并以某种方式找到该选项的权重时触发的功能。按照__str__
解决方案,它看起来可能像这样:
var current_weight = 0
document.querySelector('#id_groups').addEventListener('click', function(e) {
if (e.target && e.target.nodeName == "LI") {
option = e.target
weight = option.textContent.split('(')
weight = parseInt(weight[-1][:-1])
if (option.checked) {
current_weight -= weight
} else {
current_weight += weight
}
document.getElementById('current_weight').textContent = current_weight
submit_button = document.getElementById('submit')
if (current_weight == 100) {
submit_button.disabled = false
} else {
submit_button.disabled = true
}
})
这必须在您的polls / event_detail.html模板导入的.js文件中。
该脚本的作用是监听django CheckboxMultiple小部件的任何LI元素的点击,并通过一些简单的字符串操作获得其权重。该字符串将类似于“组名称(23)”。如果选中该选项,则脚本将从current_weight中减去其权重(用户已取消选择该选项)。否则,它将增加重量。更新后的总和将以动态方式显示在您要添加到id ='current_weight'的event_detail.html模板中的元素上。然后,通过启用或禁用其提交按钮,此变量可以控制是否可以提交表单。
如果要在服务器端验证此权重== 100的限制,则可以在views.py中执行类似的操作:
if request.method == 'POST':
total_weight = 0
try:
post = request.POST
for item in post['groups']:
weight = EventGroup.objects.get(pk=item).weight
total_weight += weight
except:
pass
if event_form.is_valid() and total_weight == 100:
event_form.save()
仅当权重== 100时,才会保存此实例。否则,您可以将适当的错误消息传递给用户。
我无法正确测试此脚本,但我希望这个想法有所帮助。我不确定“确保所选组中的每个用户仅列出一次”是什么意思,所以我无法回答。机会很大!