Django3 serializer many to many

Hola,

Estoy haciendo una app (gnu) para bajarse las transacciones de un programa llamado Buxfer usando su api (*1) y no estoy logrando que me grabe los datos de una relación many to many. El codigo fuente de la app está en github (*1) pero igual lo coio abajo.

El problema está en el campo tags del modelo Transaction que es una relacion many to many con la tabla Tag. Cuando traigo las transacciones graba todo menos la tabla intermedia entre Transaction y Tag, pero no da ninguna excepción, solamente deja sin grabar esa tabla. En la api las tags vienen por nombre entonces yo las convierto a id para que se graben pero no he logrado que se graben.

models.py:

from django.db import models

Create your models here.

class ProjectBaseModel(models.Model):
“”“Base abstract model for all models used throughout the project.”""
## Basic time tracking for all models ##
time_created = models.DateTimeField(“created”, auto_now_add=True, db_index=True)
time_modified = models.DateTimeField(“modified”, auto_now=True, db_index=True)

class Meta:
    abstract = True

TRANSACTION_TYPES = {
(‘income’, ‘income’),
(‘expense’, ‘expense’),
(‘transfer’, ‘transfer’),
(‘refund’, ‘refund’),
(‘sharedBill’, ‘sharedBill’),
(‘paidForFriend’, ‘paidForFriend’),
(‘loan’, ‘loan’)
}

class Account(ProjectBaseModel):
id = models.IntegerField(primary_key=True)
name = models.CharField(max_length=200)
currency = models.CharField(max_length=3)
bank = models.CharField(max_length=200)
balance = models.FloatField()
lastSynced = models.DateTimeField(‘Last Sync’, blank=True, null=True)

def __str__(self):
    return f"{self.name}, id= {self.id}, currency= {self.currency} "

class Tag(ProjectBaseModel):
id = models.IntegerField(primary_key=True)
name = models.CharField(max_length=200)
parentId = models.IntegerField(blank=True, null=True)
relativeName = models.CharField(max_length=100)

def __str__(self):
    return f"{self.name}, id= {self.id} "

class TransactionType(ProjectBaseModel):
id = models.IntegerField(primary_key=True)
name = models.CharField(max_length=200)

class Transaction(ProjectBaseModel):
id = models.IntegerField(primary_key=True)
description = models.CharField(max_length=200)
#date = models.DateTimeField(‘Last Sync’, blank=True, null=True)
normalizedDate = models.DateField(‘Last Sync’, blank=True, null=True)
#type: “transfer”,
transactionType = models.ForeignKey(TransactionType, on_delete=models.CASCADE, related_name=‘transactions’)
#rawTransactionType: 6,
amount = models.FloatField()
expenseAmount = models.FloatField()
accountId = models.ForeignKey(Account, on_delete=models.CASCADE, related_name=‘transactions’, blank=True, null=True)
#accountName
tags = models.ManyToManyField(‘Tag’, related_name=‘transactions’)
status = models.CharField(max_length=200)
isFutureDated = models.BooleanField(blank=True)
isPending = models.BooleanField(blank=True)
sortDate = models.DateField(blank=True)
fromAccount = models.ForeignKey(Account, on_delete=models.CASCADE, related_name=‘transactionsFrom’, blank=True, null=True)
toAccount = models.ForeignKey(Account, on_delete=models.CASCADE, related_name=‘transactionsTo’, blank=True, null=True)

serializers.py:

from rest_framework import serializers
from rest_framework.fields import ReadOnlyField
from django.db.models import Q
import pprint
from .models import Account, Tag, TransactionType, Transaction

class AccountSerializer(serializers.ModelSerializer):
class Meta:
model = Account
fields = (‘id’, ‘name’, ‘currency’, ‘bank’, ‘balance’, ‘lastSynced’)

class TagSerializer(serializers.ModelSerializer):
class Meta:
model = Tag
fields = (‘id’, ‘name’, ‘parentId’, ‘relativeName’)

class TransactionTypeSerializer(serializers.ModelSerializer):
class Meta:
model = TransactionType
fields = (‘id’, ‘name’)

class TransactionSerializer(serializers.ModelSerializer):
tagNames = TagSerializer(read_only=True, many=True, source=‘tags’) # llamar a transactionserializer con many= True para que sea man to many

def to_internal_value(self, data):
    if data['tagNames']:
        tags_qs = Q()
        for tag in data['tagNames']:
            tags_qs = tags_qs | Q(name=tag)
        tag_objs = Tag.objects.filter(tags_qs)
        data['tagNames'] = [x.id for x in tag_objs]

    if 'fromAccount' in data and data['fromAccount']:
        data['fromAccount'] = data['fromAccount']['id']
    if 'toAccount' in data and data['toAccount']:
        data['toAccount'] = data['toAccount']['id']
    transaction_type = TransactionType.objects.filter(name=data['transactionType'])
    if not transaction_type:
        transaction_type = TransactionType(id=data['rawTransactionType'], name=data['transactionType'])
        transaction_type.save()
    else:
        transaction_type = transaction_type[0]
    try:
        data['transactionType'] = transaction_type.id
    except Exception as e:
        print(e)
    return super(TransactionSerializer, self).to_internal_value(data)

class Meta:
    model = Transaction
    fields = ('id', 'description', 'normalizedDate', 'transactionType', 'amount', 'expenseAmount', 'accountId', 'tagNames', 'status',
              'isFutureDated', 'isPending', 'sortDate', 'fromAccount', 'toAccount')

def create(self, validated_data):
    transaction = Transaction.objects.create(**validated_data)

    return transaction

(*1): https://www.buxfer.com/help/api
(*2): https://github.com/javiermarcon/buxfer_api_to_db

Gracias,

Javier.