【发布时间】:2014-01-03 20:05:39
【问题描述】:
我正在使用 django 1.5.5 和 python 2.6
我有这个模型
class Site(models.Model):
url = models.CharField(max_length = 512)
我想自定义模型,以便具有“www”前缀的 url 的站点和不返回相同对象的站点返回相同的对象。
因此,如果我有一个 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)
这很好用,现在唯一的问题是,如果我使用任何类型的字段查找,那么它不会使用新逻辑。
所以任何类型的url__in、url__contains 等都不起作用。
我确信有比实现 django 中可用的每个归档查找更好的方法。
【问题讨论】:
-
您可能想要覆盖 get_absolute_url 方法而不是将其保存到数据库中。阅读更多关于它的信息here
-
另外,
Site.objects.filter(url__endswith='foo.com')有什么问题?这将匹配两种情况 -
@yuvi 两者都会匹配,但也会匹配 'notmy_foo.com'
-
可能有一种方法可以使用正则表达式。等等,我会挖一点