2017-09-05 7 views
3

このORMクエリは正常に動作しています。私は、出力を参照するには、以下の試験をし、それが実際に期待されているとおり静的なCASE WHENステートメントを動的に変換して.annotate()に変換します。

members=Members.objects.all().annotate(age_groups=Case(
       When(birthdate__year__range=(2007,2017), then=Value('0-10')), 
       When(birthdate__year__range=(1997,2006), then=Value('11-20')), 
       When(birthdate__year__range=(1987,1996), then=Value('21-30')), 
       When(birthdate__year__range=(1977,1986), then=Value('31-40')), 
       When(birthdate__year__range=(1967,1976), then=Value('41-50')), 
       When(birthdate__year__range=(1957,1966), then=Value('51-60')), 
       When(birthdate__year__range=(1947,1956), then=Value('61-70')), 
       When(birthdate__year__range=(1937,1946), then=Value('71-80')), 
       When(birthdate__year__range=(1927,1936), then=Value('81-90')), 
       When(birthdate__year__range=(1917,1926), then=Value('91-100')), 
       default=Value('100+'), output_field=CharField()) 
       ).values('age_groups',).annotate(total=Count('age_groups')) 

しかし、私は、ユーザーが作業したい日付フィールドを指定することができるように関数に移動すると、彼らが好むグループ化します(例: 0-20、21-40など)。そのために、私は単に呼び出されたときにCASE WHEN statementsを文字列として出力する以下の関数を書いた。問題は私がそれをannotate()に渡すときですstrにはno resolve errorがあります。

私は何をしたいのですか?私はannoate()に次の関数の出力を渡す必要があります:

from datetime import date 
def AgeGrouping(field_name,required_min_age=0,required_max_age=100,jump_by=10): 
now_year=date.today().year 

reply='Case(' 
just_started=True 
for i in range(now_year-required_min_age,now_year-required_max_age,-jump_by): 

    if just_started==False: 
     min_age=max_age + 1 
     max_age=min_age + 9 

    else: 
     min_age= now_year - i 
     max_age= min_age + 10 

    min_year=now_year- min_age 
    max_year= now_year - max_age 

    reply="\n".join([reply,"When(" + field_name + "__year__range=(" + str(max_year) + "," + str(min_year) + "), then=Value('" + str(min_age) + "-" + str(max_age) + "')),"]) 

    just_started=False 

reply="\n".join([reply, "default=Value('100+'), output_field=models.CharField())"]) 

return reply 

次に、このようにそれを呼び出す:

print(AgeGrouping('birthdate',required_min_age=0,required_max_age=100,jump_by=10)) 

答えて

2

あなたの現在のアプローチが必要なコードを含む文字列を作成することです。文字列をコードとして評価することは可能ですが、セキュリティ上の問題があります。

より良い方法は、ループを使用してWhen()オブジェクトのリストを作成することです。その後、あなたの注釈でCase()と呼ぶとき、リストを解凍することができます。

def age_grouping(field_name, required_min_age=0, required_max_age=100, jump_by=10): 
    ... 
    whens = [] 
    for i in range(now_year-required_min_age,now_year-required_max_age,-jump_by): 
     # Set min_age, max_age, min_year, max_year 
     ... 
     description = '%s-%s' % (min_age, max_age) # e.g. '0-10' 
     # create dict of kwargs for When() 
     kwargs = {'%s__year__range' % field_name: (min_year, max_year)} 
     whens.append(When(then=Value(description), **kwargs)) 

    # Return the Case() object that you can pass to annotate() 
    return Case(*whens, default=Value('100+'), output_field=CharField()) 

あなたはその後、

Members.objects.all().annotate(age_groups=age_grouping(...)) 
+0

おかげ@Alasdairを呼び出すことができるはずですが...非常によく期待通りに働いていました。 –

関連する問題