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模型实例,不是字典。是的,你是对的,那么我应该重新回答这个问题吗?它可能会更清楚。另外,我也不明白为什么你的数据不包含任何内容,或者案例二和案例三之间的区别。请把表格的代码贴出来。