Code

Opened 5 years ago

Closed 5 years ago

Last modified 5 years ago

#11310 closed (worksforme)

Unable to serialize ManyToMany fields with "trough"

Reported by: Pavel Schön <pavel@…> Owned by: nobody
Component: Core (Serialization) Version: master
Severity: Keywords: ManyToMany
Cc: Triage Stage: Unreviewed
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: UI/UX:

Description

Problem is, that ManyToMany field with intermediate table is ignored in PythonSerializer. This patch should fix it.

http://code.djangoproject.com/svn/django/trunk/django/core/serializers/python.py
59,61c59,60
<         if field.creates_table:
<             self._current[field.name] = [smart_unicode(related._get_pk_val(), strings_only=True)
<                                for related in getattr(obj, field.name).iterator()]
---
>         self._current[field.name] = [smart_unicode(related._get_pk_val(), strings_only=True)
>             for related in getattr(obj, field.name).iterator()]

Attachments (0)

Change History (6)

comment:1 Changed 5 years ago by Pavel Schön <pavel@…>

  • Component changed from Uncategorized to Serialization
  • Has patch set
  • Keywords ManyToMany added
  • Needs documentation unset
  • Needs tests unset
  • Patch needs improvement unset

comment:2 Changed 5 years ago by russellm

  • Resolution set to worksforme
  • Status changed from new to closed

The test suite contains a test to validate that serialization works for m2m with a through field (see the [http://code.djangoproject.com/browser/django/trunk/tests/regressiontests/m2m_through_regress/models.py regressiontests/m2m_through_regress tests). Without a test case showing a specific failure case I'm going to mark this worksforme.

comment:3 Changed 5 years ago by pavel@…

  • Resolution worksforme deleted
  • Status changed from closed to reopened
  • Version changed from 1.0 to SVN

Hi,
look at this example:

class A(models.Model):
        foo = models.CharField(max_length=32)
#       b = models.ManyToManyField('B', through='A_B')
        b = models.ManyToManyField('B')

class B(models.Model):
        bar = models.CharField(max_length=32)

class A_B(models.Model):
        a = models.ForeignKey('A')
        b = models.ForeignKey('B')

Then i run:

>>> from django.core.serializers import serialize
>>> serialize('python', A.objects.all())
[{'pk': 1L, 'model': u'testapp.a', 'fields': {'foo': u'eeeee', 'b': [1L]}}]

This is OK.

Now I change models to this:

class A(models.Model):
        foo = models.CharField(max_length=32)
        b = models.ManyToManyField('B', through='A_B')
#       b = models.ManyToManyField('B')

class B(models.Model):
        bar = models.CharField(max_length=32)

class A_B(models.Model):
        a = models.ForeignKey('A')
        b = models.ForeignKey('B')

I serialize it:

>>> from django.core.serializers import serialize
>>> serialize('python', A.objects.all())
[{'pk': 1L, 'model': u'testapp.a', 'fields': {'foo': u'eeeee'}}]

'b' is missing in output...

comment:4 Changed 5 years ago by russellm

  • Resolution set to worksforme
  • Status changed from reopened to closed

Your example code is explicitly serializing objects of type A. However, when you have a through relationship, you need to serialize the A_B model separately, since that model could contain extra data.

When you don't have a through model, there isn't an actual model representing the through relationship., so the m2m data is included on the A model as a list of related objects.

comment:5 Changed 5 years ago by pavel@…

Thanks for explanation. I was migrating some models without 'through' to use 'through' and serialization behaviour was changed. I made a wraparound of this using custom serializer:

class CustomSerializer(python.Serializer):
	def handle_m2m_field(self, obj, field):
		field.creates_table = True
		super(XMLRPCSerializer, self).handle_m2m_field(obj, field)

Yeah, it's ugly, but it works ;-)

comment:6 Changed 5 years ago by pavel@…

s/XMLRPCSerializer/CustomSerializer/g

Add Comment

Modify Ticket

Change Properties
<Author field>
Action
as closed
as The resolution will be set. Next status will be 'closed'
The resolution will be deleted. Next status will be 'new'
Author


E-mail address and user name can be saved in the Preferences.

 
Note: See TracTickets for help on using tickets.