Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django Admin not saving pre-populated inline fields which are left in their initial state

I have some custom admin code which initialises some inline child objects.

If the user edits one of the inline child object's default values, then that child element is created when the parent object is saved.

I assume that Django is checking whether values have changed from their initial values and only saving if the user has changed a value.

Is this the case?

How do I force Django Admin to create inline child objects with their unchanged default values, if the user chooses not to change the default values?

class PrepopIpInlineFormSet(forms.models.BaseInlineFormSet):
    model = Ip

    def __init__(self, *args, **kwargs):
        super(PrepopIpInlineFormSet, self).__init__(*args, **kwargs)
        initial = # calculate a set of default Ip model initial values
        self.initial = initial


class PrepopIpInline(admin.options.InlineModelAdmin):
    template = "admin/linked.html"
    model = Ip
    formset = PrepopIpInlineFormSet
    fk_name = 'sim'
    admin_model_path = None
    show_url = True

    def __init__(self, *args):
        super(PrepopIpInline, self).__init__(*args)
        if self.admin_model_path is None:
            self.admin_model_path = self.model.__name__.lower()

    def get_formset(self, request, obj=None, **kwargs):
        formset = super(PrepopIpInline, self).get_formset(request, obj, **kwargs)
        formset.request = request
        return formset

    def get_extra(self, request, obj=None, **kwargs):
        if obj:
            return 0
        else:
            return ApnGgsn.objects.all().count()
like image 409
fadedbee Avatar asked Nov 28 '22 16:11

fadedbee


2 Answers

Origin: How to force-save an "empty"/unchanged django admin inline?

from django.contrib import admin
from django.forms.models import BaseInlineFormSet, ModelForm

class AlwaysChangedModelForm(ModelForm):
    def has_changed(self):
        """ Should returns True if data differs from initial. 
        By always returning true even unchanged inlines will get validated and saved."""
        return True

class CheckerInline(admin.StackedInline):
    """ Base class for checker inlines """
    extra = 0
    form = AlwaysChangedModelForm
like image 172
Yevgeniy Shchemelev Avatar answered Dec 06 '22 19:12

Yevgeniy Shchemelev


Based on @Robert Townely 's answer I created this working solution.

Bonus: you don't need to instantiate a new model nor modify the form.

Just replace <foreign_key_field_in_child_obj> with your fild name.

def save_related(self, request, form, formsets, change):
    super().save_related(request, form, formsets, change)
    obj = form.instance
    for formset in formsets:
        for form in formset:
            # obj = parent model instance
            # form.has_changed = false, no changes in pre-populated fields
            # form.instance = child model instance
            if not form.has_changed():
                form.instance.<foreign_key_field_in_child_obj> = obj
                form.save()
like image 22
j4n7 Avatar answered Dec 06 '22 19:12

j4n7