我正在使用django 1.5.5和python 2.6
我有这个模型
class Site(models.Model):
url = models.CharField(max_length = 512)
我想自定义模型,以便具有'www'前缀的网址和不会返回相同对象的网站的网站。
因此,如果我有一个url ='http://foo.com'的网站,则以下所有内容都将返回相同的对象
mysite = Site.objects.get(url__iexact='http://foo.com')
mysite = Site.objects.get(url__iexact='http://www.foo.com')
mysite = Site.objects.filter(url__iexact='http://foo.com')
mysite = Site.objects.filter(url__iexact='http://www.foo.com')
我正在考虑制作类似的方法。
@classmethod
def get_site(cls,url):
# search for site with url = url
if url.startswith('http://www'):
# search without www
else:
# search with www
return site
但我确信有更好的方法可以让我继续使用objects.get
和objects.filter
根据Gonzalo Delgado的建议,我做了一个自定义模型经理
这是我的代码
def url_variants(url):
prefixes = ['http://www.','https://www.','http://','https://',] # order must be from longest to shortest
for prefix in prefixes:
if url.startswith(prefix):
url = url[len(prefix):]
break
return [ prefix+url for prefix in prefixes]
class SiteManager(models.Manager):
def filter(self, *args, **kwargs):
if 'url' in kwargs:
variants = url_variants(url)
# in order to chain '__in' and '__iexact' Q is needed
q_list = [Q(url__iexact=n) for n in variants]
q_list = reduce(lambda a, b: a | b, q_list)
args = (q_list,) + args
kwargs.pop("url", None) # remove original Field lookups
return super(SiteManager, self).filter(*args, **kwargs)
这很好,现在唯一的问题是,如果我使用任何类型的Field查找,那么它不会使用新的逻辑。
所以任何类型的url__in
,url__contains
等都不起作用
我确信有一种比实现django中可用的每个字段查找更好的方法。
答案 0 :(得分:1)
您需要创建custom manager并扩展get
并过滤methods
:
class SiteManager(models.Manager):
def get(self, *args, **kwargs):
if 'url' in kwargs:
# handle 'www' prefix here and update kwargs['url'] accordingly
return super(SiteManager, self).get(*args, **kwargs)
def filter(self, *args, **kwargs):
if 'url' in kwargs:
# handle 'www' prefix here and update kwargs['url'] accordingly
return super(SiteManager, self).filter(*args, **kwargs)
class Site(models.Model):
url = models.CharField(max_length = 512)
objects = SiteManager()
答案 1 :(得分:0)
我想我找到了解决方案。它并不完美,但我认为这对我来说已经足够了 它基于Gonzalo Delgado的答案。
这是我的代码:
from django.db import models
from django.db.models import Q
def url_variants(urls):
if isinstance(urls, basestring): # if it is not a list then make a list
urls = [urls]
variants = []
for url in urls:
prefixes = ['http://www.','https://www.','http://','https://',] # order must be from longest to shortest
for prefix in prefixes:
if url.startswith(prefix):
url = url[len(prefix):]
break
variants += [ prefix+url for prefix in prefixes]
return variants
def variants_filter(variants,lookup):
q_list = [Q(**{ lookup: n}) for n in variants]
q_list = reduce(lambda a, b: a | b, q_list)
return (q_list,)
class SiteManager(models.Manager):
def filter(self, *args, **kwargs):
# find keys that contain 'url'
for key in kwargs:
if key.startswith('url'):
variants = url_variants(kwargs[key])
args = variants_filter(variants, key.replace('__in','')) + args # if there is an '__in' then remove it we already have list support
kwargs.pop(key, None)
break
return super(SiteManager, self).filter(*args, **kwargs)