#やりたいこと
- クイズフォーム:好きなおつまみを選択する形式にする
- クイズで表示されるおつまみを毎回ランダムに選ぶ
- フロントからクイズの結果を受け取る
- クイズの結果を用いておつまみをpredictする
- predictしたランキングをフロントに送信する
- アンケート結果をDBに登録する
#できなかったこと
- 画像の扱い方まだわからん
- jSONで受け取ってページ遷移⇒結果を出力
- 画像アップロードからお酒推定⇒PREDICTに渡す
#クイズフォーム(ラジオボタン作成)+クイズで表示されるおつまみを毎回ランダムに選ぶ+
ns = random.sample(range(15,83), 9)
def decide_coice(count, CHOICE_dict):
CHOICEs = {
(ns[count*3], CHOICE_dict[ns[count*3]]),
(ns[count*3+1], CHOICE_dict[ns[count*3+1]]),
(ns[count*3+2], CHOICE_dict[ns[count*3+2]])
}
return CHOICEs
CHOICESAKE = {
(1,'1'),
(2,'2'),
(3,'3'),
}
CHOICE_dict = {
15:'サラダ系',
16:'野菜スティック',
(略)
82: 'フルーツのアイス',
}
CHOICE = {
(15,'サラダ系'),
(略)
(82, 'フルーツのアイス'),
}
class RadioForm(forms.Form):
select = forms.ChoiceField(label='酒', widget=forms.RadioSelect, choices= CHOICESAKE, initial=2)
select2 = forms.ChoiceField(label='属性2', widget=forms.RadioSelect, choices= decide_coice(0, CHOICE_dict), initial=15)
select3 = forms.ChoiceField(label='属性3', widget=forms.RadioSelect, choices= decide_coice(1, CHOICE_dict), initial=15)
select4 = forms.ChoiceField(label='属性4', widget=forms.RadioSelect, choices= decide_coice(2,CHOICE_dict), initial=15)
formsで入力を受け取る処理を書きます。
CHICEとCHICE_dictがあるのは処理の都合上です。1つでうまいこと処理する方法は必ずあります。
画像から酒分類の処理がまだできてないからCHOICESAKEで酒の値を与えてる。ここに酒の番号を与えたい。
乱数を生成して、その番号に対応するおつまみをクイズとして表示している。
#フロントからクイズの結果を受け取る
def new(request):
params = {'message': '', 'form': None}
if request.method == 'POST':
#form = QuizForm(request.POST)
form = RadioForm(request.POST)
if form.is_valid():
"""
redirect_url = '/newview'
form = urlencode(QuizForm(request.POST))
url = f'{redirect_url}?{form}'
return redirect(url)
"""
key = (int(form.data['select']), int(form.data['select2']), int(form.data['select3']), int(form.data['select4']))
return recommend(request, key[0], key[1], key[2], key[3])
else:
params['message'] = '再入力して下さい'
params['form'] = form
else:
params['form'] = RadioForm()
return render(request, 'frontend/new.html', params)
quizのページ作ってくれてたけど触るの忍びなかったからnewでクイズを作りました。
form = RadioForm(request.POST)
でform
に _Queryset型_でクイズの結果が入ってます。
クイズ送信時に値が正常だったらreturn recommend(request, key[0], key[1], key[2], key[3])
で次の処理に移ります。
ここで問題が発生
ほんとならfrontend/recommendにページ遷移して結果を表示したかったんですけど、jsonのデータを渡す方法がわからなかったです
- URLに引数を含めて次のページ遷移、URLから値をゲット
- 関数に直接渡す
- クイズ結果をDBに格納して、recommendで改めて取り出す。
の2つが実現できそうで、2つ目を選びました。その結果処理はずっと_/new_のURLで行われるようになってます。一応3つ目も実装はしました。
引数は全部intでこの番号っていうのは最初に出てきてCHOICEの番号と対応してます。
return recommend(request, 酒の番号, おつまみ番号1, おつまみ番号2, おつまみ番号3)
#クイズの結果を用いておつまみをpredictする
処理の流れは以下
1.ユーザーが選択した酒の評価が高いデータを取り出すfindsameperson()
2.ユーザーが選択したおつまみを参考に類似度を計算get_simiralities()
3.類似度で並べ替えてランキング付けpredict()
quizAnser = [CHOICE_dict[one+3], CHOICE_dict[two], CHOICE_dict[three], CHOICE_dict[four]]
#画像とクイズから得られたターゲットデータ
target_sake = target_items_list[one+3]
first_otsumami = {target_items_list[two] : two}
second_otsumami = {target_items_list[three] : three}
target_data = [first_otsumami, second_otsumami]
sample_lists = list(Sample.objects.all().values())
#選んだ酒の評価が高い人のサンプルデータを取得
samePersonList = findsamePerson(target_sake, sample_lists)
#類似度を計算
similarities = get_similarities(samePersonList, target_data)
#ランキング付ける
ranking = predict(samePersonList, similarities, target_items_list, CHOICE_dict)
params = {
'title': 'title',
'massage': similarities,
'酒の種類':quizAnser[0],
'おつまみ1':quizAnser[1],
'おつまみ2':quizAnser[2],
'おつまみ3':quizAnser[3],
'1位':ranking[0][0],
'quizAnser': quizAnser,
'data': ranking,
}
return render(request, 'frontend/recommend.html', context=params)
def findsamePerson(target_sake, sample_lists):#(str, list[dict])
#ターゲットの酒の評価が5のサンプルを抽出する
#評価が高い人のデータ(辞書型)をsamePersonListに入れていく
samePersonList = []
for item in sample_lists:
if item[target_sake] >= 3:
samePersonList.append(item)
else:
pass
return samePersonList
#predictしたランキングをフロントに送信、表示
params = {
'title': 'title',
'massage': similarities,
'酒の種類':quizAnser[0],#str
'おつまみ1':quizAnser[1],#str
'おつまみ2':quizAnser[2],
'おつまみ3':quizAnser[3],
'1位':ranking[0][0],#str
'quizAnser': quizAnser,#入力結果の名称のリスト(str)[酒、おつ1、おつ2、おつ3]
'data': ranking,#dictのリスト=[{おつまみ名1:類似度},{おつまみ名2:類似度}...]類似度でソート済み
}
return render(request, 'frontend/recommend.html', context=params)
paramsのkey(左)がhtmlで使えるラベルで、value(右)が実際の中身
<h2>あなたの今日のおつまみは……</h2>
<img src="{% static 'frontend/img/result/salad.jpg' %}">
<h2>{{1位}}!!!</h2>
<br>
<p>{{酒の種類}}にぴったりな、{{1位}}です。<br>
<br>
サラダの他に、以下の食材もおすすめです。<br>
サラダが苦手だったり、他のおつまみも併せて食べたい時は参考にしてみてください。</p>
</div>
{% for item, similarities in data %}
<p>
{{forloop.counter}}位:{{item}}【ポイント】: {{similarities}}
</p>
{% endfor %}
{{key}}でparamsの値が出力できて、{% %}でpythonの関数が使えるからループしてる。
↓出力画面
#アンケートをDBに登録する
手作業で入力する地獄のような作業です。今は20個くらいしか登録できてません
また映画でも見ながらやっときます
ラーメン食べてきます。変なとこと、改善あったらslackで聞いてください!明日も時間あります!
##見たサイト
DjangoとJavaScript(JS)を使用してリダイレクトさせる方法
DjangoでJSONを送受信する
DjangoでJson
【Django】ラジオボタンを設置したり、マークアップを整形したりする
パラメータを渡してリダイレクト
model内でDBを削除
(ModelChoiceField)登録画面で別モデルを参照したラジオボタンを表示(Django)
画面遷移のロジックがわからない
how to convert Querydict to python dict
formの基本
モデルからフォームを生成する