【问题标题】:web2py: SQLFORM URL duplicate validationweb2py:SQLFORM URL 重复验证
【发布时间】:2025-12-27 05:15:12
【问题描述】:

我想禁止用户向数据库提交重复的 url。

目前我的做法是:

db.url.URL.requires=[IS_URL(error_message='URL Error'),
                     IS_NOT_IN_DB(db, 'url.URL',error_message='Dupilcated URL')]

它涵盖了有“http”和没有“http”的情况。 例如,如果 www.123.com 已经在数据库中,则用户无法提交http://www.123.com。 但是这种方法不包括“https”的情况,即用户仍然可以提交https://www.123.com

有没有办法防止这种重复?

我认为在调用 SQLFORM().process() 之前消除 URL 中的“http”/“https”(如果有)。这样,数据库中的url都没有“http”/“https”。但我不知道如何在调用 SQLFORM().process() 之前编辑用户输入。

现在我的代码是

url_form=SQLFORM(db.url).process()

有什么想法吗?

谢谢!

【问题讨论】:

    标签: web2py


    【解决方案1】:

    您可以创建一个自定义验证器以在进一步处理之前去除 http/https:

    import re
    db.url.URL.requires = [lambda url: (re.sub(r'http[s]?://', '', url), None),
                           IS_URL(error_message='URL Error'),
                           IS_NOT_IN_DB(db, 'url.URL',error_message='Dupilcated URL')]
    

    注意,自定义验证器返回一个元组,包括更改后的 URL 和 NoneNone 表示没有错误)。然后将更改后的 URL 传递给其余两个验证器。

    注意,默认情况下,IS_URL 将在任何缺少方案的 URL 前加上“http://”(在这种情况下将是所有 URL,因为第一个验证器会去除方案)。要抑制这种行为,您可以执行IS_URL(prepend_scheme=None)

    【讨论】:

    • 谢谢!有用。我见过 lambda 好几次,但我从来没有真正理解它是如何工作的。
    【解决方案2】:

    您可以创建一个custom validator,它将检查数据库中的 http 和 https 版本。这也允许格式化 URL。想想所有小写的主机名和删除 url 中的关键字参数 (?a=b)。如果您打算这样做,请务必查看urlparse

    以下代码未经测试,但可以为您提供足够的代码来创建您自己的解决方案。

    class scheme_independant_url_is_not_in_db:
        def __init__(self, db,error_message='Duplicate URL'):
            self.db = db
            self.e = error_message
    
        def __call__(self, value):
            # test the entered uri
            url_validator = IS_NOT_IN_DB(db,'url.URL')
            value, error = url_validator(value)
            if error: 
                return value,self.e
            # find the opposing scheme
            if value.lower().startswith('http:'):
                opposite_scheme_value =  'https:'+value[5:] 
            elif value.lower().startswith('https:')
                opposite_scheme_value =  'http:'+value[6:] 
            # error on the opposite_scheme_value in db
            value, error = url_validator(opposite_scheme_value)
            if error: 
                return value,self.error_message
            # return the original url, preserving the original scheme
            return (value, None)
    ... 
    
    db.url.URL.requires=[IS_URL(error_message='URL Error'),
                     scheme_independant_url_is_not_in_db(db)]
    

    【讨论】:

    • 非常感谢!你的代码很容易理解。
    • 不剥离方案的另一个好处可能是某些网站提供不同的内容或可能无法访问。