order of fields on ModelAdmin

How to get all the fields on my custom ModelAdmin, in their original order?
I see there is ModelAdmin.get_fields method, but the read_only fields are missing.
I can add them back, but then I lose the original order, as the read_only fields are excluded.
How do I get my order back, i.e the order of fields from the model?

You have access to the attributes of the ModelAdmin class itself. Example, say you have an admin class defined as:
class MyModelAdmin(admin.ModelAdmin):

You have access to the fields and readonly_fields attributes on that class, e.g. MyModelAdmin.fields and MyModelAdmin.readonly_fields.

Note that the fields exposed in the admin are not necessarily all the fields in the model.

You can get the list of model fields from the _meta.fields attribute on the model.

But, keep in mind that there’s no requirement, assurance, or documented interface specifying that fields are going to be listed in any specific order. All these APIs and class attributes are free to present these elements in any order at any time.
There is also no documented relationship between the fields as they are defined in the model and the columns as they exist in the underlying database.

All this means is that any code you write that relies upon this information as having some “intrinsic ordering” must be considered fragile and suspect, and can fail at any time now or in the future.

This is exactly what I am doing.

My model:

class Foo(models.Model):
    name = models.CharField(unique=True, max_length=50)
    custom_field = models.CharField(max_length=50)
    field1 = models.CharField(max_length=50)
    field2 = models.CharField(max_length=50)
    field3 = models.CharField(max_length=50)
    field4 = models.CharField(max_length=50)

My ModelAdmin:

class BaseAdmin(admin.ModelAdmin):
    pass

@admin.register(Foo)
class FooAdmin(BaseAdmin):
    pass

Now when I access some ModelAdmin attributes, I get:

'fields': ['name', 'custom_field', 'field1', 'field2', 'field3', 'field4']
'exclude': None

Then I am adding some read_only fields:

class BaseAdmin(admin.ModelAdmin):
    def get_readonly_fields(self, request, obj=None):
        return [*self.readonly_fields, "custom_field"]

Now I get:

'fields': ['name', 'field1', 'field2', 'field3', 'field4', 'custom_field'],
'exclude': ['custom_field']

My question: how can I reconstruct fields so that it has its original order, while still allowing me to use read_only fields?

You can’t.

The representation of these fields internally are an undocumented interface, which means you cannot reliably depend upon what you’re going to see. And, even if you did find a way to do this, there’s no promise that it’s going to stay the same in the next release.