djangodjango-admindjango-admin-filters

Django select2 with autocomplete_fields to have a dynamic default value


I have a Product model and a HeadFlowDataset model. These two models are connected with a foreinkey relationship, in which one product can have many headflowdataset pairs.

Their model codes are as below:

class Product(models.Model):
    id = models.UUIDField(
        primary_key=True,
        default=uuid.uuid4,
        editable=False,
    )
    ...
    # other fields in the model, not exactly related to this problem

class HeadFlowDataSet(models.Model):
    id = models.UUIDField(
        primary_key=True,
        default=uuid.uuid4,
        editable=False,
    )
    product = models.ForeignKey(
        Product,
        on_delete=models.CASCADE,
    )
    head = models.FloatField()
    flow = models.FloatField()

    def __str__(self):
        return self.product.pump_name

Every product can have up to 10-15 head-flow sets. And currently I'm using Django admin panel to populate my product database. On the other hand, there may be up to 1000 products in total. So when the admin was trying to add head-flow datasets, the process was a bit challenging to find the product name from the select menu that Django admin provided. So I used Django autocomplete_fields in the ModelAdmin as below so that the admin can at least search for the product name:

class HeadFlowDatasetAdmin(admin.ModelAdmin):
    list_display = (
        "product",
        "head",
        "flow",
    )
    fields = (
        "product",
        "head",
        "flow",
    )
    autocomplete_fields = ["product"]

    def get_ordering(self, request):
        return [Lower("product__pump_name"), "head"]

But this approach too is a bit frustrating to search for the product name every time we are trying to add a new head-flow dataset.

QUESTION: How can I set a default value for this select2 field that dynamically sets the last product searched as the default value? So that when the admin tries to add a new head-flow dataset, he sees the last product selected by default until he manually changes the product?


Solution

  • You can use a concept in Django called InlineModelAdmin [django-docs] and in your case, your admin.py module can be as below:

    from django.contrib import admin
    from your_app_name.models import Product, HeadFlowDataSet
    
    
    class HeadFlowDatasetInline(admin.TabularInline):
        model = HeadFlowDataset
        extra = 1
    
    
    class ProductAdmin(admin.ModelAdmin):
        list_display = (
            "pump_name",
            "main_model",
            "usage",
            "pump_type",
        )
        search_fields = (
            "pump_name",
            "main_model__model_name_fa",
            "usage__usage_name_fa",
            "pump_type__type_name",
        )
        fields = (
            "main_model",
            "usage",
            "sub_usage",
            "pump_type",
            "pump_name",
            "pump_image",
            "NPSH_diagram_image",
            "power_diagram_image",
            "max_head",
            "max_flow",
            "motor_ph",
            "motor_rpm",
            "pump_technical_datasheet_fa",
            "pump_technical_datasheet_en",
        )
        inlines = [HeadFlowDatasetInline]
    
        def save_model(self, request, obj, form, change):
            obj.created_by = request.user
            obj.last_updated_by = request.user
            obj.save()
    
        def save_formset(self, request, form, formset, change):
            instances = formset.save(commit=False)
            for instance in instances:
                instance.user = request.user
                instance.save()
    

    With the above code snippet, you have an inline part with one set of HeadFlowDatasetobjects on each page of your Product models in your Django admin panel which can be added on need form that panel and with this approach, this issue will be resolved.