Django验证电子邮件外键。

3

我有这个个人资料资源:

class ProfileResource(resources.ModelResource):
    email = fields.Field(attribute='email', 
        widget=CharWidget(), 
        column_name='email')

    class Meta:
        model = Profile
        clean_model_instances = True
        import_id_fields = ('email',)

在创建配置文件时,会验证电子邮件地址的有效性。这个功能运行良好,但当我将其用作外键时,如下所示:

class InvestmentResource(resources.ModelResource):
    email = fields.Field(attribute='email', 
        widget=ForeignKeyWidget(Profile, field='email'), 
        column_name='email')

    class Meta:
        model = Investment
        clean_model_instances = True
        import_id_fields = ('id',)

    def before_import_row(self, row, row_number=None, **kwargs):
        self.email = row["email"]
        self.profile__firstname = row["firstname"]
        self.profile__lastname = row["lastname"]

    def after_import_instance(self, instance, new, row_number=None, **kwargs):
        """
        Create any missing Profile entries prior to importing rows.
        """
        try:
            profile, created = Profile.objects.get_or_create(email=self.email)

            profile.firstname = self.profile__firstname
            profile.lastname = self.profile__lastname
            profile.save()

            instance.profile = profile

        except Exception as e:
            print(e, file=sys.stderr)

现在不再验证电子邮件。我尝试为InvestmentResource上的电子邮件添加两个小部件,ForeignKeyWidgetCharWidget,但没有起作用。

那么我该如何在InvestmentResource内验证电子邮件?

1个回答

2
问题在于您的“电子邮件”字段被视为查找键而不是电子邮件地址。这可以通过自定义“ForeignKeyWidget”来添加电子邮件验证来解决。
正在发生的是,您正在导入一个投资资源,可能是这样的:
email,firstname,lastname
bob@example.com,bob,smith

您已将 InvestmentResource 配置为使用电子邮件作为 Profile 的查找键。 这意味着 django-import-export 不会将其处理为电子邮件地址,而是作为 Profile 的查找键进行处理,因此在代码中 (ForeignKeyWidget) 它将执行类似以下内容的操作:
Profile.objects.get(email='bob@example.com')

如果成功,您的Investment实例将具有正确的配置文件作为外键引用。如果关联的Profile不存在,则会引发DoesNotExist异常。因此,您可以认为在csv中发送的电子邮件地址必须有效,因为如果无效,则无法进行查找。但是,如果您想在尝试加载Profile之前检查电子邮件是否语法正确,则可以轻松完成此操作,您需要重写ForeignKeyWidget以先执行验证。
from django.core.exceptions import ValidationError
from django.core.validators import validate_email

class ValidatingForeignKeyWidget(widgets.ForeignKeyWidget):

    def clean(self, value, row=None, *args, **kwargs):
        
        try:
            validate_email(value)
        except ValidationError as e:
            # a quirk of import-export means that the ValidationError 
            # should be re-raised
            raise ValueError(f"invalid email {e}")
    
        try:
            val = super().clean(value)
        except self.model.DoesNotExist:
            raise ValueError(f"{self.model.__name__} with value={value} does not exist")
        return val

再次感谢!还有一个问题,这里验证电子邮件的逻辑是否与模型中的EmailField验证相同? - Prosy Arceno
1
是的,它是相同的逻辑。 - Matthew Hegarty

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接