Добавить в мое поле регистрации с отношением ManyToMany в Django - PullRequest
0 голосов
/ 28 января 2020

Написан пользовательский логгер, он используется при редактировании или модификации объектов. Появилось поле с отношением «многие ко многим», и его изменение не отображается. Как это можно исправить?

Код обработчика:

class BaseLog(metaclass=ABCMeta):
    def __init__(self, instance, created):
        self.diff = {}

        self.created = created

        self.new_instance = instance
        self.old_instance = self._get_object(instance.id)

        self.fields = self._get_fields()

    def update_diff(self, field, new, old=None):
        print(old)
        if old is None:
            self.diff[field] = new
        else:
            if old != new:
                self.diff[field] = (old, new)

    def get_diff(self):
        for field in self.fields:
            if self.old_instance is not None:
                self.update_diff(
                   field[0],
                   getattr(self.new_instance, field[1]),
                   getattr(self.old_instance, field[1]),
                )
            else:
                self.update_diff(field[0], getattr(self.new_instance, field[1]))

        return self.diff

    @abstractmethod
    def _get_object(self, obj_id):
        pass

    @abstractmethod
    def _get_fields(self):
        pass

Код для моей модели:

class ServiceLog(BaseLog):
    def _get_object(self, obj_id):
        if self.created:
            return None

        try:
            return Service.objects.get(id=obj_id)
        except Service.DoesNotExist:
            return None

    def _get_fields(self):
        return [
            ('flow', 'flow_name'),
            ('currency', 'currency_iso_name'),
            ('contractor', 'contractor_name'),
            ('amount', 'amount'),
            ('callback_url', 'callback_url'),
            ('definition', 'definition'),
            ('description', 'description'),
            ('charge_strategy', 'charge_strategy'),
            ('routine', 'routine'),
            ('service_keys', 'service_keys')
        ]

Сохранить запись:

@receiver([pre_save_with_user, post_save_with_user])
    def logger_update_callback(sender, **kwargs):
        is_created = kwargs['created']
        if sender == Service:
            obj_log = ServiceLog(kwargs['instance'], is_created)
        elif sender == Deal:
            obj_log = DealLog(kwargs['instance'], is_created)
        else:
            raise NotImplementedError(
                'Logs for the model {} are not implemented'.format(sender)
            )

        log_record = {'who': str(kwargs.get('user', None)), 'what_model': sender.__name__,
                      'what_str': str(kwargs['instance']), 'what_id': kwargs['instance'].id, 'is_created': is_created,
                      'diff': obj_log.get_diff()}

        if log_record['diff']:
            log = Log.objects.create(**log_record)
            log.save()
        else:
            pass

Model.py:

class Service(models.Model):
    flow = models.ForeignKey(
        Flow,
        on_delete=models.CASCADE,
        related_name='services_flows'
    )
    currency = models.ForeignKey(
        Currency,
        on_delete=models.CASCADE,
        related_name='services_currencies'
    )
    contractor = models.ForeignKey(
        Contractor,
        on_delete=models.CASCADE,
        related_name='services_contractors',
    )
    amount = models.IntegerField(default=0)
    callback_url = models.CharField(
        max_length=128,
        blank=True,
        null=True,
        default=None,
    )
    definition = JSONField(null=True, blank=True, default=dict())
    name = models.CharField(max_length=255, db_index=True)
    description = models.TextField(null=True, blank=True)
    charge_strategy = models.CharField(max_length=64, default='default')
    routine = JSONField(null=True, blank=True, default=dict())
    service_keys = models.ManyToManyField(ApiKey, through='ServiceKey')

    @property
    def currency_iso_name(self):
        return str(self.currency)

    @property
    def contractor_name(self):
        return str(self.contractor)

    @property
    def flow_name(self):
        return str(self.flow)

    @signal_sending(pre_save_with_user, post_save_with_user)
    def save(self, *args, **kwargs):
        super(Service, self).save(*args, **kwargs)

    def __str__(self):
        return '{}'.format(self.name)

    def __repr__(self):
        return self.name

Промежуточная таблица:

class ServiceKey(models.Model):
    service = models.ForeignKey(
        Service,
        on_delete=models.CASCADE,
        related_name='service',
        null=False,
        primary_key=True
    )
    key = models.ForeignKey(
        ApiKey,
        on_delete=models.CASCADE,
        related_name='apikey',
        null=False
    )

    class Meta:
        unique_together = (('service', 'key'),)

Корректная работа:

Снимок экрана с отображением нового объекта

Когда я взаимодействую только с полем servicekey:

Снимок экрана с некорректной работой

UPD: Я нашел информацию о m2m_change, но не могу отправить сигнал.

Мой код:

@receiver(m2m_changed, sender=Service.service_keys.through)
def logger_callback2(sender, **kwargs):
    print('M2MSIGNAL')
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...