Ajax based drop down menu in Django admin

In your model admin class, you have:

This means it’s going to use the class FeedFeedSpecificationInline (FFSI) as an inline.

It (FFSI), is defined as:

It defines a reference to FeedSpecificationForm.

It’s in the definition for that form that you need to do this work of defining the field values for the fields, not in the ModelAdmin class itself.

You’ll also have the need to ensure that you’re passing the right data through the various functions to ensure the instances of the form are created correctly.

I’m sorry, but I have no actual code to share. We don’t customize the Admin to this degree - we reserve the admin strictly for internal support roles, which means we never want to filter out options. Anytime we’re doing something that is restricting options based on context is done in a regular view. (We use a very strict interpretation of the first two paragraphs of the Django Admin docs.)

Hi,

I was able to make it work. I am posting the solution that worked for me so that other might benefit. Again to repeat the requirements. Let’s say we have a parent model A, Child models B,C.
In the Django admin:

  1. Child Forms for models B, C should be inline with Form of Model A.

  2. Say, model A has a field x which is a drop down. Model B has a field y. When x changes, y should change dynamically via ajax.

  3. When we click save and continue editing or save. From A , B validation fields must be cleaned so that y is compared to changed value of x instead of old value of x and throwing validation errors.

  4. Solution: Override _clean_fields(self) method to refresh values of y for new values of x.

class FeedSpecificationForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super(FeedSpecificationForm, self).__init__(*args, **kwargs)
        self.fields['item_types'].widget = forms.CheckboxSelectMultiple(
            choices=Item.TypeChoice.feed_specification_choices()
        )
        try:
            self.fields['tags'].queryset = Tag.objects.filter(
                station=self.instance.feed.station
            )
            self.fields['video_tags'].queryset = VideoTag.objects.filter(
                station=self.instance.feed.station
            )
        except:
            self.fields['tags'].queryset = Tag.objects.none()
            self.fields['video_tags'].queryset = VideoTag.objects.none()
    
    def _clean_fields(self):
        self.fields['tags'].queryset = Tag.objects.filter(station_id=self.data['station'])
        self.fields['video_tags'].queryset = VideoTag.objects.filter(station_id=self.data['station'])
        super()._clean_fields()

class FeedFeedSpecificationInline(admin.StackedInline):
    model = FeedSpecification
    form = FeedSpecificationForm
    readonly_fields = ('id', )
    extra = 1
    
class FeedFeedShowcaseInline(admin.StackedInline):
    model = FeedShowcase
    readonly_fields = ('id', )
    extra = 1

@admin.register(Feed)
class FeedAdmin(admin.ModelAdmin):
    search_fields = ('slug','station__name')
    list_filter = ('station__name',)
    inlines = [FeedFeedSpecificationInline, FeedFeedShowcaseInline]        
    class Media:
        js = ("feed_station_tag.js",)

ajax file

jQuery(function($){
    $(document).ready(function(){
        $("#id_station").change(function(){
            console.log("station id", $(this).val());
            $.ajax({
                url: window.location.origin +"/api/v1/tags/",
                type:"GET",
                data:{station_id: $(this).val(),page_size: 500000},
                success: function(result) {
                    var result1 = result["results"];
                    console.log("tags for the given station ID are",result1);
                    var total_forms = $("#id_specifications-TOTAL_FORMS").val();
                    for(i=0;i< total_forms; i++){
                        var tag_id = "id_specifications-"+i+"-tags"
                        cols = document.getElementById(tag_id);
                        cols.options.length = 0;
                        for(var k in result1){
                            cols.options.add(new Option(result1[k]["name"],result1[k]["id"]));
                        }

                    }
                
                },
                error: function(e){
                    console.error(JSON.stringify(e));
                },
            });
        });
    }); 
});
1 Like

Hello, our solution is helpful but i having issue on the same.

Like i have 2 models of django in a one app names are detail and task so in the task app i had taken the detail model as a foreign key so whenever i select any saved attribute of detail field in task model then the same column like of detail field should be fill like name and email both are same so they both are filled same as of detail model attribute i selected
i have attached the screenshot of this

Screenshot from 2024-01-26 11-57-31

Welcome @vishan25 !

If you’re having an issue with customizing the admin, I suggest you open a new topic with a complete description of that issue. What you describe here does not appear to be directly related to the original. Also this topic has been marked as “Solved”, making it less likely that people will see it to respond.

ok will you guide me but i stuck over there badly