This is my model in an app that describes a graph (a DAG to be precise):
class Node(models.Model):
name = models.CharField(max_length=120, blank=True, null=True)
parents = models.ManyToManyField('self', blank=True, symmetrical=False)
def list_parents(self):
return self.parents.all()
def list_children(self):
return Node.objects.filter(parents=self.id)
def list_withindirect(self, arg):
direct = getattr(self, arg)()
withindirect = set(direct)
for d in direct:
withindirect |= set(d.list_withindirect(arg))
return list(withindirect)
def list_ancestors(self):
return self.list_withindirect('list_parents')
def list_descendants(self):
return self.list_withindirect('list_children')
def list_of_allowed_parents(self):
return list(
set(Node.objects.all()) - set(self.list_descendants()) - {self}
)
def __str__(self):
return self.name
Each node can have many other nodes as a parent. The essential point here is, that a given node has a specific set of allowed parents. That is what the method list_of_allowed_parents
is for. But how can I get a form to show only these nodes in the dropdown?
Currently this is the form:
class NodeForm(forms.ModelForm):
class Meta:
model = Node
fields = ['name', 'parents']
Which I register with the admin:
class NodeAdmin(admin.ModelAdmin):
list_display = ['id', 'name', 'list_parents', 'list_children']
form = NodeForm
admin.site.register(Node, NodeAdmin)
I assume I will have to use something like:
parents = forms.ModelMultipleChoiceField(queryset=node.list_of_allowed_parents())
But how would I pass the specific node
to the definition in forms.py?
Ideally this constraint would be added in the model. ManyToManyField
offers the parameters choices
and limit_choices_to
, but there seems to be no way to add self.list_of_allowed_parents
here.