Django - MultipleCheckBoxSelector with m2m field - How to add object instead of save_m2m() -


i use inlineformset_factory custom form option in order change queryset , widget of m2m field, ie: ezmap. want form give user option add or remove current selected_map m2m field checkboxselectmultiple widget. however, dont want give user ability remove other objects there. problem when save formset formset.save_m2m(), overides field , erase objects saved.

how add new object without erasing others?

enter image description here


models: (some of unecessary fields removed)

class shapefile(models.model):     filename = models.charfield(max_length=255)  class ezmap(models.model):     map_name = models.slugfield(max_length=50)     layers = models.manytomanyfield(shapefile, verbose_name='layers display', null=true, blank=true)  class layerstyle(models.model):     stylename = models.slugfield(max_length=50)     layer = models.foreignkey(shapefile)     ezmap = models.manytomanyfield(ezmap) 

forms:

class polygonlayerstyleformset(forms.modelform):     add_to_map = forms.booleanfield(required=false)     def __init__(self, *args, **kwargs):         self.map_selected =  kwargs.pop("map_selected", none)         super(polygonlayerstyleformset, self).__init__(*args, **kwargs)         self.fields['conditionstyle'].help_text = "put * if want select entire table"         self.fields['ezmap'].widget = forms.checkboxselectmultiple()         self.fields['ezmap'].queryset = ezmap.objects.filter(id=self.map_selected.id)         self.fields['ezmap'].help_text =""      class meta:         model = layerstyle      def save(self, *args, **kwargs):         instance = super(polygonlayerstyleformset, self).save(*args, **kwargs)         instance.add_to_map = self.cleaned_data['add_to_map']         return instance   ftlstylepolygonformset = inlineformset_factory(shapefile, layerstyle, can_delete=true, extra=1, max_num=5,                 fields = ['stylename', 'conditionstyle', 'fillcolor', 'fillopacity', 'strokecolor', 'strokeweight', 'ezmap'], form=polygonlayerstyleformset) 

views:

def setlayerstyle(request, map_name, layer_id):     map_selected = ezmap.objects.get(map_name=map_name, created_by=request.user)     layer_selected = shapefile.objects.get(id=layer_id)     layerstyle_selected = layerstyle.objects.filter(layer=layer_selected)     styleformset = ftlstylepolygonformset     if request.post:         formset = styleformset(request.post, instance=layer_selected)         if formset.is_valid():             instances = formset.save()             instance in instances:                 if instance.add_to_map:                     instance.ezmap.add(map_selecte)                 else:                     instance.ezmap.remove(map_selected)             save_link = u"/ezmapping/map/%s" % (map_name)             return httpresponseredirect(save_link)     else:         formset = styleformset(instance=layer_selected)         #set initial data add_to_map         form in formset:             if form.instance.pk:                 if map_selected in form.instance.ezmap.all():                     form.fields['add_to_map'].initial = {'add_to_map': true} 

i confused you're doing ezmap form field. set queryset single-element list, use checkboxselectmultiple widget it. setting let user deselect matching map, not add new ones?

to @ initialization, need define custom base formset class , pass in formset argument factory.

from django.forms.models import baseinlineformset  class polygonlayerstyleform(forms.modelform):     def __init__(self, *args, **kwargs):         self.map_selected =  kwargs.pop("map_selected", none)         super(polygonlayerstyleform, self).__init__(*args, **kwargs)         self.fields['conditionstyle'].help_text = "put * if want select entire table"         self.fields['ezmap'].widget = forms.checkboxselectmultiple()         self.fields['ezmap'].queryset = ezmap.objects.filter(id=self.map_selected.id)         self.fields['ezmap'].help_text =""      class meta:         model = layerstyle  class polygonlayerstyleformset(baseinlineformset):     def __init__(self, *args, **kwargs):         self.map_selected =  kwargs.pop("map_selected", none)         super(polygonlayerstyleformset, self).__init__(*args, **kwargs)      def _construct_form(self, i, **kwargs):         kwargs['map_selected'] = self.map_selected         return super(polygonlayerstyleformset, self)._construct_form(i, **kwargs)  ftlstylepolygonformset = inlineformset_factory(shapefile, layerstyle, formset=polygonlayerstyleformset, form=polygonlaterstyleform, # , other arguments above                                                ) 

it might simpler go through formset forms , directly change field's queryset after creating in view:

    formset = ftlstylepolygonformset(instance=layer_selected)     form in formset.forms:         form.fields['ezmap'].queryset = ezmap.objects.filter(id=map_selected.id) 

speaking of which, usual convention split post , cases in view:

from django.shortcuts import render  def setlayerstyle(request, map_name, layer_id):     map_selected = ezmap.objects.get(map_name=map_name, created_by=request.user)     layer_selected = shapefile.objects.get(id=layer_id)     layerstyle_selected = layerstyle.objects.filter(layer=layer_selected)     if request.method == 'post':         formset = ftlstylepolygonformset(request.post, instance=layer_selected, map_selected=map_selected)         if formset.is_valid():             instances = formset.save()             save_link = u"/ezmapping/map/%s" % (map_name)             return httpresponseredirect(save_link)     else:         formset = ftlstylepolygonformset(instance=layer_selected, map_selected=map_selected)     return render(request, "ezmapping/manage_layerstyle.html", {'layer_style': layerstyle_selected, 'layerstyleformset': formset, 'layer': layer_selected}) 

and it's better use redirect shortcut reverse lookup view redirect on success rather hardcode target url. , use get_object_or_404 or equivalent when accessing objects based on url arguments - right bogus url trigger exception , give user 500 status error, undesirable.

to conditionally add ezmap relationship:

class polygonlayerstyleform(forms.modelform):     add_to_map = forms.booleanfield()      def save(self, *args, **kwargs):         instance = super(polygonlayerstyleform, self).save(*args, **kwargs)         instance.add_to_map = self.cleaned_data['add_to-map']         return instance 

then in view:

instances = formset.save() instance in instances:     if instance.add_to_map:         instance.ezmap.add(map_selected) 

you add call in save method, you'd have set map member data sometime - , more importantly, deal commit=false case.


Comments

Popular posts from this blog

css - Which browser returns the correct result for getBoundingClientRect of an SVG element? -

gcc - Calling fftR4() in c from assembly -

Function that returns a formatted array in VBA -