I'm upgrade django from 1.8.4 to 1.11.6 and encountered problem. I have two models:
from django.db import models
class File(models.Model):
title = models.CharField(max_length=128, verbose_name=_('title'))
description = models.CharField(
max_length=255, blank=True, null=True, verbose_name=_('description')
)
class Task(models.Model):
output_data = models.ManyToManyField(
File, blank=True, verbose_name=_('output_data')
)
I'm running manage.py loaddata with the following data for models above:
files.json:
[ { "fields": { "description": "", "title": "Data file 2", }, "model": "files.file", "pk": 2 } ]
tasks.json:
[ { "fields": { "output_data": [2] }, "model": "tasks.task", "pk": 1 } ]
loaddata creates file and task, but not create m2m relation. Before the update everything worked fine.
UPD: I found where loaddata create m2m relation: local/lib/python2.7/site-packages/django/db/models/fields/related_descriptors.py:972, method set:
def set(self, objs, **kwargs):
if not rel.through._meta.auto_created:
opts = self.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 `objs` in case it's a queryset whose value
# could be affected by `manager.clear()`. Refs #19816.
objs = tuple(objs)
clear = kwargs.pop('clear', False)
db = router.db_for_write(self.through, instance=self.instance)
with transaction.atomic(using=db, savepoint=False):
if clear:
self.clear()
self.add(*objs)
else:
old_ids = set(self.using(db).values_list(self.target_field.target_field.attname, flat=True))
new_objs = []
for obj in objs:
fk_val = (
self.target_field.get_foreign_related_value(obj)[0]
if isinstance(obj, self.model) else obj
)
if fk_val in old_ids:
old_ids.remove(fk_val)
else:
new_objs.append(obj)
self.remove(*old_ids)
self.add(*new_objs)
I understand what is happening here, but I do not see the logic in what is happening. If someone knows why this is happening, please explain to me. Thanks