Поле, связанное с полиморфной моделью Django

Я пытаюсь удалить повторяющийся код в своих моделях Django. Как вы можете видеть в приведенном ниже коде, единственная разница между send_salary_notification и send_pension_notifications заключается в том, что в одном используется связанное поле jurisdiction, а в другом — agency. Как я могу реорганизовать код, чтобы юрисдикция/агентство устанавливались один раз на основе record_type?

Я попытался создать переменную класса как record_type, и в этой первой функции установил переменную с cls.record_type = record_type, а затем это:

agencies_changed.append(subscription.record_type)

Но это дает ошибку, что record_type не является допустимым экземпляром.

Вот мой код:

class Subscriber(models.Model):
    email = models.EmailField(null=False, unique=True)
    activation_key = models.CharField(max_length=64)
    key_expires = models.DateTimeField(default=get_key_expiration)
    verified = models.BooleanField(default=False)

    @classmethod
    def send_notifications(cls, record_type, slugs):
        """
        Sends notifications for all subscribers.
        """
        subscribers = cls.objects.all()
        for subscriber in subscribers:
            if record_type == 'salary':
                subscriber.send_salary_notifications(slugs, record_type)
            elif record_type == 'pension':
                subscriber.send_pension_notifications(slugs, record_type)

    def send_salary_notifications(self, slugs, record_type):
        matching_subscriptions = self.get_matching_salary_subscriptions(slugs)
        agencies_changed = []

        if not matching_subscriptions:
            return None

        for subscription in matching_subscriptions:
            agencies_changed.append(subscription.jurisdiction)
            self.update_salary_last_year_sent(subscription)

        message = self.build_notification_message(agencies_changed, record_type)
        self.send_notification_email(message)

    def send_pension_notifications(self, slugs, record_type):
        matching_subscriptions = self.get_matching_pension_subscriptions(slugs)
        agencies_changed = []

        if not matching_subscriptions:
            return None

        for subscription in matching_subscriptions:
            agencies_changed.append(subscription.agency)
            self.update_pension_last_year_sent(subscription)

        message = self.build_notification_message(agencies_changed, record_type)
        self.send_notification_email(message)


class SalarySubscription(models.Model):
    subscriber = models.ForeignKey('subscriptions.Subscriber', related_name='salary_subscriptions')
    jurisdiction = models.ForeignKey('jurisdiction.Jurisdiction')
    last_year_sent = models.PositiveSmallIntegerField(null=True)


class PensionSubscription(models.Model):
    subscriber = models.ForeignKey('subscriptions.Subscriber', related_name='pension_subscriptions')
    agency = models.ForeignKey('pensions.Agency')
    last_year_sent = models.PositiveSmallIntegerField(null=True)
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
0
32
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Предполагая, что вы не хотите изменять методы get_matching_pension_subscriptions, get_matching_salary_subscriptions, update_salary_last_year_sent и update_pension_last_year_sent, вы можете реорганизовать свой код следующим образом. Вы можете определить один метод уведомления и динамически получать связанные атрибуты, используя встроенную функцию getattr в зависимости от record_type. Могут быть другие решения по рефакторингу, более подходящие для вашей кодовой базы, но видеть фрагмент кода, который вы опубликовали, это решение очень разумно.

class Subscriber(models.Model):
    @classmethod
    def send_notifications(cls, record_type, slugs):
        """
        Sends notifications for all subscribers.
        """
        subscribers = cls.objects.all()
        for subscriber in subscribers:
            subscriber._send_notification(record_type, slugs)

    def _send_notification(self, record_type, slugs):
        matching_subscriptions = getattr(self, 'get_matching_{}_subscriptions'.format(record_type))(slugs)
        if not matching_subscriptions:
            return None

        agencies_changed = []
        agency_attribute = {
            'salary': 'jurisdiction',
            'pension': 'agency'
        }[record_type]

        for subscription in matching_subscriptions:
            agencies_changed.append(getattr(subscription, agency_attribute))
            getattr(self, 'update_{}_last_year_sent'.format(record_type))(subscription)

        message = self.build_notification_message(agencies_changed, record_type)
        self.send_notification_email(message)

Другие вопросы по теме