【问题标题】:Django - How to get details from many-to-many relationship in multiple select form fieldDjango - 如何从多选表单字段中的多对多关系中获取详细信息
【发布时间】:2020-05-12 18:40:44
【问题描述】:

我有 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。除此之外,我将还需要确保所选组中的每个用户只列出一次。 有没有人知道如何实现这些控件,或者至少如何显示附加信息以向用户提供相关的必要信息?

【问题讨论】:

    标签: python django django-forms many-to-many checkboxlist


    【解决方案1】:

    在选项中显示组权重的最简单方法是更改​​ 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 的名为“Group”的组将在选项列表中显示为“Group (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()
    

    只有当 weight == 100 时才会保存实例。否则,您可以将适当的错误消息传递给用户。

    我无法正确测试这个脚本,但我希望这个想法能有所帮助。我不确定您所说的“确保所选组中的每个用户只列出一次”是什么意思,所以我无法回答。好机会!

    【讨论】:

    • 非常感谢@YuriAFGomes 的回复。嗯,权重的信息来了,其实我也打算定义一个js脚本。关键是我希望有一种方法可以直接获取信息,但这种解决方法非常合适。再次感谢
    • 最新一点,我想说的是,您在模型中看到的组是用户组;对于每个事件,用户应该只出现一次(或根本不出现),这意味着如果多个组链接到该事件,则每个用户不应属于多个组。我认为最好的解决方案是在服务器端进行此测试
    猜你喜欢
    • 2013-09-04
    • 2020-02-26
    • 1970-01-01
    • 2023-03-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多