简体   繁体   中英

How do I set initial values for extra fields on a Django Model Formset

Given the following models:

class ParentModel(models.Model):
    name = models.CharField(max_length=255)

class ChildModel(models.Model):
    name = models.CharField(max_length=255)
    weight = models.FloatField()
    parent = models.ForeignKey("ParentModel")

And the following ModelForm that has some extra fields for ChildModel:

class ChildBalancingForm(forms.ModelForm):
    min_weight = forms.FloatField(min_value=0.0, max_value=1.0, required=True, label="Min Weight")
    max_weight = forms.FloatField(min_value=0.0, max_value=1.0, required=True, label="Max Weight")
    class Meta:
        model = ChildModel
        fields = []

I have a parent model that has many children. I need to use some math to balance the weights of the children (with some bounds on the minimum and maximum weight of each child). So, I am trying to create a formset that allows a user to enter a min and a max weight for each child to submit for rebalancing. I want to specify a default minimum weight, and a default maximum weight in said form. Thus, I have the following in my view:

# code to load up the parent whose children are being rebalanced..
# code to set a value for default_min_weight and default_max_weight
# code to get the number of children of said parent, num_children

initial_data = [{"min_weight": default_min_weight, "max_weight": default_max_weight},] * num_children
BalancingFormSet = modelformset_factory(ChildModel, form=ChildBalancingForm, extra=0, can_delete=False, min_num=num_children, max_num=num_children)
formset = BalancingFormSet(queryset=parent.childmodel_set.all(), initial=initial_data)

However when I output the form, the default values I specified for min_weight and max_weight do not show (the fields are just empty). What is the proper way to specify initial values for those extra fields in my formset?

The problem here is that ModelFormSet s redefine the initial parameter to apply to the extra forms. However, source-diving reveals that we can just re-add it under a different name:

# code to load up the parent whose children are being rebalanced..
# code to set a value for default_min_weight and default_max_weight
# code to get the number of children of said parent, num_children

initial_data = [{"min_weight": default_min_weight, "max_weight": default_max_weight},] * num_children

BalancingFormSetBase = modelformset_factory(ChildModel, form=ChildBalancingForm, extra=0, can_delete=False, min_num=num_children, max_num=num_children)

class BalancingFormSet(BalancingFormSetBase):
    def __init__(self, *args, **kwargs):
        initial_forms_initial = kwargs.pop("initial_forms_initial", None)
        super(BalancingFormSet, self).__init__(*args, **kwargs)
        if not initial_forms_initial is None:
            self.initial = initial_forms_initial

formset = BalancingFormSet(queryset=parent.childmodel_set.all(), initial_forms_initial=initial_data)

I (sloppily) tested equivalent code on Django 1.8, and it didn't interfere with instance attributes - I didn't check what happens if you have extra set to something that isn't 0 , though.

Starting with 1.9, overriding the new get_form_kwargs method may be more robust as it doesn't assume that we can overwrite the initial attribute without unwanted consequences.

Of course, if you have this pattern more than once, it might make sense to put this __init__ definition into a base class or a mixin - however, for clarity and simplicity, I'm not doing this here.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM