web-dev-qa-db-ja.com

Django startswithフィールド

郵便番号フィールドを持つ住所モデルがあるとします。次の行を使用して、「123」で始まる郵便番号の住所を検索できます。

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

今、私はこの検索を「他の方法」で行う必要があります。 postcode_prefixフィールドを持つアドレスモデルがあり、postcode_prefixが「12345」のように特定のコードのプレフィックスであるすべてのアドレスを取得する必要があります。したがって、私のデータベースにpostcode_prefix = "123"と "234"の2つのアドレスがある場合、最初のアドレスのみが返されます。

何かのようなもの:

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

ジャンゴでそれを行うより良い方法はありますか?ありがとう、ファブリツィオ

22
sfabriz

SQL用語では、次のような読み取りを実現する必要があります(「12345」は検索している郵便番号です)。

_SELECT *
FROM address
WHERE '12345' LIKE postcode_prefix||'%'
_

これは実際には標準的なクエリではなく、Django get()/ filter()のみを使用して)でこれを実現する可能性はありません。

ただし、Djangoは、extra()で追加のSQL句を提供する方法を提供します:

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

詳細については、 extra()のDjangoドキュメント を参照してください。また、エクストラには純粋なSQLが含まれているため、この句がデータベースに対して有効であることを確認する必要があります。

これがうまくいくことを願っています。

9
cyroxx

私はあなたがあなたの「何かのような」行でやろうとしていることは次のように適切に書かれていると思います:

Address.objects.filter(postcode__startswith=postcode_prefix)
26
Joe Day

一口ですが、検索値に注釈を付けてからフィルタリングすることでこれを行うことができます。すべてがデータベース内で非常に迅速に行われます。

from Django.db.models import Value as V, F, CharField

MyModel.objects.annotate(
    search_str=Value('...', output_field=CharField())
).filter(
    search_str__istartswith=F('my_previx_field')
)

最近、ニースのテンプレート関数を使用してこれを実行できると確信しています...しかし、これは私にとっては十分にクリーンです。

1
Oli

可能な代替案。 (実行時に、2番目のパラメーターとして2番目のパラメーターとして列を使用して、受け入れられたソリューションとどのように比較するかわからない)

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

したがって、すべての接頭辞、またはそれらを一緒に生成します...

0
Vajk Hermecz

A.問題ではない場合 https://code.djangoproject.com/ticket/1336 、これを行うことができます:

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.最後に成功しました。私はこれをなんとかして、以下のモンキーパッチを使用して行いました:

  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

ちょうど定義されたカスタムルックアップ '_starts'、これは '_ startswith'の逆ロジックを持っています

0
brawaga