Figured it out thanks to this hint: https://stackoverflow.com/a/6200451/1344854
Model save() method stays default. First I tied a tag to my FkModel and M2mModel instances. The rest of the job is done in ModelAdmin.
# models.py
class FkModel(models.Model):
name = models.CharField(max_length=255, unique=True)
tag = models.ForeignKey(Tag, blank=True, null=True, related_name='fk')
...
class M2mModel(models.Model):
name = models.CharField(max_length=255, unique=True)
tag = models.ForeignKey(Tag, blank=True, null=True, related_name='m2m')
...
# admin.py
class MyModelAdmin(admin.ModelAdmin):
def save_model(self, request, obj, form, change):
form.save() # as I learned, without saving at this point, obj.field_m2m.all() will be empty
tags = []
if obj.field_m2m.all():
tags += [m2m.tag for m2m in obj.field_m2m.all()]
if obj.field_fk:
tags += [obj.field_fk.tag]
form.cleaned_data['tags'] = tags
super(MyModelAdmin, self).save_model(request, obj, form, change)