Filtering ModelAdmin many to many field using char field

Hello,

I have the below models:

class Play (models.Model):
    event = models.ForeignKey(Event, on_delete=models.CASCADE)
    time = models.TimeField(help_text="Start Time of Activity.")
    duration = models.IntegerField(
        help_text="Duration of the Activity in Minutes.")
    teams1 = models.ManyToManyField(Team, related_name='teams1_to_teams', blank=True)

And

class Team (models.Model):
    name = models.CharField(max_length=100, help_text="Team Name.")
    event = models.ForeignKey(Event, on_delete=models.CASCADE)

Which means a Team is linked to an event and also Play is linked to an event. When I edit a Play record in Admin I currently see in the manytomany Team fields all possible teams regardless of event and I wanted to only show the Teams that have an event the same as Play. This is what I have in admin.py for Play:

class PlayAdmin(admin.ModelAdmin):
    list_display = ('id', 'event', 'where', 'who')
    search_fields = ["event"]
    save_as = True
    
    def formfield_for_manytomany(self, db_field, request, **kwargs):
            if db_field.name == "teams1":
                kwargs["queryset"] = Team.objects.filter(event=self.event)
            return super(PlayAdmin, self).formfield_for_manytomany(db_field, request, **kwargs)

which doesn’t work as self.event is not valid in the queryset. Please could you tell me how I get the event from Play to then filter the Team ?

Hello!

Do you want to see an instance of the Team related to an Event?

Please share your view.

The issue with what you have here is that the reference to self in the formfield_for_manytomany is a reference to the PlayAdmin instance, not the instance of Play.

You would need to find the attribute of the ModelAdmin instance that holds the reference to the instance of the entity being edited, and use that in the filter. (<conjecture> I believe it’s implied in the docs that the attribute name would be instance, and so self.instance is the instance of the Play model being edited, which means that self.instance.event is the related Event instance, or that self.instance.event_id is the key itself. </conjecture> Unfortunately, I’m not in a position to verify this. If you wanted to check it out, you could add something like a print(dir(self)) in this method to see what attributes exist.)

Thanks Ken. Looks like self.instance doesn’t exist. I ended up cheating by creating my own event_id variable and then using this in the queryset filter:

    def get_form(self, request, obj=None, **kwargs):
        self.event_id = obj.event
        return super().get_form(request, obj, **kwargs)

    def formfield_for_manytomany(self, db_field, request, **kwargs):

         if db_field.name == "teams1":
            kwargs["queryset"] = Team.objects.filter(event=self.event_id)
        
         return super(PlayAdmin, self).formfield_for_manytomany(db_field, request, **kwargs)