Customize Django admin with fieldsets, search, filter, readonly_fields



 To create advanced configuration for Django admin with fieldsets, search, and filter, you can follow these steps:

1. Define your Django model: Start by defining your Django model in your app's `models.py` file. For example, let's say you have a model called `Product` with several fields.

```python

from django.db import models


class Product(models.Model):

    name = models.CharField(max_length=100)

    description = models.TextField()

    price = models.DecimalField(max_digits=8, decimal_places=2)

    category = models.ForeignKey('Category', on_delete=models.CASCADE)

```


2. Register the model in the admin site: In your app's `admin.py` file, import the model and register it with the admin site.


```python

from django.contrib import admin

from .models import Product


admin.site.register(Product)

```


3. Customize the admin interface: To configure advanced options for the admin interface, you can override the default `ModelAdmin` class. Create a new class that inherits from `admin.ModelAdmin` and override the desired settings.


```python

from django.contrib import admin

from .models import Product


class ProductAdmin(admin.ModelAdmin):

    search_fields = ['name']  # Specify the fields to search in the admin interface

    list_filter = ['category']  # Add filters for the specified fields


    fieldsets = (

        ('General Information', {

            'fields': ('name', 'description', 'price')

        }),

        ('Category', {

            'fields': ('category',)

        }),

    )  # Group fields into sections (fieldsets) for better organization


admin.site.register(Product, ProductAdmin)

Collapsed fieldsets 

fieldsets = [
        (
            None,
            {
                "fields": ["url", "title", "content", "sites"],
            },
        ),
        (
            "Advanced options",
            {
                "classes": ["collapse"],
                "fields": ["registration_required", "template_name"],
            },
        ),
    ]

```


In the above example, we've added search functionality for the `name` field using the `search_fields` attribute. We've also added a filter option for the `category` field using the `list_filter` attribute. The `fieldsets` attribute is used to group fields into sections for better organization in the admin interface.


With these customizations, you should see the advanced configuration in the Django admin interface for the `Product` model, including the search field, filter options, and fieldset organization.


Note: Make sure to run the necessary migrations (`python manage.py makemigrations` and `python manage.py migrate`) after making changes to the models or admin configuration.


Readonly_fields

By default, the Django admin interface allows all fields to be editable. However, you can specify certain fields as read-only by using the `readonly_fields` attribute in your `ModelAdmin` class. This attribute should be a list or tuple containing the fields that you want to display as non-editable.


The fields specified in `readonly_fields` will be displayed as-is in the admin interface and cannot be modified. Additionally, they are excluded from the form used for creating and editing objects. It's important to note that if you have explicitly defined the `fields` or `fieldsets` attributes in your `ModelAdmin` class, the read-only fields must be present in order to be shown; otherwise, they will be ignored.


If you use `readonly_fields` without explicitly defining the field ordering through `ModelAdmin.fields` or `ModelAdmin.fieldsets`, the read-only fields will be added at the end of the form after all the editable fields.


A read-only field can display data not only from a model's field but also from a method of the model or a method of the `ModelAdmin` class itself. This functionality is similar to how `ModelAdmin.list_display` works. This allows you to use the admin interface to provide feedback on the status of the objects being edited. For example, you can display computed values or call methods to generate custom display outputs for read-only fields.


readonly_fields = ["address_report"]


Example for Offer model in an UV application. 

class OfferAdmin(admin.ModelAdmin):

    save_as = True

    ordering = ['-modified', '-created']

    search_fields = ('vehicle_merk__name', 'vehicle_model__name', 'name', 'owner_description', 'note' )

    list_filter = ('offer_status', 'offer_type', 'created',  'vehicle_merk')

    list_display = ('__str__', 'created', 'owner_description')

    raw_id_fields = ('stock_vehicle',)

    readonly_fields = ('automatic_purchase_price', 'unique_key', 'source',)

    fieldsets = [

        (   

            "Contactpersoon",

            {   

                "fields": ["name", "email", "phone_number", "source"],

            },

        ),

        (   

            "Vehicle information",

            {   

                "fields": ["offer_type", "owner_description", "vehicle_merk", "vehicle_model", "mileage", "first_registration", "fuel_type", "gearbox", "owner_laste_price", "estimate_purchase_price", "automatic_purchase_price",  "offer_status", "note", "created", "offer_type", "stock_vehicle"],

            },

        ),


        (   

            "Advanced Vehicle information",

            {   

                "fields": ["paint", "colour", "emission_class", "engine_size", "doors", "seats", "carrosserietype", "power_kw", "power_hp", ],

            },

        ),

    ]


How to add a custom button to Django change view page?


To add a custom button to the Django change view page, you can follow these steps:

1. Create a custom template for the change view: First, create a custom template for the change view of your model. By default, Django uses the template named `change_form.html` for the change view. To override it, create a new template file in your app's templates directory with the same name (`change_form.html`).

2. Customize the template: Open the `change_form.html` template and add the custom button to it. You can place the button anywhere in the template according to your desired layout. For example, you can add a button at the bottom of the form like this:

```django
{% extends "admin/change_form.html" %}

{% block object-tools-items %}
    {{ block.super }}
    <li>
        <a href="{% url 'admin:myapp_mymodel_custom_action' original.pk %}" class="btn btn-primary">
            Custom Action
        </a>
    </li>
{% endblock %}
```

In the code above, we're extending the default `admin/change_form.html` template and overriding the `object-tools-items` block. Within the block, we've added a list item (`<li>`) with a link (`<a>`) to a custom action URL. Customize the URL by replacing `'myapp_mymodel_custom_action'` with the actual URL name for your custom action view. You can also modify the button's appearance by adding appropriate CSS classes.

3. Define a custom action view: In your app's `views.py` file, define a custom action view that will be triggered when the custom button is clicked. This view should handle the custom action logic. For example:

```python
from django.shortcuts import render, redirect

def custom_action_view(request, object_id):
    # Implement your custom action logic here
    # Retrieve the object based on the provided object_id
    # Perform the desired action

    # Redirect back to the change view or any other desired view
    return redirect('admin:myapp_mymodel_change', object_id)
```

Replace `'myapp_mymodel_change'` with the actual URL name for the change view of your model.

4. Define a URL pattern: Add a URL pattern to your app's `urls.py` file to map the custom action view. For example:

```python
from django.urls import path
from . import views

app_name = 'myapp'

urlpatterns = [
    # ...
    path('mymodel/<int:object_id>/custom-action/', views.custom_action_view, name='mymodel_custom_action'),
    # ...
]
```

Replace `'myapp'` with the actual name of your app and `'mymodel'` with the name of your model.

With these changes, you should have a custom button displayed on the Django change view page for your model. Clicking the button will trigger the custom action view, allowing you to perform your desired logic.
 
PS: 

If you really have to make a lot of adjustments, it seems that you could compile a separate view with form and menu faster than adjusting it with admin because this is very generic.

Comments