2012-08-10 83 views
13

假设我有一个带有邮政编码字段的地址模型。我可以用邮政编码开始,“123”这一行查找地址:Django开始在字段

Address.objects.filter(postcode__startswith="123") 

现在,我需要做的这个“周围的其他方式”搜索。我有一个带有postcode_prefix字段的Address模型,我需要检索postcode_prefix是给定代码前缀的所有地址,如“12345”。所以如果在我的数据库中有两个地址postcode_prefix =“123”和“234”,只有第一个会被返回。

喜欢的东西:

Address.objects.filter("12345".startswith(postcode_prefix)) 

的问题是,这是行不通的。 唯一的解决办法我能想出是对第一个字符进行过滤,如:

Address.objects.filter(postcode_prefix__startswith="12345"[0]) 

,然后,当我得到的结果,做一个列表理解可以过滤他们正确,就像这样:

results = [r for r in results if "12345".startswith(r.postcode_prefix)] 

在django中有更好的方法吗? 谢谢你, 法布里奇奥

+0

前缀的长度是固定的还是有可变长度? – cyroxx 2012-08-10 15:47:03

+0

可变长度:) – sfabriz 2012-08-10 16:22:22

回答

8

在SQL方面,你想达到什么倒像是( “12345”是您正在搜索)邮编:

SELECT * 
FROM address 
WHERE '12345' LIKE postcode_prefix||'%' 

这是不是一个真正的标准查询,我没有看到任何可能只用得到(Django中做到这一点)/过滤器()。

然而,Django还提供了一种方法来提供额外的SQL条款与extra()

postcode = '12345' 
Address.objects.extra(where=["%s LIKE postcode_prefix||'%%'"], params=[postcode]) 

请参阅Django documentation on extra()作进一步参考。另请注意,额外包含纯SQL,因此您需要确保该子句对您的数据库有效。

希望这对你有用。

+1

谢谢。这可能是最好的方法,但是,正如你所说,它会变成数据库的依赖。我很高兴,虽然没有快速django魔术,我失踪了。 非常感谢! Fabrizio – sfabriz 2012-08-10 20:03:03

11

我想你想你“类似”线正确地写成这样做:

Address.objects.filter(postcode__startswith=postcode_prefix) 
+0

实际上,OP反其道而行之。确切地说, – cyroxx 2012-08-10 16:09:54

+0

。我需要相反的方式。我可以用一种以上的方法用python来完成,但我只需要知道我是否错过了一些适当的django方法来完成它。 :) – sfabriz 2012-08-10 16:24:03

0

A.如果没有问题https://code.djangoproject.com/ticket/13363, 你可以这样做:

queryset.extra(select={'myconst': "'this superstring is myconst value'"}).filter(myconst__contains=F('myfield')) 

也许,他们会解决一个问题,它可以工作。

B.如果不是问题16731(抱歉没有提供完整的URL,没有足够的代表,请参阅上面的另一张票),您可以通过添加'.annotate'的字段进行过滤,并创建自定义聚合函数,如下所示: http://coder.cl/2011/09/custom-aggregates-on-django/

C.最后一次成功。我已成功地做到这一点使用的monkeypatching如下:

  1. django.db.models.sql.Query.query_terms
  2. django.db.models.fields.Field。get_prep_lookup
  3. django.db.models.fields.Field.get_db_prep_lookup
  4. django.db.models.sql.where.WhereNode.make_atom

刚刚定义的自定义查找 '_ 开始',它有着相反的逻辑' _startswith'

0

一种可能的选择。 (不知道如何比较与一列作为第二个参数去喜欢接受的解决方案,在执行时间)

q=reduce(lambda a,b:a|b, [Q(postcode__startswith=postcode[:i+1]) for i in range(len(postcode))])

因此,你产生的所有前缀,并且还是在一起......