2

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

Martin Gergov
  • 1,556
  • 4
  • 20
  • 29

0 Answers0