Accessing both Directions of ManyToManyFields

In order to access a ManyToManyField also in the model that does not define it, explicitly define the field in the model form.

For instance, assume Data Entries shall be have many to many Relations with Dataset References.

First define that Datasets References uses Data Entries as Categories via many to many Relations:

# dataset.models:
form django.db import models


class Reference(models.Model):
    pmid = models.IntegerField()
    categories = models.ManyToManyField('data.Entry')
    ...

In the data form define the References field explicitly:

# data.forms:
from django import forms

from datasets.models import Reference

from models import Entry


class EntryForm(forms.ModelForm):
    references = forms.ModelMultipleChoiceField(
        label="References",
        queryset=References.objects.all(),
        required=False,
        help_text="References to the literature",
        widget=admin.widgets.FilterSelectMultiple('references', False)
    )
    class Meta:
        models = Entry

The form can be employed outside as well as inside the admin:

# data.admin:
from django.contrib import admin

class EntryAdmin(admin.ModelAdmin):
    fields = ('references',)

    def safe_model(self, request, obj, form, change):
        # Save without m2m field (can not save them until obj has id):
        super(EntryAdmin, self).save_model(request, obj, form, change):
        # If it worked, deal with m2m fields:
        obj.references.clear()
        for reference in form.cleaned_data['references']:
            obj.references.add(reference)

    def get_form(self, request, obj=None, **kwargs):
        if obj:
            self.form.base_fields['references'].initial = [o.pk for o in obj.references.all()]
        else:
            self.form.base_fields['references'].initial = []
        return super(EntryAdmin, self).get_form(request, obj, **kwargs)


admin.site.register(Entry, EntryAdmin)
many-to-many-formatted.jpg/
Edit tutorial

Comment on This Data Unit