Python django.db.models.ManyToManyField() Examples
The following are 30 code examples for showing how to use django.db.models.ManyToManyField(). These examples are extracted from open source projects. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example.
You may check out the related API usage on the sidebar.
You may also want to check out all available functions/classes of the module
django.db.models
, or try the search function
.
Example 1
Project: django-idcops Author: Wenvki File: models.py License: Apache License 2.0 | 6 votes |
def _dict(self): exclude = ['operator_id', 'creator_id', 'created', 'modified'] opts = self._meta data = {} keys = [f.attname for f in opts.fields] for f in chain(opts.many_to_many): #if isinstance(f, models.ManyToManyField): if self.pk is None: data[f.name] = [] else: data[f.name] = list(f.value_from_object(self).values_list('pk', flat=True)) original = { k:self.__dict__.get(k) for k in keys if k not in exclude } data.update(**original) for key, value in data.items(): if isinstance(value, timezone.datetime): value = formats.localize(timezone.template_localtime(value)) data.update(**{key: value}) return data
Example 2
Project: GTDWeb Author: lanbing510 File: related.py License: GNU General Public License v2.0 | 6 votes |
def __set__(self, instance, value): if not self.related.field.rel.through._meta.auto_created: opts = self.related.field.rel.through._meta raise AttributeError( "Cannot set values on a ManyToManyField which specifies an " "intermediary model. Use %s.%s's Manager instead." % (opts.app_label, opts.object_name) ) # Force evaluation of `value` in case it's a queryset whose # value could be affected by `manager.clear()`. Refs #19816. value = tuple(value) manager = self.__get__(instance) db = router.db_for_write(manager.through, instance=manager.instance) with transaction.atomic(using=db, savepoint=False): manager.clear() manager.add(*value)
Example 3
Project: GTDWeb Author: lanbing510 File: related.py License: GNU General Public License v2.0 | 6 votes |
def __set__(self, instance, value): if not self.field.rel.through._meta.auto_created: opts = self.field.rel.through._meta raise AttributeError( "Cannot set values on a ManyToManyField which specifies an " "intermediary model. Use %s.%s's Manager instead." % (opts.app_label, opts.object_name) ) # Force evaluation of `value` in case it's a queryset whose # value could be affected by `manager.clear()`. Refs #19816. value = tuple(value) manager = self.__get__(instance) db = router.db_for_write(manager.through, instance=manager.instance) with transaction.atomic(using=db, savepoint=False): manager.clear() manager.add(*value)
Example 4
Project: GTDWeb Author: lanbing510 File: related.py License: GNU General Public License v2.0 | 6 votes |
def _check_ignored_options(self, **kwargs): warnings = [] if self.null: warnings.append( checks.Warning( 'null has no effect on ManyToManyField.', hint=None, obj=self, id='fields.W340', ) ) if len(self._validators) > 0: warnings.append( checks.Warning( 'ManyToManyField does not support validators.', hint=None, obj=self, id='fields.W341', ) ) return warnings
Example 5
Project: GTDWeb Author: lanbing510 File: validation.py License: GNU General Public License v2.0 | 6 votes |
def validate_list_display(self, cls, model): " Validate that list_display only contains fields or usable attributes. " if hasattr(cls, 'list_display'): check_isseq(cls, 'list_display', cls.list_display) for idx, field in enumerate(cls.list_display): if not callable(field): if not hasattr(cls, field): if not hasattr(model, field): try: model._meta.get_field(field) except FieldDoesNotExist: raise ImproperlyConfigured( "%s.list_display[%d], %r is not a callable or " "an attribute of %r or found in the model %r." % (cls.__name__, idx, field, cls.__name__, model._meta.object_name) ) else: # getattr(model, field) could be an X_RelatedObjectsDescriptor f = fetch_attr(cls, model, "list_display[%d]" % idx, field) if isinstance(f, models.ManyToManyField): raise ImproperlyConfigured( "'%s.list_display[%d]', '%s' is a ManyToManyField " "which is not supported." % (cls.__name__, idx, field) )
Example 6
Project: FIR Author: certsocietegenerale File: decorator.py License: GNU General Public License v3.0 | 6 votes |
def has_perm(self, user, permission): if user.is_superuser: return True if isinstance(permission, six.string_types): permission = [permission, ] if user.has_perms(permission): return True if self._authorization_meta.owner_field and self._authorization_meta.owner_permission and \ self._authorization_meta.owner_permission in permission and \ user.pk == getattr(self, self._authorization_meta.owner_field).pk: return True paths = self._authorization_meta.model.get_authorization_paths(user, permission) if not paths.count(): return False for field in self._authorization_meta.fields: f = self._meta.get_field(field) relation = getattr(self, field) if isinstance(f, models.ManyToManyField): qs_filter = reduce(lambda x, y: x | y, [Q(path__startswith=path) for path in paths]) if relation.filter(qs_filter).distinct().exists(): return True elif isinstance(f, models.ForeignKey): if relation is not None and any(relation.path.startswith(p) for p in paths): return True return False
Example 7
Project: bioforum Author: reBiocoder File: checks.py License: MIT License | 6 votes |
def _check_prepopulated_fields_key(self, obj, model, field_name, label): """ Check a key of `prepopulated_fields` dictionary, i.e. check that it is a name of existing field and the field is one of the allowed types. """ try: field = model._meta.get_field(field_name) except FieldDoesNotExist: return refer_to_missing_field(field=field_name, option=label, model=model, obj=obj, id='admin.E027') else: if isinstance(field, (models.DateTimeField, models.ForeignKey, models.ManyToManyField)): return [ checks.Error( "The value of '%s' refers to '%s', which must not be a DateTimeField, " "a ForeignKey, a OneToOneField, or a ManyToManyField." % (label, field_name), obj=obj.__class__, id='admin.E028', ) ] else: return []
Example 8
Project: StormOnline Author: stormsha File: edit.py License: Apache License 2.0 | 5 votes |
def formfield_for_dbfield(self, db_field, **kwargs): # If it uses an intermediary model that isn't auto created, don't show # a field in admin. if isinstance(db_field, models.ManyToManyField) and not db_field.rel.through._meta.auto_created: return None attrs = self.get_field_attrs(db_field, **kwargs) return db_field.formfield(**dict(attrs, **kwargs))
Example 9
Project: StormOnline Author: stormsha File: edit.py License: Apache License 2.0 | 5 votes |
def get_field_style(self, db_field, style, **kwargs): if style in ('radio', 'radio-inline') and (db_field.choices or isinstance(db_field, models.ForeignKey)): attrs = {'widget': widgets.AdminRadioSelect( attrs={'inline': 'inline' if style == 'radio-inline' else ''})} if db_field.choices: attrs['choices'] = db_field.get_choices( include_blank=db_field.blank, blank_choice=[('', _('Null'))] ) return attrs if style in ('checkbox', 'checkbox-inline') and isinstance(db_field, models.ManyToManyField): return {'widget': widgets.AdminCheckboxSelect(attrs={'inline': style == 'checkbox-inline'}), 'help_text': None}
Example 10
Project: StormOnline Author: stormsha File: edit.py License: Apache License 2.0 | 5 votes |
def get_form_datas(self): # Prepare the dict of initial data from the request. # We have to special-case M2Ms as a list of comma-separated PKs. if self.request_method == 'get': initial = dict(self.request.GET.items()) for k in initial: try: f = self.opts.get_field(k) except models.FieldDoesNotExist: continue if isinstance(f, models.ManyToManyField): initial[k] = initial[k].split(",") return {'initial': initial} else: return {'data': self.request.POST, 'files': self.request.FILES}
Example 11
Project: StormOnline Author: stormsha File: multiselect.py License: Apache License 2.0 | 5 votes |
def get_field_style(self, attrs, db_field, style, **kwargs): if style == 'm2m_transfer' and isinstance(db_field, ManyToManyField): return {'widget': SelectMultipleTransfer(db_field.verbose_name, False), 'help_text': ''} if style == 'm2m_dropdown' and isinstance(db_field, ManyToManyField): return {'widget': SelectMultipleDropdown, 'help_text': ''} return attrs
Example 12
Project: StormOnline Author: stormsha File: quickform.py License: Apache License 2.0 | 5 votes |
def formfield_for_dbfield(self, formfield, db_field, **kwargs): if formfield and self.model in self.admin_site._registry and isinstance(db_field, (models.ForeignKey, models.ManyToManyField)): rel_model = get_model_from_relation(db_field) if rel_model in self.admin_site._registry and self.has_model_perm(rel_model, 'add'): add_url = self.get_model_url(rel_model, 'add') formfield.widget = RelatedFieldWidgetWrapper( formfield.widget, db_field.rel, add_url, self.get_model_url(self.model, 'add')) return formfield
Example 13
Project: resolwe Author: genialis File: builder.py License: Apache License 2.0 | 5 votes |
def _connect_signal(self, index): """Create signals for building indexes.""" post_save_signal = ElasticSignal(index, "build") post_save_signal.connect(post_save, sender=index.object_type) self.signals.append(post_save_signal) post_delete_signal = ElasticSignal(index, "remove_object") post_delete_signal.connect(post_delete, sender=index.object_type) self.signals.append(post_delete_signal) # Connect signals for all dependencies. for dependency in index.get_dependencies(): # Automatically convert m2m fields to dependencies. if isinstance(dependency, (models.ManyToManyField, ManyToManyDescriptor)): dependency = ManyToManyDependency(dependency) elif isinstance(dependency, ReverseManyToOneDescriptor): dependency = ReverseManyToOneDependency(dependency) elif isinstance(dependency, ForwardManyToOneDescriptor): dependency = ForwardManyToOneDependency(dependency) elif not isinstance(dependency, Dependency): raise TypeError( "Unsupported dependency type: {}".format(repr(dependency)) ) signal = dependency.connect(index) self.signals.extend(signal)
Example 14
Project: django-idcops Author: Wenvki File: edit.py License: Apache License 2.0 | 5 votes |
def get_form_kwargs(self): kwargs = super(NewModelView, self).get_form_kwargs() params = self.request.GET.dict() mfields = [f.attname for f in self.opts.fields] for k in params.keys(): if k in mfields: kwargs.update({k: params[k]}) related_models = [] for f in self.opts.get_fields(): if isinstance(f, (models.ForeignKey, models.ManyToManyField)): if f.related_model: related_models.append(f.related_model) if User in related_models: kwargs.update({'user': self.request.user}) return kwargs
Example 15
Project: django-idcops Author: Wenvki File: edit.py License: Apache License 2.0 | 5 votes |
def get_form_kwargs(self): kwargs = super(EditModelView, self).get_form_kwargs() params = self.request.GET.dict() mfields = [f.attname for f in self.opts.fields] for k in params.keys(): if k in mfields: kwargs.update({k: params[k]}) related_models = [] for f in self.opts.get_fields(): if isinstance(f, (models.ForeignKey, models.ManyToManyField)): if f.related_model: related_models.append(f.related_model) if User in related_models: kwargs.update({'user': self.request.user}) return kwargs
Example 16
Project: django-angularjs-blog Author: bluedazzle File: test_Serializer.py License: BSD 2-Clause "Simplified" License | 5 votes |
def setUp(self): self.time_func = TimeFormatFactory.get_time_func('string') # DATABASES = { # 'default': { # 'ENGINE': 'django.db.backends.sqlite3', # 'NAME': ':memory:', # 'USER': '', # Not used with sqlite3. # 'PASSWORD': '', # Not used with sqlite3. # 'HOST': '', # Set to empty string for localhost. Not used with sqlite3. # 'PORT': '', # } # } # settings.configure(DATABASES=DATABASES, DEBUG=True) # class TestAuthor(models.Model): # name = models.CharField(default='test_author') # # def __unicode__(self): # return self.name # # class TestTags(models.Model): # tag = models.CharField(default='test_tag') # create_time = models.DateTimeField(auto_now=True) # # class TestArticle(models.Model): # title = models.CharField(default='test') # content = models.CharField(default='test') # author = models.ForeignKey(TestAuthor, related_name='author_art') # tags = models.ManyToManyField(TestTags, related_name='tag_art') # create_time = models.DateTimeField(auto_now=True) # # # self.author = TestAuthor() # self.author.save() # tags = TestTags(tag='tag1') # tags.save() # self.article = TestArticle(author=self.author) # self.article.tags.add(tags) # self.article.save()
Example 17
Project: GTDWeb Author: lanbing510 File: autodetector.py License: GNU General Public License v2.0 | 5 votes |
def _generate_added_field(self, app_label, model_name, field_name): field = self.new_apps.get_model(app_label, model_name)._meta.get_field(field_name) # Fields that are foreignkeys/m2ms depend on stuff dependencies = [] if field.rel and field.rel.to: # Account for FKs to swappable models swappable_setting = getattr(field, 'swappable_setting', None) if swappable_setting is not None: dep_app_label = "__setting__" dep_object_name = swappable_setting else: dep_app_label = field.rel.to._meta.app_label dep_object_name = field.rel.to._meta.object_name dependencies = [(dep_app_label, dep_object_name, None, True)] if getattr(field.rel, "through", None) and not field.rel.through._meta.auto_created: dependencies.append(( field.rel.through._meta.app_label, field.rel.through._meta.object_name, None, True, )) # You can't just add NOT NULL fields with no default or fields # which don't allow empty strings as default. preserve_default = True if (not field.null and not field.has_default() and not isinstance(field, models.ManyToManyField) and not (field.blank and field.empty_strings_allowed)): field = field.clone() field.default = self.questioner.ask_not_null_addition(field_name, model_name) preserve_default = False self.add_operation( app_label, operations.AddField( model_name=model_name, name=field_name, field=field, preserve_default=preserve_default, ), dependencies=dependencies, )
Example 18
Project: GTDWeb Author: lanbing510 File: related.py License: GNU General Public License v2.0 | 5 votes |
def __init__(self, to, db_constraint=True, swappable=True, **kwargs): try: to._meta except AttributeError: # to._meta doesn't exist, so it must be RECURSIVE_RELATIONSHIP_CONSTANT assert isinstance(to, six.string_types), ( "%s(%r) is invalid. First parameter to ManyToManyField must be " "either a model, a model name, or the string %r" % (self.__class__.__name__, to, RECURSIVE_RELATIONSHIP_CONSTANT) ) # Class names must be ASCII in Python 2.x, so we forcibly coerce it # here to break early if there's a problem. to = str(to) kwargs['verbose_name'] = kwargs.get('verbose_name', None) kwargs['rel'] = ManyToManyRel( self, to, related_name=kwargs.pop('related_name', None), related_query_name=kwargs.pop('related_query_name', None), limit_choices_to=kwargs.pop('limit_choices_to', None), symmetrical=kwargs.pop('symmetrical', to == RECURSIVE_RELATIONSHIP_CONSTANT), through=kwargs.pop('through', None), through_fields=kwargs.pop('through_fields', None), db_constraint=db_constraint, ) self.swappable = swappable self.db_table = kwargs.pop('db_table', None) if kwargs['rel'].through is not None: assert self.db_table is None, "Cannot specify a db_table if an intermediary model is used." super(ManyToManyField, self).__init__(**kwargs)
Example 19
Project: GTDWeb Author: lanbing510 File: related.py License: GNU General Public License v2.0 | 5 votes |
def deconstruct(self): name, path, args, kwargs = super(ManyToManyField, self).deconstruct() # Handle the simpler arguments if self.db_table is not None: kwargs['db_table'] = self.db_table if self.rel.db_constraint is not True: kwargs['db_constraint'] = self.rel.db_constraint if self.rel.related_name is not None: kwargs['related_name'] = self.rel.related_name if self.rel.related_query_name is not None: kwargs['related_query_name'] = self.rel.related_query_name # Rel needs more work. if isinstance(self.rel.to, six.string_types): kwargs['to'] = self.rel.to else: kwargs['to'] = "%s.%s" % (self.rel.to._meta.app_label, self.rel.to._meta.object_name) if getattr(self.rel, 'through', None) is not None: if isinstance(self.rel.through, six.string_types): kwargs['through'] = self.rel.through elif not self.rel.through._meta.auto_created: kwargs['through'] = "%s.%s" % (self.rel.through._meta.app_label, self.rel.through._meta.object_name) # If swappable is True, then see if we're actually pointing to the target # of a swap. swappable_setting = self.swappable_setting if swappable_setting is not None: # If it's already a settings reference, error if hasattr(kwargs['to'], "setting_name"): if kwargs['to'].setting_name != swappable_setting: raise ValueError( "Cannot deconstruct a ManyToManyField pointing to a " "model that is swapped in place of more than one model " "(%s and %s)" % (kwargs['to'].setting_name, swappable_setting) ) # Set it from django.db.migrations.writer import SettingsReference kwargs['to'] = SettingsReference( kwargs['to'], swappable_setting, ) return name, path, args, kwargs
Example 20
Project: GTDWeb Author: lanbing510 File: related.py License: GNU General Public License v2.0 | 5 votes |
def contribute_to_class(self, cls, name, **kwargs): # To support multiple relations to self, it's useful to have a non-None # related name on symmetrical relations for internal reasons. The # concept doesn't make a lot of sense externally ("you want me to # specify *what* on my non-reversible relation?!"), so we set it up # automatically. The funky name reduces the chance of an accidental # clash. if self.rel.symmetrical and (self.rel.to == "self" or self.rel.to == cls._meta.object_name): self.rel.related_name = "%s_rel_+" % name super(ManyToManyField, self).contribute_to_class(cls, name, **kwargs) # The intermediate m2m model is not auto created if: # 1) There is a manually specified intermediate, or # 2) The class owning the m2m field is abstract. # 3) The class owning the m2m field has been swapped out. if not self.rel.through and not cls._meta.abstract and not cls._meta.swapped: self.rel.through = create_many_to_many_intermediary_model(self, cls) # Add the descriptor for the m2m relation setattr(cls, self.name, ReverseManyRelatedObjectsDescriptor(self)) # Set up the accessor for the m2m table name for the relation self.m2m_db_table = curry(self._get_m2m_db_table, cls._meta) # Populate some necessary rel arguments so that cross-app relations # work correctly. if isinstance(self.rel.through, six.string_types): def resolve_through_model(field, model, cls): field.rel.through = model add_lazy_relation(cls, self, self.rel.through, resolve_through_model)
Example 21
Project: GTDWeb Author: lanbing510 File: related.py License: GNU General Public License v2.0 | 5 votes |
def formfield(self, **kwargs): db = kwargs.pop('using', None) defaults = { 'form_class': forms.ModelMultipleChoiceField, 'queryset': self.rel.to._default_manager.using(db), } defaults.update(kwargs) # If initial is passed in, it's a list of related objects, but the # MultipleChoiceField takes a list of IDs. if defaults.get('initial') is not None: initial = defaults['initial'] if callable(initial): initial = initial() defaults['initial'] = [i._get_pk_val() for i in initial] return super(ManyToManyField, self).formfield(**defaults)
Example 22
Project: GTDWeb Author: lanbing510 File: related.py License: GNU General Public License v2.0 | 5 votes |
def db_type(self, connection): # A ManyToManyField is not represented by a single column, # so return None. return None
Example 23
Project: GTDWeb Author: lanbing510 File: checks.py License: GNU General Public License v2.0 | 5 votes |
def _check_field_spec_item(self, cls, model, field_name, label): if field_name in cls.readonly_fields: # Stuff can be put in fields that isn't actually a model field if # it's in readonly_fields, readonly_fields will handle the # validation of such things. return [] else: try: field = model._meta.get_field(field_name) except FieldDoesNotExist: # If we can't find a field on the model that matches, it could # be an extra field on the form. return [] else: if (isinstance(field, models.ManyToManyField) and not field.rel.through._meta.auto_created): return [ checks.Error( ("The value of '%s' cannot include the ManyToManyField '%s', " "because that field manually specifies a relationship model.") % (label, field_name), hint=None, obj=cls, id='admin.E013', ) ] else: return []
Example 24
Project: GTDWeb Author: lanbing510 File: checks.py License: GNU General Public License v2.0 | 5 votes |
def _check_filter_item(self, cls, model, field_name, label): """ Check one item of `filter_vertical` or `filter_horizontal`, i.e. check that given field exists and is a ManyToManyField. """ try: field = model._meta.get_field(field_name) except FieldDoesNotExist: return refer_to_missing_field(field=field_name, option=label, model=model, obj=cls, id='admin.E019') else: if not isinstance(field, models.ManyToManyField): return must_be('a ManyToManyField', option=label, obj=cls, id='admin.E020') else: return []
Example 25
Project: GTDWeb Author: lanbing510 File: checks.py License: GNU General Public License v2.0 | 5 votes |
def _check_prepopulated_fields_key(self, cls, model, field_name, label): """ Check a key of `prepopulated_fields` dictionary, i.e. check that it is a name of existing field and the field is one of the allowed types. """ forbidden_field_types = ( models.DateTimeField, models.ForeignKey, models.ManyToManyField ) try: field = model._meta.get_field(field_name) except FieldDoesNotExist: return refer_to_missing_field(field=field_name, option=label, model=model, obj=cls, id='admin.E027') else: if isinstance(field, forbidden_field_types): return [ checks.Error( "The value of '%s' refers to '%s', which must not be a DateTimeField, " "ForeignKey or ManyToManyField." % ( label, field_name ), hint=None, obj=cls, id='admin.E028', ) ] else: return []
Example 26
Project: GTDWeb Author: lanbing510 File: options.py License: GNU General Public License v2.0 | 5 votes |
def get_changeform_initial_data(self, request): """ Get the initial form data. Unless overridden, this populates from the GET params. """ initial = dict(request.GET.items()) for k in initial: try: f = self.model._meta.get_field(k) except FieldDoesNotExist: continue # We have to special-case M2Ms as a list of comma-separated PKs. if isinstance(f, models.ManyToManyField): initial[k] = initial[k].split(",") return initial
Example 27
Project: GTDWeb Author: lanbing510 File: validation.py License: GNU General Public License v2.0 | 5 votes |
def check_field_spec(self, cls, model, flds, label): """ Validate the fields specification in `flds` from a ModelAdmin subclass `cls` for the `model` model. Use `label` for reporting problems to the user. The fields specification can be a ``fields`` option or a ``fields`` sub-option from a ``fieldsets`` option component. """ for fields in flds: # The entry in fields might be a tuple. If it is a standalone # field, make it into a tuple to make processing easier. if type(fields) != tuple: fields = (fields,) for field in fields: if field in cls.readonly_fields: # Stuff can be put in fields that isn't actually a # model field if it's in readonly_fields, # readonly_fields will handle the validation of such # things. continue try: f = model._meta.get_field(field) except FieldDoesNotExist: # If we can't find a field on the model that matches, it could be an # extra field on the form; nothing to check so move on to the next field. continue if isinstance(f, models.ManyToManyField) and not f.rel.through._meta.auto_created: raise ImproperlyConfigured("'%s.%s' " "can't include the ManyToManyField field '%s' because " "'%s' manually specifies a 'through' model." % ( cls.__name__, label, field, field))
Example 28
Project: GTDWeb Author: lanbing510 File: validation.py License: GNU General Public License v2.0 | 5 votes |
def validate_raw_id_fields(self, cls, model): " Validate that raw_id_fields only contains field names that are listed on the model. " if hasattr(cls, 'raw_id_fields'): check_isseq(cls, 'raw_id_fields', cls.raw_id_fields) for idx, field in enumerate(cls.raw_id_fields): f = get_field(cls, model, 'raw_id_fields', field) if not isinstance(f, (models.ForeignKey, models.ManyToManyField)): raise ImproperlyConfigured("'%s.raw_id_fields[%d]', '%s' must " "be either a ForeignKey or ManyToManyField." % (cls.__name__, idx, field))
Example 29
Project: GTDWeb Author: lanbing510 File: validation.py License: GNU General Public License v2.0 | 5 votes |
def validate_filter_vertical(self, cls, model): " Validate that filter_vertical is a sequence of field names. " if hasattr(cls, 'filter_vertical'): check_isseq(cls, 'filter_vertical', cls.filter_vertical) for idx, field in enumerate(cls.filter_vertical): f = get_field(cls, model, 'filter_vertical', field) if not isinstance(f, models.ManyToManyField): raise ImproperlyConfigured("'%s.filter_vertical[%d]' must be " "a ManyToManyField." % (cls.__name__, idx))
Example 30
Project: GTDWeb Author: lanbing510 File: validation.py License: GNU General Public License v2.0 | 5 votes |
def validate_filter_horizontal(self, cls, model): " Validate that filter_horizontal is a sequence of field names. " if hasattr(cls, 'filter_horizontal'): check_isseq(cls, 'filter_horizontal', cls.filter_horizontal) for idx, field in enumerate(cls.filter_horizontal): f = get_field(cls, model, 'filter_horizontal', field) if not isinstance(f, models.ManyToManyField): raise ImproperlyConfigured("'%s.filter_horizontal[%d]' must be " "a ManyToManyField." % (cls.__name__, idx))