How to force-save an "empty"/unchanged django admin inline?
Asked Answered
O

3

31

I have some inlines in one of my admin models which have default values which likely won't need to be changed when adding a new instance with "Add another ...". Unfortunately django won't recognize these inline as new objects unless some value has changed. This forces me to add an inline, change an arbitrary value, save, change the value back and save again to reach the desired effect.

The only solution I've come up with so far is to add a hidden 'changed'-field which would be populated via JavaScript when adding a new inline. As this feels very hackish I hope there is a more elegant solution.

Opiate answered 7/9, 2010 at 10:15 Comment(0)
O
76

It took me quite some time to figure out but it is actually really simple.

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
Opiate answered 17/9, 2010 at 10:55 Comment(1)
I wouldn't say obvious, but definitely simple and awesome!Chemisette
S
13

@daniel answer is great, however it will try to save the instance that is already created ever if no changes is made, which is not necessary, better to use it like:

class AlwaysChangedModelForm(ModelForm):
    def has_changed(self, *args, **kwargs):
        if self.instance.pk is None:
            return True
        return super(AlwaysChangedModelForm, self).has_changed(*args, **kwargs)
Sandra answered 20/4, 2016 at 21:21 Comment(1)
I tried this and self.instance.pk was a blank string sometimes (not None), so I had to change this to if not self.instance.pk:. Also, has_changed method (From ModelForm->BaseForm) does not have any additional *args or **kwargs so pylint has a warning about this method having no parameters. Otherwise is working good!Jablonski
K
5

Combined @Daniels, @HardQuestions' and @jonespm answers:

class MarkNewInstancesAsChangedModelForm(forms.ModelForm):
    def has_changed(self):
        """Returns True for new instances, calls super() for ones that exist in db.
        Prevents forms with defaults being recognized as empty/unchanged."""
        return not self.instance.pk or super().has_changed()
Kwashiorkor answered 16/4, 2020 at 11:54 Comment(1)
While this code may solve the question, including an explanation of how and why this solves the problem would really help to improve the quality of your post, and probably result in more up-votes. Remember that you are answering the question for readers in the future, not just the person asking now. Please edit your answer to add explanations and give an indication of what limitations and assumptions apply.Handsaw

© 2022 - 2024 — McMap. All rights reserved.