【问题标题】:Efficient Django QuerySet regex高效的 Django QuerySet 正则表达式
【发布时间】:2010-12-04 18:33:14
【问题描述】:

我有一个这样的模型:

class CampaignPermittedURL(models.Model):
    hostname = models.CharField(max_length=255)
    path = models.CharField(max_length=255,blank=True)

我会经常收到一个 URL,我可以将其拆分为主机名和路径。我希望最终用户能够输入主机名(yahoo.com)和可能的路径(婚礼)。

我想查找 URL 何时与主机名/路径组合不“匹配”,如下所示:

  • 成功: www.yahoo.com/weddings/newyork
  • 成功:yahoo.com/weddings
  • 失败: cnn.com
  • 失败:cnn.com/weddings

我认为最好的方法是:

url = urlsplit("http://www.yahoo.com/weddings/newyork")
### split hostname on . and path on /
matches = CampaignPermittedURL.objects.filter(hostname__regex=r'(com|yahoo.com|www.yahoo.com)'), \
    path__regex=r'(weddings|weddings/newyork)')

有人有更好的想法吗?我正在使用PostgreSQL,否则我想尝试Django Full Text Search,但我不确定这是否值得,或者它是否真的比这更符合我的需求。还有其他同样快的方法吗?

请记住,我的方法已将 URL 传递给它,并且 CampaignPermittedURL 对象可能有数百条记录。我首先在寻找可扩展/可维护的解决方案,但它也需要高效,因为这将扩展到每秒数百次调用。

我也可以使用另一个后端 (Sphinx?),但我最关心的是尽可能地使用标准 Django。

【问题讨论】:

    标签: regex django full-text-search


    【解决方案1】:

    正则表达式:^(http\:\/\/)?(www\.)?yahoo\.com(\/.+)?$

    http://www.yahoo.com/weddings/newyork pass
    www.yahoo.com/weddings/foo            pass
    www.yahoo.com/weddings                pass
    www.yahoo.com                         pass
    
    yahoo.com/weddings/foo                pass
    yahoo.com/weddings                    pass
    yahoo.com                             pass
    
    cnn.com/weddings/foo                  fail
    cnn.com/weddings                      fail
    cnn.com                               fail
    

    【讨论】:

    • 这基本上简化了我对此的回答 - 迄今为止最好的答案:(hostname__regex=r'(www\.)?(yahoo\.)?(com)?$'), \ path__regex=r'^(weddings\/)?(newyork)?')
    【解决方案2】:

    我最终构建了一个“详细”正则表达式并使用问题中指定的 ORM。这在不离开 Django 的情况下应该相当快:

            # >>> url.hostname.split(".")
        # ["bakery", "yahoo", "com"]
        host_list = url.hostname.split(".")
    
        # Build regex like r"^$|^[.]?com$|^[.]?yahoo\.com$|^[.]?baking[.]yahoo[.]com$"
        # Remember that
        # >>> r'\'
        # '\\'
        host_list.reverse()
    
        # append_str2 might not be necessary
        append_str = r""
        append_str2 = r""
        host_regex = r"^$"
        for host in host_list:
            append_str = r"[.]" + host + append_str
            append_str2 = append_str[3:]
            host_regex = host_regex + r"|^[.]?" + append_str2 + r"$"
        # If nothing is in the filter at all, bypass the filter.
        if CampaignRequiredURL.objects.filter():
            if not CampaignRequiredURL.objects.filter(hostname__iregex=host_regex):
                #Do something based on a hit.
    

    【讨论】:

    • 很好地使用了 django 的 __iregex,因为 url 的域部分不区分大小写,这是在正则表达式中检查的唯一部分。您的正则表达式将匹配 YAHOO.COM,因为它应该。 @maček's 会错过这个。
    猜你喜欢
    • 2022-12-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-11
    • 1970-01-01
    • 2014-11-06
    相关资源
    最近更新 更多