2009-10-07 7 views
3

J'ai un modèle comme celui-ci:efficace Django QuerySet regex

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

Sur une base régulière, je vais être remis une URL, que je peux urlsplit en un nom d'hôte et un chemin. Ce que je voudrais, c'est que l'utilisateur final puisse entrer un nom d'hôte (yahoo.com) et éventuellement un chemin (mariages).

Je voudrais trouver quand une URL ne 'match' que la combinaison nom d'hôte/chemin comme ceci:

  • succès: www.yahoo.com/weddings/newyork
  • succès: yahoo .com/mariages
  • échec
  • : cnn.com
  • échec: cnn.com/weddings

I thi nk la meilleure façon de le faire est:

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)') 

Est-ce que quelqu'un a de meilleures idées? J'utilise PostgreSQL et je voudrais sinon essayer Django Full Text Search mais je ne suis pas sûr si cela en vaut la peine ou si cela correspond vraiment mieux à mes besoins. Existe-t-il d'autres méthodes aussi rapides? Gardez à l'esprit que l'URL de mon méthode est transmise à ma méthode et que l'objet CampaignPermittedURL peut contenir plusieurs centaines d'enregistrements. Je cherche avant tout des solutions extensibles/maintenables, mais il faut aussi que ce soit efficace puisque cela sera réduit à plusieurs centaines d'appels par seconde.

Je suis également très bien avec l'utilisation d'un autre back-end (Sphinx?), Mais je suis très préoccupé par le fait de rester avec le Django standard au plus haut degré possible.

Répondre

3

J'ai fini par construire une expression rationnelle 'verbose' et en utilisant le ORM comme indiqué dans la question. Cela devrait être assez rapide sans au départ de 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. 
+0

Bonne utilisation de '__iregex' de django, puisque la partie domaine des URL est insensible à la casse et c'est la seule partie qui est vérifiée dans l'expression rationnelle. Votre regex va correspondre à YAHOO.COM, comme il se doit. @ maček va manquer celui-ci. – hobs

3

Regex: ^(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 
+0

Cela simplifie essentiellement ma réponse un peu à cette question - meilleure réponse à ce jour que:.? (hostname__regex = r '(www \) (yahoo \.)? (com)? $ '), \ path__regex = r'^(mariages \ /)? (newyork)? ') –

Questions connexes