おつまみrecommender進捗(メモ)

#やりたいこと
* クイズフォーム：好きなおつまみを選択する形式にする
* クイズで表示されるおつまみを毎回ランダムに選ぶ
* フロントからクイズの結果を受け取る
* クイズの結果を用いておつまみをpredictする
* predictしたランキングをフロントに送信する
* アンケート結果をDBに登録する

#できなかったこと
* 画像の扱い方まだわからん
* jSONで受け取ってページ遷移⇒結果を出力
* 画像アップロードからお酒推定⇒PREDICTに渡す

#クイズフォーム（ラジオボタン作成）+クイズで表示されるおつまみを毎回ランダムに選ぶ＋
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/515470/f4d21a66-b5b3-acc7-6104-c17576d5e87c.png)

```python:forms.py

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があるのは処理の都合上です。１つでうまいこと処理する方法は必ずあります。
画像から酒分類の処理がまだできてないからCHOICESAKEで酒の値を与えてる。ここに酒の番号を与えたい。

乱数を生成して、その番号に対応するおつまみをクイズとして表示している。


#フロントからクイズの結果を受け取る
```python:frontend/views.py
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で改めて取り出す。


の２つが実現できそうで、２つ目を選びました。その結果処理はずっと_/new_のURLで行われるようになってます。一応3つ目も実装はしました。
引数は全部intでこの番号っていうのは最初に出てきてCHOICEの番号と対応してます。
`` return recommend(request, 酒の番号, おつまみ番号１, おつまみ番号２, おつまみ番号３) ``

#クイズの結果を用いておつまみをpredictする
処理の流れは以下
***
１．ユーザーが選択した酒の評価が高いデータを取り出す``findsameperson()``
２．ユーザーが選択したおつまみを参考に類似度を計算``get_simiralities()``
３．類似度で並べ替えてランキング付け``predict()``
***
```python:views.py
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],
        'おつまみ１':quizAnser[1],
        'おつまみ２':quizAnser[2],
        'おつまみ３':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])
    #ターゲットの酒の評価が５のサンプルを抽出する
    #評価が高い人のデータ（辞書型）をsamePersonListに入れていく

    samePersonList = []
    for item in sample_lists:
        if item[target_sake] >= 3:
            samePersonList.append(item)
        else:
            pass
    return samePersonList
```
#predictしたランキングをフロントに送信、表示
```python:vies.py
    params = {
        'title': 'title',
        'massage': similarities,
        '酒の種類':quizAnser[0],#str
        'おつまみ１':quizAnser[1],#str
        'おつまみ２':quizAnser[2],
        'おつまみ３':quizAnser[3],
        '1位':ranking[0][0],#str
        'quizAnser': quizAnser,#入力結果の名称のリスト(str)[酒、おつ１、おつ２、おつ３]
        'data': ranking,#dictのリスﾄ=[{おつまみ名1:類似度},{おつまみ名2:類似度}...]類似度でソート済み
    }
    return render(request, 'frontend/recommend.html', context=params)
```

paramsのkey(左)がhtmlで使えるラベルで、value(右)が実際の中身

```html:frontend/recommend.html
                        <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の関数が使えるからループしてる。
↓出力画面
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/515470/072c0cfe-4d4a-e769-cb8f-7e65267dd81e.png)

#アンケートをDBに登録する
手作業で入力する地獄のような作業です。今は20個くらいしか登録できてません
また映画でも見ながらやっときます


ラーメン食べてきます。変なとこと、改善あったらslackで聞いてください！明日も時間あります！

##見たサイト
[DjangoとJavaScript(JS)を使用してリダイレクトさせる方法](https://awesome-linus.com/2019/04/03/django-return-redirect-and-redirect-js/)
[DjangoでJSONを送受信する](https://awesome-linus.com/2019/04/03/django-return-redirect-and-redirect-js/)
[DjangoでJson](https://e-tec-memo.herokuapp.com/article/12/)
[【Django】ラジオボタンを設置したり、マークアップを整形したりする](https://qiita.com/xKxAxKx/items/284abc565715f2283fec)
[パラメータを渡してリダイレクト](https://djangobrothers.com/blogs/django_redirect_with_parameters/)
[model内でDBを削除](https://dot-blog.jp/news/django-objects-delete/)
[(ModelChoiceField)登録画面で別モデルを参照したラジオボタンを表示（Django）](https://hombre-nuevo.com/python/python0067/)
[画面遷移のロジックがわからない](https://teratail.com/questions/288276)
[how to convert Querydict to python dict](https://stackoverrun.com/ja/q/5216419)
[formの基本](https://www.nblog09.com/w/2019/05/01/django-forms-basic/)
[モデルからフォームを生成する](https://djangoproject.jp/doc/ja/1.0/topics/forms/modelforms.html)