0

I'm trying to make only the 1st inline object boolean field True by default only for Add page.

So, I have Person model and Email model which has the foreign key of Person model as shown below:

# "models.py"

class Person(models.Model):
    name = models.CharField(max_length=20)

    def __str__(self):
        return self.name

class Email(models.Model):
    person = models.ForeignKey(Person, on_delete=models.CASCADE)
    is_used = models.BooleanField()
    email = models.EmailField()

    def __str__(self):
        return self.email

Then, I set the custom form EmailForm to form in EmailInline() as shown below:

# "admin.py"

class EmailForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        kwargs['initial'] = {'is_used': True}
        super().__init__(*args, **kwargs)

class EmailInline(admin.TabularInline):
    model = Email
    form = EmailForm # Here
    
@admin.register(Person)
class PersonAdmin(admin.ModelAdmin):
    inlines = (EmailInline,)

But, all inline objects are is_used=True by default on Add page as shown below:

enter image description here

And, I added one main object with one inline object which is is_used=True as shown below:

enter image description here

But, the added inline object and other not-yet-added inline objects are is_used=True on Change page as shown below:

enter image description here

And, I added one main object with one inline object which is is_used=False as shown below:

enter image description here

But, the added inline object and other not-yet-added inline objects are is_used=True on Change page as shown below:

enter image description here

So, how can I make only the 1st inline object boolean field True by default only for Add page?

Super Kai - Kazuya Ito
  • 22,221
  • 10
  • 124
  • 129
  • Does this answer your question? [Django: Admin inline forms initial data for every instance](https://stackoverflow.com/questions/12384973/django-admin-inline-forms-initial-data-for-every-instance) – Abdul Aziz Barkat May 17 '23 at 14:28

1 Answers1

0

You can use the global variable count in __init__() and overridden get_formset() and set EmailForm to self.form in overridden get_formset() as shown below to make only the 1st inline object boolean field True by default only for Add page:

# "admin.py"

count = 0 # Here
class EmailForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        global count
        if count < 1:
            kwargs['initial'] = {'is_used': True}
            count += 1
        super().__init__(*args, **kwargs)

class EmailInline(admin.TabularInline):
    model = Email
    
    def get_formset(self, request, obj=None, **kwargs):
        if not obj:
            self.form = EmailForm
        global count
        count = 0
        return super().get_formset(request, obj, **kwargs)

@admin.register(Person)
class PersonAdmin(admin.ModelAdmin):
    inlines = (EmailInline,)

Then, only the 1st inline object is is_used=True by default on Add page as shown below:

enter image description here

And, I added one main object with one inline object which is is_used=True as shown below:

enter image description here

Then, only the added inline object is is_used=True on Change page as shown below:

enter image description here

And, I added one main object with one inline object which is is_used=False as shown below:

enter image description here

Then, the added inline object and other not-yet-added inline objects are is_used=False on Change page as shown below:

enter image description here

In addition, if changing count < 1 to count < 2 as shown below:

# "admin.py"

count = 0
class EmailForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        global count
        if count < 2: # Here
            kwargs['initial'] = {'is_used': True}
            count += 1
        super().__init__(*args, **kwargs)

# ...

Then, the 1st and 2nd inline objects are is_used=True by default on Add page as shown below:

enter image description here

Super Kai - Kazuya Ito
  • 22,221
  • 10
  • 124
  • 129
  • This can break quite easily with concurrent access. – Abdul Aziz Barkat May 17 '23 at 14:28
  • @Abdul Aziz Barkat Because of it uses the global variable `count`? – Super Kai - Kazuya Ito May 17 '23 at 14:36
  • Yes, assume two (or more) users make a request at about the same time. One possibility is the reset to 0 causes other users to have multiple `True` defaults, while another possibility is that a user never gets a `True` default since the other user already caused the `count` to increment. Global variables are quite prone to race conditions. – Abdul Aziz Barkat May 17 '23 at 14:40