StackedInline/InlineModelAdmin conditional readonly/secret field

I would like to display the secret field of my implementation in a conditional way.

Conditional situations:

1.) new objects should display the automatically created secret field before saving the api key
2.) existing objects should not display the secret field in the ApiClient edit view

My goal is something along the lines of what is implemented in the module “djangorestframework-api-key”,
but overloading save_model() or even save_formset() has unfortunately been unsuccessful so far.

Do you have an idea?

I am using the following models in my application:

class ApiClient(models.Model):
    """Generate Customer API Clients for customers"""

    class Meta:
        verbose_name = "API Client"
        constraints = [
            models.UniqueConstraint(fields=['system', 'client_id'], name='api_client_unique')
        ]

    system = models.ForeignKey(DesiredTenant, on_delete=models.CASCADE)
    client_id = models.CharField("Client-ID", max_length=60,
                                 default="api-client-",
                                 validators=[RegexValidator(regex=API_CLIENT_REGEX,
                                                            message="Client-ID must start with 'api-client-', "
                                                                    "followed by a name")])
    ....
    description = models.CharField(max_length=250, blank=True)
    secret = models.CharField("Secret",
                              max_length=36,
                              default=random_secret,
                              validators=[MinLengthValidator(36)],
                              )
    date_created = models.DateTimeField(default=timezone.now, help_text="Creation date of the api key")
    ...


class DesiredTenant(models.Model):
    _DEFAULT_MINIMUM_PASSWORD_LENGTH: int = 8

    class Meta:
        verbose_name = "Tenant"
        permissions = [
            (CAN_VIEW_MANAGEMENT_PASSWORD_PERMISSION, "Can view management password"),
        ]

    id = models.CharField("System-ID", primary_key=True, max_length=63,
                          validators=[ALLOWED_CHARACTERS_REGEX_VALIDATOR],
                          help_text=f"For internal reference only. {ALLOWED_CHARACTERS_IN_IDENTIFIER_MESSAGE}")
    ....

My admin.py looks like this:
(StackedInline is not modified by my code)

from django.contrib.admin import TabularInline, StackedInline

class ApiClientInline(StackedInline):
    model = ApiClient
    extra = 0
    verbose_name = "API Client"
    verbose_name_plural = "API Clients"
    readonly_fields = ['date_created']

1 Like

Hey there!
Maybe this can help you.

Thanks for the reference!

I created a copy of of “BaseInlineFormSet” named “ApiClientInlineFormSet” and assigned it to the “formset” of “ApiClientInline”.

In my understanding the constructor is only invoked a single time.
How can i implement the behavior described in my initial post?