比较Django模型实例的两个列表

2024-09-30 08:15:07 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个相当复杂的用例,我需要比较两个字典列表,但是列表可以处于各种不同的状态,理想情况下,我希望能够在一个列表中处理所有这些字典。在

这样做的背景是,我有一个表单,它被呈现为一个复选框表,并且我试图获得表单的初始数据与更新时返回的cleaned_data之间的差异(即选中或取消选中复选框)。在

所以通常初始数据只包含选中复选框的数据,例如

initial_data = [<Event: Event object>, <Event: Event object>, <Event: Event object>, <Event: Event object>]

当一个事件对象包含一个id和一个名称时,它们可以是同一个事件。在

如果未选中复选框,则cleaned_data可能如下所示:

^{pr2}$

在本例中,我希望从初始的_数据中获取事件,其中清理后的_数据中没有事件。下一个用例是,如果选中复选框,则初始数据可能如下所示:

initial_data = [<Event: Event object>, <Event: Event object>]

然后像这样清理数据:

cleaned_data = [<Event: Event object>, <Event: Event object>, <Event: Event object>, <Event: Event object>]

在本例中,我希望从已清理的\u数据中返回与初始的\u数据不匹配的事件。在

还有第三部分使事情复杂化,如果有一行没有选中的复选框,它也会显示为无。所以我还需要处理这个问题:

initial_data = [<Event: Event object>, <Event: Event object>]

cleaned_data = [<Event: Event object>, None, <Event: Event object>, <Event: Event object>]

因此,为了澄清我要做的是,如果在cleaned_data中有对应的None,则返回初始事件数据;如果与初始数据的cleaned_data存在差异,则返回事件和None,并删除None。在

我想做点什么:

events = [[x for x in cleaned_data if x not in initial_data], [x for x in initial_data if x not in cleaned_data]]

但这只适用于我的一个用例(它适用于第二个用例,但对于第一个用例,它返回none而不是事件)。在

如果你能帮上忙,我会非常感激的,因为我觉得我已经很接近了,但我就是想不起来了!在

谢谢你的时间。在

另外,这是Django应用程序的一部分

--编辑--

表单代码如下:

class ActivityGroupInline(InlineFormSet):
    model = models.ActivityGroup
    fields = ['events',]
    can_delete = False
    extra = 0

    @property
    def widgets(self):
        return {
            'events': widgets.CheckboxSelectMultiple(),
        }

    def get_factory_kwargs(self):
        kwargs = super().get_factory_kwargs()

        kwargs.update({
            'widgets': self.widgets,
        })

        return kwargs


class ActivityGroupEventLink(NamedFormsetsMixin, UpdateWithInlinesView):
    model = models.Container
    fields = []
    template_name = 'main/link_activitygroupsevents.html'
    success_url = reverse_lazy('dashboard')
    inlines = [ActivityGroupInline,]
    inlines_names = ['activitygroup_inline',]

    def get_object(self, queryset=None):
        return models.Container.objects.first()

    def get_context_data(self, *args, **kwargs):
        context = super().get_context_data(*args, **kwargs)

        context['breadcrumbs'] = [
            {'name': 'Home', 'url': reverse_lazy('dashboard')},
            {'name': 'Link Activities to Events', 'is_active': True}
        ]

        all_events = models.Event.objects.filter(
            container=context['object'],
        ).all()

        context['events'] = { event.id: event for event in all_events }

        for form in context['activitygroup_inline'].forms:
            activitygroup_kcs = set(form.instance.key_characteristics.all())

            potential_event_ids = set()

            for event in all_events:
                event_kcs = set(event.key_characteristics.all())

                if event_kcs & activitygroup_kcs:
                    potential_event_ids.add(event.id)

            form.fields['events'].choices = models.Event.objects.filter(
                id__in=list(potential_event_ids)
            ).order_by('id').values_list('id', 'name')

        return context

    def forms_valid(self, form, inlines):
        self.object = form.save()

        for formset in inlines:
            instances = formset.save(commit=False)

            for inst in instances:
                initial_events = [] # This is code I added to work with the solution that I am now trying
                new_events = []
                for f in formset:
                    initial_events.append(f.initial['events']) # This is code I added to work with the solution that I am now trying
                    new_events.append(f.cleaned_data['events'].first())

                flat_initial = [item for sublist in initial_events for item in sublist] # This is code I added to work with the solution that I am now trying

                try:
                    event = next(event for event in new_events if event is not None) # This is what I was previously doing to find the relevant event but it only works if there is one column in the table.
                except StopIteration:
                    raise ValidationError('There must be at least one Activity Group linked to an event.')

                activityevent = inst.activityevent_set.filter(activity_group_id=inst.id, event_id=event.id)

                if activityevent.exists():
                    activityevent.delete()
                else:
                    new_activityevent = models.ActivityEvent.objects.create(
                        activity_group=inst,
                        event=event,
                    )
                    new_activityevent.save()

                inst.save()

        return HttpResponseRedirect(self.get_success_url())

它还使用django外部形式。基本上,activity_group和event都有一个中间模型activityevent,因此当创建一个新链接时,还需要创建一个新的activityevent,并且需要在删除链接时删除它。在

--编辑2--

表单本身如下所示:

Matrix form

我只关心这个问题的复选框


Tags: 数据inselfeventidfordataobject

热门问题