首页 > 解决方案 > 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)

标签: pythondjangodjango-models

解决方案


假设您不想更改get_matching_pension_subscriptionsget_matching_salary_subscriptions和方法update_salary_last_year_sentupdate_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)

推荐阅读