Opened 3 years ago

Closed 3 years ago

Last modified 7 months ago

#24731 closed New feature (needsinfo)

ManyToMany model clean validation of related fields

Reported by: blah73 Owned by: nobody
Component: Database layer (models, ORM) Version: 1.8
Severity: Normal Keywords: ManyToMany clean validation
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

Suppose I have a model with a ManyToManyField similar to this one (the model Word has a language, too):

class Sentence(models.Model):
    words = models.ManyToManyField(Word)
    language = models.ForeignKey(Language)
    def clean(self):
        for word in self.words.all():
            if word.language_id != self.language_id:
                raise ValidationError('One of the words has a false language')

When trying to add a new sentence (e.g. through django admin) I get 'Sentence' needs to have a value for field "sentence" before this many-to-many relationship can be used.

Apparently the only way to fix this is to put the validation logic in a forms.ModelForm and then add that form to the admin.ModelAdmin. This fixes the issue with the admin input but now my API is fragile. (Directly API access can add invalid data)

Is this part of a larger issue with Many to Many fields? Is there anything in progress that would alleviate this specific issue? I understand that the ManyToMany is pretty complex and this would likely require restructuring it. I'd like to help out if I possible... the current work around solution is kinda dangerous from a Django user perspective.

I borrowed this example from the following source:
http://stackoverflow.com/questions/7986510/django-manytomany-model-validation

and made a minimal example case in Django 1.8:
https://github.com/blah73/mmtest

Change History (5)

comment:1 Changed 3 years ago by Tim Graham

Resolution: needsinfo
Status: newclosed

I'm not aware of any work or proposals that would make something like this possible. Since we'd need to make some decisions on an API, discussion should first happen on the DevelopersMailingList. I'll close this ticket until we have an action plan.

Possible solution using signals: http://schinckel.net/2012/02/06/pre-validating-many-to-many-fields./

comment:2 Changed 3 years ago by blah73

Thanks for the link. Using m2m signals looks like it will work and I plan on implementing it. However it does add additional complexity compared to normal model validation. I'll make a post on the developers mailing list.

comment:3 Changed 3 years ago by Federico Capoano

Hi everybody,

I also think this is an area for improvement in django.

I've posted on django-developers: https://groups.google.com/forum/#!topic/django-developers/pQ-8LmFhXFg

I quote the relevant bits:


I spent a few hours working on this issue, I consider myself fluent with django and it's quite shocking I had to put such an amount of effort just to validate many2many relationships before they are saved to the database.

IMHO it would be better if we could do one of these two (or even both) things:

  1. make this process easier in future django versions
  2. document the current best practice to solve this problem in current django to save people's time

What do people you think?

Here's my solution working with django 1.9:
https://github.com/openwisp/django-netjsonconfig/compare/4082988...dcdbbf4

What do you think of it? Can it be improved in some way?


Keep up the good work
Federico Capoano

Last edited 20 months ago by Federico Capoano (previous) (diff)

comment:4 Changed 7 months ago by Geoffrey Fairchild

This ticket was closed about 3 years ago. I just encountered this issue, and it's quite irritating. It definitely seems like something should be done about this. Can this be reopened?

Last edited 7 months ago by Geoffrey Fairchild (previous) (diff)

comment:5 Changed 7 months ago by Tim Graham

As I said in comment one, if there is some consensus about how to proceed, the ticket may be reopened.

Note: See TracTickets for help on using tickets.
Back to Top