def __init__(self, *args, **kwargs): # super(BaseEditForm, self).__init__(*args, **kwargs) super().__init__(*args, **kwargs) self.issued_relation = None self.received_relation = None self.old_user_id = self.instance.user_id pk = self.instance.pk if pk is not None: # Edit mode relations = Relation.objects.filter( subject_entity=pk, type__in=(REL_SUB_BILL_ISSUED, REL_SUB_BILL_RECEIVED)) issued_relation = find_first( relations, (lambda r: r.type_id == REL_SUB_BILL_ISSUED), None) received_relation = find_first( relations, (lambda r: r.type_id == REL_SUB_BILL_RECEIVED), None) if issued_relation: self.issued_relation = issued_relation self.fields[ 'source'].initial = issued_relation.object_entity_id if received_relation: self.received_relation = received_relation self.fields['target'].initial = received_relation.object_entity
def save(self): # BEWARE: chosen contacts can have already relations with the event ; # we avoid several 'REL_OBJ_IS_INVITED_TO' relations, # 'REL_OBJ_CAME_EVENT' override existing 'REL_OBJ_NOT_CAME_EVENT' relations etc... event = self.event user = self.user relations = Relation.objects create_relation = relations.create related_contacts = self.cleaned_data['related_contacts'] # NB: queries are regrouped to optimise relations_map = defaultdict(list) # per contact relations lists for relation in relations.filter( subject_entity=event.id, type__in=_TYPES, object_entity__in=[ contact.id for relationtype, contact in related_contacts ], ): relations_map[relation.object_entity_id].append(relation) relations2del = [] for relationtype, contact in related_contacts: relationtype_id = relationtype.id contact_relations = relations_map.get(contact.id, ()) # REL_OBJ_CAME_EVENT or REL_OBJ_NOT_CAME_EVENT if relationtype_id != constants.REL_OBJ_IS_INVITED_TO: symmetric = _SYMMETRICS[relationtype_id] rel2del = find_first( contact_relations, lambda relation: relation.type_id == symmetric, None, ) if rel2del is not None: relations2del.append(rel2del.id) if find_first(contact_relations, lambda relation: relation.type_id == relationtype_id, None) is None: create_relation( subject_entity=event, type=relationtype, object_entity=contact, user=user, ) if relations2del: relations.filter(pk__in=relations2del).delete() return event
def test_find_first(self): class Info: def __init__(self, data): self.data = data i1, i2, i3, i4 = Info(1), Info(2), Info(2), Info(5) l = [i1, i2, i3, i4] self.assertIs(find_first(l, lambda i: i.data == 1), i1) self.assertIs(find_first(l, lambda i: i.data == 2), i2) self.assertIs(find_first(l, lambda i: i.data == 5), i4) self.assertIsNone(find_first(l, lambda i: i.data == 12, None)) self.assertRaises(IndexError, find_first, l, lambda i: i.data == 12)
def __init__(self, section=None, *args, **kwargs): super().__init__(*args, **kwargs) self.section = section # Lines which are in the section where we create our line. self.section_lines = section_lines = [] # The lines after the one we create (but not in the same section): # their order have to be incremented self.next_lines = next_lines = [] # Order of the last line before our section (used if our section is empty). self.empty_section_order = 1 nodes = [*SectionTree(self.pform)] section_id = section.id if section else None # Filling of 'section_lines' & 'next_lines' node_it = reversed(nodes) try: while True: node = next(node_it) if not node.is_section: if node.section_id == section_id: section_lines.append(node) else: next_lines.append(node) elif node.id == section_id: previous_line = find_first( node_it, (lambda node: not node.is_section), None) if previous_line: self.empty_section_order = previous_line.order + 1 break except StopIteration: pass if section_lines: section_lines.reverse() # TODO: cached_gettext ?? msg_fmt = gettext('Before: «{question}» (#{number})').format choices = [ (0, gettext('Start of section')), *((i, msg_fmt(question=node.question, number=node.number)) for i, node in enumerate(section_lines[1:], start=1)), (len(section_lines), gettext('End of section')), ] self.fields['index'] = TypedChoiceField( label=gettext('Order'), coerce=int, choices=choices, initial=len(choices) - 1, )
def clean_old_choices(self): old_choices = self.cleaned_data['old_choices'] self.choices_2_keep = choices_2_keep = [] self.choices_2_del = choices_2_del = [] for existing_choice, choice in zip(self.initial_choices, old_choices): if choice is None: choices_2_del.append(existing_choice) else: choice = choice.strip() if not choice: raise ValidationError( self.error_messages['empty_choices'], code='empty_choices', ) # TODO: move this validation to the field ?? choices_2_keep.append((existing_choice[0], choice)) if choices_2_del: condition = PollFormLineCondition.objects \ .filter(source=self.instance, raw_answer__in=[str(c[0]) for c in choices_2_del], ) \ .first() if condition is not None: choice_id = int(condition.raw_answer) raise ValidationError( self.error_messages['used_choice'], params={ 'choice': find_first(choices_2_del, (lambda c: c[0] == choice_id))[1], 'question': condition.line.question, }, code='used_choice', ) return old_choices
def _post_instance_creation(self, instance, line, updated): super()._post_instance_creation(instance, line, updated) cdata = self.cleaned_data user = self.user append_error = self.append_error source, err_msg = cdata['source'].extract_value(line, user) append_error(err_msg) target, err_msg = cdata['target'].extract_value(line, user) append_error(err_msg) create_rel = partial( Relation.objects.safe_create, subject_entity=instance, user=instance.user, ) # TODO: move this intelligence in models.Base.save() (see regular Forms) if not updated: create_rel(type_id=REL_SUB_BILL_ISSUED, object_entity=source) create_rel(type_id=REL_SUB_BILL_RECEIVED, object_entity=target) instance.billing_address = copy_or_create_address( target.billing_address, instance, _('Billing address')) instance.shipping_address = copy_or_create_address( target.shipping_address, instance, _('Shipping address')) instance.save() else: # Update mode relations = Relation.objects.filter( subject_entity=instance.pk, type__in=(REL_SUB_BILL_ISSUED, REL_SUB_BILL_RECEIVED)) issued_relation = find_first( relations, (lambda r: r.type_id == REL_SUB_BILL_ISSUED), None) received_relation = find_first( relations, (lambda r: r.type_id == REL_SUB_BILL_RECEIVED), None) assert issued_relation is not None assert received_relation is not None if issued_relation.object_entity_id != source: issued_relation.delete() create_rel(type_id=REL_SUB_BILL_ISSUED, object_entity=source) if received_relation.object_entity_id != target: received_relation.delete() create_rel(type_id=REL_SUB_BILL_RECEIVED, object_entity=target) b_change = s_change = False if cdata['override_billing_addr']: b_change = _copy_or_update_address( target, instance, 'billing_address', _('Billing address'), ) if cdata['override_shipping_addr']: s_change = _copy_or_update_address( target, instance, 'shipping_address', _('Shipping address'), ) if b_change or s_change: instance.save()