【问题标题】:Correct way of saving objects with URLField使用 URLField 保存对象的正确方法
【发布时间】:2020-10-27 13:38:44
【问题描述】:

我有一个模型类KeyWord

class KeyWord(models.Model):
    keyword = models.CharField(verbose_name="Topic",max_length=50)
    link = models.URLField(verbose_name = "Next Best Action", max_length=500,null=True)

    def __str__(self):
        return self.keyword

如果我创建这样的对象:

KeyWord.objects.create(keyword="hello",link="world")

理想情况下会引发错误,因为我将普通文本分配给 link 字段,该字段是 URLField 但对象创建成功?

我应该使用哪个字段或者我应该怎么做才能保存具有有效链接的对象?

【问题讨论】:

  • 为什么它不是一个有效的 URL?这将解析为相对于当前文档位置的 url “world”。因此,如果文档位置是 hello.com,那么 URL 世界将是 hello.com/world。没有办法强制 vanilla Django URLField 要求完全限定的 URL。
  • 实际上我是通过从 excel 文件中读取数据来保存对象的。如果我没有得到有效的链接,我想提出一个错误。例如,如果在任何特定行如果获取keyword="macbook"link="https://apple.com",我将保存该对象,否则如果获取keyword="macbook"link="apple",则将传递错误消息apple is not a valid url 并且函数将返回。
  • 我希望我现在把我的问题说清楚了,你可以指导我。

标签: django django-models


【解决方案1】:

先决条件:模型验证仅在您调用 full_clean() 时进行。如果你使用ModelForm,这在你调用form.save()时为你完成,但如果你上传一个带有自定义视图逻辑的Excel文件,那么你需要do this yourself

验证模型涉及三个步骤:

  • 验证模型字段 - Model.clean_fields()
  • 整体验证模型 - Model.clean()
  • 验证字段唯一性 - Model.validate_unique()

当您调用模型的 full_clean() 方法时,会执行所有三个步骤。

正如我之前所说,没有办法告诉 URLField 需要fully qualified URLs。为此,您需要覆盖 URLValidator。

这有一个非常讨厌的正则表达式,你可能不想弄乱它,所以另一种方法是添加额外的验证器:

from django.core.exceptions import ValidationError
from django.utils.deconstruct import deconstructible

@deconstructible
class RequireHttpOrHttpsUrl:
    def __call__(self, value):
        if not value.startswith("http://") and not value.startswith("https://"):
            raise ValidationError('Please provide a http or https resource')

class KeyWord(models.Model):
    keyword = models.CharField(verbose_name="Topic",max_length=50)
    link = models.URLField(
        verbose_name = "Next Best Action",
        max_length=500, null=True,
        validators=[RequireHttpOrHttpsUrl()]
    )

    def __str__(self):
        return self.keyword

按照 cmets 中的建议使用 urllib.parse():

我强烈建议在 urllib.parse() 更好的地方使用 URLValidator。 URLValidator 拒绝:

  • http://
  • http://bla
  • https://bla

接受:

所以,我找不到添加另一个解析器的好处。

【讨论】:

  • 您也可以使用 urllib 使其更加严格(以 Python 3.8 为例)python from urllib.parse import urlparse parsed = urlparse('https://apple.com/foo') bool(parsed.scheme) and bool(parsed.netloc) # True
  • 不需要,因为默认的 URLValidator 仍然存在,这已经足够好。
  • 首先我应用了迁移python manage.py makemigrations appName 然后python manage.py migrate。然后我再次上传了excel文件。 non http and https 的仍然值被保存。但是我遵循了这个答案stackoverflow.com/questions/7160737/… 并找到了解决方法。不过感谢您的支持。
  • @Melvyn 这不是关于验证它是否是一个有效的 URL,而是让解析器完成确定 URL 的哪些组件存在的繁重工作。在我的示例中,验证我们是否同时拥有架构和域。
  • @AmandeepSinghSawhney 您可能使用的是早期版本,我在编辑之前将验证器添加为类而不是实例。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-05-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-17
  • 1970-01-01
相关资源
最近更新 更多