多选择字段保存

时间:2013-07-23 17:22:02

标签: jquery django django-views

我正在开发一个带有模型的RSVP应用程序:

class Guest(models.Model):
    profile = models.ForeignKey(UserProfile)
    ...
    invite_list = models.ManyToManyField(GuestList, through='RSVP')


class RSVP(models.Model):
    guestlist = models.ForeignKey(GuestList)
    guest = models.ForeignKey(Guest, related_name='rsvp')
    ...

我正在尝试创建一个多选字段表单,允许用户选择要添加到RSVP的来宾。我使用jQuery将多个选项增强到2个框,其中所选项目将出现在右侧的框中。

在forms.py中并使用crispy_forms

class RSVPSelectGuestForm(forms.Form):    
    guests = forms.MultipleChoiceField()

    def __init__(self, *args, **kwargs):
        profile = kwargs.pop('profile', None)
        guestlist_pk = kwargs.pop('guestlist_pk', None)
        super(RSVPSelectGuestForm, self).__init__(*args, **kwargs)
        self.helper = FormHelper()
        self.helper.layout = Layout(
            Field('guests', 
                id='guests-multiple-select',
            ),
            FormActions(
                Submit('submit', 'Save'),
            ),       
        )
        self.fields['guests'].choices = [(obj.id, str(obj)) for obj in Guest.objects.filter(profile=profile)]
        self.fields['guests'].initial = [(obj.guest_id) for obj in RSVP.objects.filter(guestlist_id=guestlist_pk)]

我能够使用上面的代码正确渲染选择多元素。我将kwargs从视图传递到get_form_kwargs上的表单。

现在问题是一种以有效的方式从RSVP表添加/删除访客的方法。我犹豫不决,因为我无法在下面提出的解决方案之间作出决定:

  1. 每次在UI中发生事件时处理表单 - 当用户选择访客时,会立即将其添加到表中;当用户取消选择用户时,将从RSVP表中删除该guest虚拟机。如果访客数量增加,这可能会导致大量的SQL读/写。

  2. 在提交表单之前不保存任何内容 - 从发布数据中,我将创建所选选项的字典,将其与表单加载时的状态进行比较,任何新行都是从表中删除添加和丢失的行。这只需要2次SQL操作。

  3. 有人可以帮忙建议一个好的解决方法或更好的想法来解决这个问题吗?在我的建议中是否有任何我可能忽略的问题?

1 个答案:

答案 0 :(得分:0)

我现在决定使用解决方案2,因为它更容易实现。向表单添加以下方法,保存表单时,创建并比较2组数据。 [python方式很简单]然后我们可以使用1个查询进行批量创建或批量删除。我尚未在更大的数据集上测试此代码。

def add_guests(self, added):
    RSVP.objects.bulk_create([
        RSVP(guestlist_id=self.guestlist_pk, guest_id=guest_pk) 
        for guest_pk in added
    ])

def remove_guests(self, removed):
    RSVP.objects.filter(guestlist_id=self.guestlist_pk, 
        guest_id__in=removed).delete()

def save(self):
    data = self.cleaned_data

    initial_data = set(self.initial_data)
    new_data = set([int(i) for i in data['guests']])

    added = new_data - initial_data
    removed = initial_data - new_data

    if added:
        self.add_guests(added)
    if removed:
        self.remove_guests(removed)

有任何改进建议吗?