質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.92%

djangoでつくったレストランリストから、該当エリアのお店だけ表示させたい。

受付中

回答 0

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 522

score 19

レストランリストの一覧から、エリア(例:渋谷など)で、該当するものだけを表示するようにしたいです。

不足情報などございましたら、随時加筆いたしますので、ご指摘頂けますと幸いです。

レストランを食べログ的にリスト表示するものをオリジナルで作ろうとしていました。
リストを無造作にリスト表示するところはできていたので、それを、条件で絞って表示できるようにアップデートしようとしております。
その条件絞り表示(つまりは検索機能)については、こちらの方のブログを参照しながらつくっていましたが、思い描いた挙動をしてくれませんでした。
DjangoでListViewを用いて検索画面を実装する方法 - 知的好奇心

エリア選択画面 tableplanner/select
tableplanner/select
(仮画面につき、レイアウトなどが、滅茶苦茶なのはご容赦ください......)

この「エリア」ラベルが付いている検索窓に「渋谷」だとか「新宿」だとか入れたら、
下部、「検索結果が存在しません」になっているところに、お店を表示するイメージで作っております。

しかし、渋谷と入れようと、新宿と入れようと、それらエリアに紐づけてあるid("2"だとか"5"だとか)を直接打ち込もうと、
「検索結果が存在しません」のままになってしまいます。

エラー文が、ワーっと吐き出されるのであればよいのですが、そういうわけでもないので困りました。
なにぶん、visual studio自体も初心者なため、デバッグやらステップ実行で原因突き止めるやり方も今ひとつわかっておらず、
したがって、裏側のどこに原因があるのか自体、ちょっと不明なまま質問投稿をしてしまっております。

ですので、ドンピシャのご回答でなくとも、原因突き止めるお力添えをいただけると非常に嬉しいです。

djando内、model, view, template

#models.py
from django.db import models
from django.urls import reverse
from django.core.validators import RegexValidator

class restaurantGenre(models.Model):
    restaurantGenre = models.TextField()

    def __str__(self):
        return self.restaurantGenre


class restaurantArea(models.Model):
    restaurantArea = models.TextField()

    def __str__(self):
        return self.restaurantArea

class restaurantDetail(models.Model):
    restaurantImg = models.FileField(verbose_name='店舗写真')
    restaurantName = models.TextField(verbose_name='店名')
    tel_number_regex = RegexValidator(regex=r'^[0-9]+$', message = ("Tel Number must be entered in the format: '09012345678'. Up to 15 digits allowed."))
    restaurantTelephone = models.CharField(validators=[tel_number_regex], max_length=15,verbose_name='電話番号', default=000000000)
    restaurantLocationAddress = models.TextField(verbose_name='住所')
    restaurantHomepageAddress = models.URLField(verbose_name='URL')
    restaurantRate = models.PositiveIntegerField(verbose_name='レート')
    restaurantCopywriting = models.TextField(verbose_name='一言コピー', default="一言コピーエリア")
    restaurantDetailArea = models.ForeignKey(restaurantArea, verbose_name='エリア',  on_delete=models.PROTECT, default=1)
    restaurantDetailGenre = models.ForeignKey(restaurantGenre, verbose_name='ジャンル',  on_delete=models.PROTECT, default=1)
    restaurantBlog = models.TextField(verbose_name='お店紹介', default='ここにお店を紹介する文章が入ります。')


    def __str__(self):
        return self.restaurantName

    def get_absolute_url(self):
        return reverse("search:index")
#views.py ※更新につき、削除しました。
#selectArea.html ※更新につき、削除しました。


restaurantDetailのデータベース仮データ中身
restaurantDetailのデータベース仮データ中身

restaurantAreaのデータベース仮データ中身
上図のidは、こちらのAreaリストと対応して引っ張っていくようになっています。
restaurantAreaのデータベース仮データ中身
「ここのリンクミスかな?」と検索窓に"2"とか"5"とか入れてみましたが、特に効果ありませんでした。

なお、開発環境は以下の通りです。

言語:python3.7.4
フレームワーク:django 2.0.6
ブラウザ:Google Chrome 77
エディタ:visual studio code 1.38
OS:Windows10 home

以下、2019/10/3追記**

views.pyにloggingモジュールを仕込んで、挙動を見てみました。
それでわかったのは、def文の1個目2個目は問題なく出力してくれており、
変数も差し支えなく渡されている模様でした。

しかし、def文の3個目は、どうにも動いてくれすらしていないようでした。
具体的には、以下のようにLoggingを仕込んだ結果、'Test3'と書かれたものが出力されませんでした。

#views.py ※更新につき、削除しました。


ちなみに、仮にフォームに「渋谷」と書いた場合の出力は、
それぞれ以下のように出力されており、ちゃんと受け渡されている模様です。

logger.info(form_value)   -> ['渋谷']
logger.info(default_data) -> {'area': '渋谷'}
logger.info(test_form)    -> <tr><th><label for="id_area">エリア:</label></th><td><input type="text" name="area" value="渋谷" required id="id_area"></td></tr>
logger.info(q_context)    -> {'view': <restaurantsList.views.selectView object at 0x04734F50>, 'test_form': <searchForm bound=False, valid=False, fields=(area)>}

