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

Python 比较两个Django模型实例列表,python,django,Python,Django,我有一个相当复杂的用例,我需要比较两个字典列表,但是列表可以处于各种不同的状态,理想情况下,我希望能够在一个列表中处理所有的字典 背景是,我有一个表单,它被呈现为一个复选框表,我试图获得表单的初始数据与更新时返回的cleaned_data之间的差异(即复选框被选中或取消选中) 因此,通常初始数据只包含复选框的数据,例如 initial_data = [<Event: Event object>, <Event: Event object>, <Event: Even

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

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

因此,通常初始数据只包含复选框的数据,例如

initial_data = [<Event: Event object>, <Event: Event object>, <Event: Event object>, <Event: Event object>]
在这种情况下,我希望从初始的_数据中获取事件,而在清理的_数据中没有。下一个用例是,如果选中复选框,则初始数据可能如下所示:

cleaned_data = [<Event: Event object>, None, <Event: Event object>, None]
initial_data = [<Event: Event object>, <Event: Event object>]
cleaned_data = [<Event: Event object>, <Event: Event object>, <Event: Event object>, <Event: Event object>]
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]]
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())
但这只适用于我的一个用例(它适用于第二个用例,但对于第一个用例,它返回Nones而不是事件)

如果能帮上忙,我将不胜感激,因为我觉得我已经很接近了,但我就是想不出来

谢谢你抽出时间

注意:这是Django应用程序的一部分

--编辑--

表单代码如下所示:

cleaned_data = [<Event: Event object>, None, <Event: Event object>, None]
initial_data = [<Event: Event object>, <Event: Event object>]
cleaned_data = [<Event: Event object>, <Event: Event object>, <Event: Event object>, <Event: Event object>]
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]]
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,并且在删除链接时需要删除它

--EDIT2--

表单本身如下所示:

cleaned_data = [<Event: Event object>, None, <Event: Event object>, None]
initial_data = [<Event: Event object>, <Event: Event object>]
cleaned_data = [<Event: Event object>, <Event: Event object>, <Event: Event object>, <Event: Event object>]
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]]
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())


我关心的只是这个问题的复选框,这里似乎没有任何字典。事件对象看起来像
{'id':1,“container\u id':1,'name':'Delivery orders','description':'orders for Delivery to customers premises','row\u count':6}
,但它可能是一个Django模型实例,不是字典。是的,你是对的,那么我应该重新回答这个问题吗?它可能会更清楚。另外,我也不明白为什么你的数据不包含任何内容,或者案例二和案例三之间的区别。请把表格的代码贴出来。