TooManyFieldsSent Error raised when saving admin.ModelAdmin with TabularInline even with unchanged fields

Whenever I try to save without editing any fields in Author in the admin page, I get a TooManyFields error. I am aware that I can simply set this in settings.py.

DATA_UPLOAD_MAX_NUMBER_FIELDS = None 
# or DATA_UPLOAD_MAX_NUMBER_FIELDS = some_large_number

However, not setting a limit would open up an attack vector and would pose security risks. I’d like to avoid this approach as much as possible.

My admin model AuthorAdmin has a TabularInline called PostInline.

admin.py

    class AuthorAdmin(admin.ModelAdmin)
        inlines = [PostInline]

    class PostInline(admin.TabularInline)
        model = Post

models.py

    class Author(models.Model):
        name = models.CharField(max_length=100)
        
        def __str__(self): 
            return str(self.name)

    class Post(models.Model):
        title = models.CharField(max_length=100)
        author = models.ForeignKey(Author, on_delete=models.CASCADE)

        def __str__(self):
            return str(self.title)
     

The reason this error is being raised is that an Author can have multiple posts. Whenever this Author is saved (without any field change), it sends out a POST request which includes the post_id and the post__series_id based on the number of posts under that same author. This can easily exceed the default limit set by Django which is set to 1000.

Is there a way to not include unchanged fields in the POST request upon save? Or a better approach to solve this issue without having to resort to updating DATA_UPLOAD_MAX_NUMBER_FIELDS?

Note
This is just an oversimplification of what I’m trying to solve. The author and post models are just examples, but they represent the relationship of the actual models I’m using. I would like to get an approach which involves not removing the inline.

Welcome @FaitAccompli !

Is there a way? Sure, but it’s going to involve writing the JavaScript necessary to do that. You would have to build the post data elements yourself from the values in the formsets, and then writing the code in the views to handle the sparse submissions.

Or, you could take another approach and gather all the data into a single JSON object in the browser, and submit it through a custom API that would process it. (You could, in theory, expand it from JSON to a regular POST submission on the server, then pass that POST data to the normal view processing it.)

But either way, since this work does need to be done in the browser, there’s going to be some JavaScript involved to solve it if you don’t want to change the max number of fields.

Hi @KenWhitesell, thank you for the reply. I’m contemplating if it’s worth the effort to do so. On one hand, I’ve considered the following:

  1. A user can just go to the Post page in admin and filter by Author there.
  2. Just increase the DATA_UPLOAD_MAX_NUMBER_FIELDS
  3. Use a third-party library to perform paginations on inlines (django-admin-inline-paginator). Although, I don’t think this is going to be maintained anymore and will likely break in future versions.

I also tried making the fields read-only but they seem to still be included in the POST request upon save. How would you go about this?

I generally don’t rely upon the admin for my non-administrative UI.
This means I’d already be building my view for this situation, and if it were likely that I would regularly exceed the 1000 by a significant margin, then I’d probably go the route of converting the post data to a JSON submission to an API-style endpoint.

I’d have no problems doubling that value to 2000. Actually, I see where that setting was introduced for version 1.10, in 2016. Given the change in server capacity since then, I don’t see where increasing it to 2000 would create more risk than the 1000 setting 8 years ago.

Actually, if I thought I was going to have a situation where I’d have more than 2000 widgets on a page, I’d be seriously rethinking the purpose of that page and how it was constructed. I’d be looking real hard to find some way to make that more practical.

Correct, you’d need to mark them as disabled. However, the server would also need to know which fields were disabled, leaving you in effectively the same position as before.

1 Like

Thanks @KenWhitesell. It’s also mentioned in the documentation:

DATA_UPLOAD_MAX_NUMBER_FIELDS

You can set this to None to disable the check. Applications that are expected to receive an unusually large number of form fields should tune this setting.

I’m guessing Django isn’t really against changing this to a higher value but it’s better for us to consider if it’s worth for our models that have this relationship to be an inline in the admin page to begin with.

I’ve tried using the pagination approach and it works well for our use case. I hope in future versions Django decides to support this although I get why they aren’t.