となると、def get_queryset(self):に該当する部分に問題があるということになるかと思うのですが、
それ以前に動きすらしていないので、原因がわからず......

以下、2019/10/3 夕方追記

@t_obaraさん、引き続きありがとうございます!
いただいたurl拝見しました。
get、get_queryset、get_context_dataの違いについて。
TemplateViewでは、get_querysetがを放ったらかしておくと動いてくれないものなのですね。

class selectView(ListView):


に修正の上、以下を直しました。

(1)"area"という変数を新たにつくってしまっていたことによるエラー
->既存のmodel.pyに準じて、全て"restaurantDetailArea"に修正。

(2)len(restaurantDetailArea)のデフォルト値が、Noneであり、
'NoneType' has no len()エラーを起こす。
->if文で、Noneのときは、無視する条件文を追記することでクリア。

しかし、queryに関する部分のエラーは乗り越えられませんでした......

まず、現状のViews.py(該当のclassのみ)は以下の通りです。

#views.py ※更新につき、削除しました。

エラー文は、以下のとおりです。

Related Field got invalid lookup: icontains

明確に該当部分のエラーだとはわかりつつも、ググって出てくる情報に、
日本語のものがいつも以上に少なく、理解に苦しんでいます。。。

まずは、経過だけ書かせていただき、一休みしたらもうワントライしてみます。

以下、2019/10/6 深夜追記

半泣きになりながら調べては試し、失敗してはまた調べを続けて、ようやっとゴールに近づいてきた感じがします......!
イメージ説明
「プルダウンメニューをつくる」「postメソッドで値を返す」そこまではできているのです。
あとは、参照した値に応じてフィルターをかけるだけなのですが、そこでエラーが起きてしまいます......

#forms.py
from django import forms
from .models import restaurantDetail, restaurantArea, restaurantGenre

areaChoices = [
    (1, '中目黒'),
    (2, '渋谷'),
    (3, '新宿'),
    (4, '恵比寿'),
    (5, '品川'),
]

class selectForm(forms.Form):
    area = forms.ChoiceField(
        label="エリア",
        required=True,
        disabled=False,
        initial=['1'],
        choices=areaChoices,
    )
#views.py
class selectView(ListView):
    model = restaurantDetail
    template_name = 'areaSelect.html'

    def get(self, request):
        f = {'form': selectForm(),}
        return render(request, 'areaSelect.html', f)

    def post(self, *args, **kwargs):
        return self.get_queryset(self)

    def get_queryset(self, request):
        if self.request.method == 'POST':
            form_selected = []
            form_selected.append(self.request.POST.get('area'))
            form_selected_num = form_selected[0]
            return restaurantDetail.objects.filter(restaurantDetailArea=form_selected_num)
        else:
            d = {'form': selectForm(),}
            return render(request, 'areaSelect.html', d) 

上記コードを動かすと、

too many values to unpack (expected 2)


というエラー文が返ってきてしまいます。
なお、上記からは削除しましたが、
loggingを随所に差し込んで、
form_selected_num = form_selected[0]
までは、値のリレーが思惑通りOKな様子も確認できています。

このエラー文について、他の方の投稿などを拝見するに、

#views.py
return restaurantDetail.objects.filter(restaurantDetailArea=form_selected_num)


ここの書き方で、引数(上記の場合"restaurantDetailArea")を書きそびれた結果起きているように見受けられます。
しかし、じぶんのコードの場合そこは満たしており、実際直前に別の形でこのfilterだけを動かしていた内は、問題なく稼働していました。

あまり見受けられない書き方でいうと

#views.py
    def post(self, *args, **kwargs):
        return self.get_queryset(self)```  


この部分が原因かなとも思いつつ、確証はありません。

ここまで来たら、なんとかしたいです!
ので、違和感ある箇所などあれば、ご指摘頂けますと幸いです......!!

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正の依頼

  • t_obara

    2019/10/03 15:06

    だいぶわかってきたかと思います。なぜget_querysetが呼ばれないのか、get_context_dataはどのように利用すべきなのかを理解されると良いと思います。 そして、そのためにこちらを参照するとよろしいかと。 https://teratail.com/questions/118626
    djangoのフレームワークとしての動作が一部理解できてくるかと。

    キャンセル

  • t_obara

    2019/10/03 18:50

    viewがどのように参照するか、テンプレートにより異なるのです。ですので、単に参照するだけであれば、get_context_dataが呼ばれるだけでもOKで、その場合にはテンプレート側でそれに応じた参照の仕方が必要となります。

    キャンセル

  • t_obara

    2019/10/07 10:25

    > too many values to unpack (expected 2)
    これ自体は、用意している変数が2なのに、それ以上の変数を返そうとしているという意味です。
    ログを確認した結果、filterが怪しいとしても、直接その行が問題となるというよりは、returnも
    含め、テンプレート側の問題も考慮されてはいかがでしょうか。

    キャンセル

まだ回答がついていません

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.92%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る