I am trying to dynamically build a list of admin actions using the get_actions() method on a ModelAdmin. Each action relates to a particular instance of another model, and as new instances may be added or removed, I want to make sure the list of actions reflects that.
Here's the ModelAdmin:
class PackageAdmin(admin.ModelAdmin):
list_display = ('name', 'quality')
def _actions(self, request):
for q in models.Quality.objects.all():
action = lambda modeladmin, req, qset: qset.update(quality=q)
name = "mark_%s" % (q,)
yield (name, (action, name, "Mark selected as %s quality" % (q,)))
def get_actions(self, request):
return dict(action for action in self._actions(request))
(The weird repetitive dict of tuples return value is explained by the Django docs for get_actions().)
As expected, this results in a list of appropriately named admin actions for bulk assignment of Quality foreign keys to Package objects.
The problem is that whichever action I choose, the same Quality object gets assigned to the selected Packages.
I assume that the closures I am creating with the lambda keyword all contain a reference to the same q object, so every iteration changes the value of q for every function.
Can I break this reference, allowing me to still use a list of closures containing different values of q?
Edit: I realise that lambda is not necessary in this example. Instead of:
action = lambda modeladmin, req, qset: qset.update(quality=q)
I could simply use def:
def action(modeladmin, req, qset):
return qset.update(quality=q)