diff options
author | Étienne Loks <etienne.loks@iggdrasil.net> | 2018-04-24 12:44:18 +0200 |
---|---|---|
committer | Étienne Loks <etienne.loks@iggdrasil.net> | 2018-06-12 08:43:58 +0200 |
commit | b32f5bf2969bc8bdbb1f402a7465b8519e21aa81 (patch) | |
tree | 17c2e17a835bde449b988b8725170e65f1ff235e | |
parent | 3ed2a3da11228913465226eee9137c93fc3c5374 (diff) | |
download | Ishtar-b32f5bf2969bc8bdbb1f402a7465b8519e21aa81.tar.bz2 Ishtar-b32f5bf2969bc8bdbb1f402a7465b8519e21aa81.zip |
Wizards: manage intermediary model for M2M relations
-rw-r--r-- | ishtar_common/wizards.py | 50 |
1 files changed, 43 insertions, 7 deletions
diff --git a/ishtar_common/wizards.py b/ishtar_common/wizards.py index e47d5b48b..70f3caa19 100644 --- a/ishtar_common/wizards.py +++ b/ishtar_common/wizards.py @@ -525,7 +525,7 @@ class Wizard(NamedUrlWizardView): frm.cleaned_data.pop('DELETE') for key in frm.cleaned_data: value = frm.cleaned_data[key] - if value is None or value == '': + if value is None or value in ['', []]: continue if key in associated_models: value = associated_models[key].objects.get( @@ -736,6 +736,18 @@ class Wizard(NamedUrlWizardView): r.delete() for key, value in m2m: related_model = getattr(obj, key + 's') + related_data = {} # used for intermediary models + + # an intermediary model is used + if not related_model.through._meta.auto_created: + for field in related_model.through._meta.get_fields(): + # is used for the obj or target + if getattr(field, 'related_model', None) and \ + (field.related_model == related_model.model or + isinstance(obj, field.related_model)): + continue + related_data[field.name] = None + if key not in m2m_items: if type(key) == dict: vals = [] @@ -747,6 +759,7 @@ class Wizard(NamedUrlWizardView): m2m_items[key] = vals else: m2m_items[key] = related_model.all() + if value not in m2m_items[key]: if type(value) == dict: model = related_model.model @@ -794,8 +807,7 @@ class Wizard(NamedUrlWizardView): # should be managed normally in forms but... fields = model._meta.get_fields() - - has_problemetic_null = False + has_problematic_null = False for field in fields: if (field.name not in value or not value[field.name]) \ @@ -806,14 +818,19 @@ class Wizard(NamedUrlWizardView): and (hasattr(field, 'default') and (not field.default or field.default == NOT_PROVIDED)): - has_problemetic_null = True + has_problematic_null = True break - if has_problemetic_null: + if has_problematic_null: continue if hasattr(model, 'data') and 'data' not in value: value['data'] = {} + # remove intermediary model keys + for k in related_data.keys(): + if k in value: + related_data[k] = value.pop(k) + if get_or_create: value, created = model.objects.get_or_create( **value) @@ -821,11 +838,30 @@ class Wizard(NamedUrlWizardView): value = model.objects.create(**value) value.save() # force post_save # check that an item is not add multiple times (forged forms) - if value not in related_model.all() and\ + if value not in related_model.all() and \ (not hasattr(related_model, 'through') or not isinstance(value, related_model.through)): # many to many and the value have been already managed - related_model.add(value) + + # an intermediary model is used + if not related_model.through._meta.auto_created: + for field in related_model.through._meta.get_fields(): + if hasattr(field, 'related_model') \ + and field.related_model: + # assume that one foreign key is used for obj + # table and value table - more complex schema + # are not managed + if isinstance(value, + field.related_model): + related_data[field.name] = value + elif isinstance(obj, + field.related_model): + related_data[field.name] = obj + related_model.through.objects.create( + **related_data + ) + else: + related_model.add(value) # necessary to manage interaction between models like # material_index management for baseitems obj._cached_label_checked = False |