Django 验证电子邮件外键
Django Validate an Email Foreign Key
我有这个配置文件资源:
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
上的电子邮件添加两个小部件 ForeignKeyWidget
和 CharWidget
,但它没有用。
然后如何验证 InvestmentResource
中的电子邮件?
问题是您的 'email' 字段被视为查找键而不是电子邮件地址。这可以通过自定义 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
我有这个配置文件资源:
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
上的电子邮件添加两个小部件 ForeignKeyWidget
和 CharWidget
,但它没有用。
然后如何验证 InvestmentResource
中的电子邮件?
问题是您的 'email' 字段被视为查找键而不是电子邮件地址。这可以通过自定义 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