ここからは細かいところやcssについてやっていこうかとおもいます。 が・・・その前に割と大きな問題が!!!
画像を付けないと投稿できない!!!!
コードを見ていくと。 models.pyのアップロード部分は
file = models.FileField('ファイル', null=True, blank=True)
で普通に考えると良いはずなんですけど画像なしでのアップロードが不可能なんですよねぇ・・・。
ここからは細かいところ
なぜかといろいろぐぐっていてようやく正解にたどり着きました。
python - Django - フォームFileFieldエラー "このフィールドは必須です"
models.pyはこう
image = models.FileField(upload_to='path')
forms.pyに追加
image = forms.FileField(required=False)
これでいけるんか!?マジか!?
というわけでこれを僕のプログラムに当てはめると、class Postのfileフィールドが
file = models.FileField('ファイル', null=True)
forms.pyは
class PostForm(forms.ModelForm): file = forms.FileField(required=False) #fileアップロード部分のラベルを消去 file = forms.FileField( label='', required=False, ←変更箇所 ) class Meta: model = Post fields = ('name', 'text', 'file')
こうなる。 null=Trueのところは他の方法でいけそうなんだけど書き換えるとmigrationsでエラーじゃないけれど怖い文章(w)が出てしまうのでとりあえずこれでオッケーにします。
続いては別アプリケーションへのリンク。 まあこれは最悪url手打ちでいいと思うんですが同プロジェクト内別アプリへのリンクについて。
Python - Django 複数アプリケーション間のリンクが作りたい|teratail
僕はmysiteというプロジェクトにpollsアプリという投票アプリケーションとboardアプリという掲示板アプリケーションを作っています。 ですのでアンケートサイトの方に
<p><a href="http://localhost:8000/board/">さらに語り合いたい人は掲示板へ</a></p>
というリンクを加えました。
また掲示板の方に
<p><a href="http://localhost:8000/polls/">現在おこなっているアンケート</a></p>
というリンクを設けました。 ・・・でも何か足りないなあ。実際に現在行っている最新のアンケートに遷移・・・まではいかなくてもせめて最新のアンケートの表示くらいはさせたいです。
別アプリからのpathを通してmodelをインポートしてみよう
というわけでboardアプリケーション内でpollsアプリケーションのmodelが使えれば表示まで行けるのではないかと思い頑張ってみました。
まず参考になったのがここ
Pythonでディレクトリの上層にあるモジュールをimportするときの注意点 - 長時間睡眠記
pollsアプリケーションのviews.pyに
from ..polls.models import Question
(.でディレクトリを上に1つ移動してる(んだよね…たぶん)ので..2つでviewsからmysiteというプロジェクトにたどり着けます。 そこから.polls(mysite内のpollsディレクトリ)、.models(pollsディレクトリの中のmodels.py)、と移動していきます。 そしてmodels.py内のclass Questionのモデルにアクセス。
・・・
・・・
出来なかったんですよ。
ValueError: Attempted relative import beyond toplevel package
こんなエラーが出てしまって。 どうすればよいか試行錯誤した結果ここら辺の情報にたどり着きました。
Python - 別ディレクトリにあるファイルのインポート - ぼっち勉強会
import sys sys.path.append('../')
このコードを書かないと上層部へのパスが通らないみたいです。先ほども説明しましたが(..)で2階層上層に移動します。 そしてそのあとに
from polls.models import Question
と書きました。これでエラーが出なくなった。 さらに views.pyを改造
class FormAndListView(FormView, ListView, TemplateResponseMixin): def get(self, request, *args, **kwargs): question = get_object_or_404(Question) ←追加 formset = PostForm(request.POST or None, files=request.FILES or None) formView = FormView.get(self, request, *args, **kwargs) listView = ListView.get(self, request, *args, **kwargs) formData = formView.context_data['form'] listData = listView.context_data['object_list'] context = {'form' : formData, 'post_list' : listData, 'question' : question} ← 'question':questionを追加 return render(request, 'board/board.html', context)
ここを追加しましたよ
question = get_object_or_404(Question) ←追加 'question' : question} ← 'question':questionを追加
これでquestionのデータがhtmlに渡ったはず。 さらにboard.htmlに
<p><a href="http://localhost:8000/polls/">現在おこなっているアンケート:{{ question.question_text }}</a></p>
すると・・・。
いま、わたし・・少しだけ夢に近づきました!
このあとやることは最新のもの、もしくは現在アンケートを取っているページのみが表示されるように改造できないか? リンクはindexページでなくアンケートページに直接飛べないか? ここら辺でしょうかね。
しかし問題が・・・。
と思っていたところでこの後問題が起きてしまいました。 アンケート側の質問を複数に増やすとキーが複数になってしまうのでエラーが出てしまいました。 でいろいろ試行錯誤して、とりあえずQustionを全て取得したらどうなんだろう?と思いまして。
class FormAndListView(FormView, ListView, TemplateResponseMixin): def get(self, request, *args, **kwargs): question = get_object_or_404(Question) ←変更するならここだよな・・・。
う~~~ん。
えいっ!
question = Question.objects.all()
やった!!!!エラー出ない!表示された!!!
ここからフィルターかけられるかなあ?と思って関数側とかhtml側とか色々いじっていたんですが上手くいかず。
仕方ないので犬の散歩に。
するとあることを思い出します。 (※余談ですけど煮詰まった後に犬の散歩したりその日はやめてお風呂入ったり寝ちゃったりすると不思議とアイデアが浮かぶんですよ。休息って大事!)
pollsアプリケーションで同じようなフィルター作ったよな・・・。というわけで当時作ったコードをチェック。
models.py
class Question(models.Model): question_text = models.CharField(max_length=200) pub_date = models.DateTimeField('date published') date_limit = models.DateTimeField('公開期限', default = timezone.now() + timedelta(days=7) ) def is_date_limit(self): # まだ公開期限を過ぎていないならTrue now = timezone.now() return now <= self.date_limit
detail.html
{% extends 'polls/base.html' %} {% block content %} {% load static %} <link rel="stylesheet" type="text/css" href="{% static 'polls/style.css' %}"> <strong>{{ question.question_text }}の投票画面</strong> <br> <strong><a href="{% url 'polls:results' question.id %}">結果を見る</a></strong> <p>集計期間{{ question.pub_date}}~{{ question.date_limit}}</p> {% if question.is_date_limit %} {% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %} <form action="{% url 'polls:vote' question.id %}" method="POST"> {{ form.non_field_errors }} {% for field in form %} <div class="form-group"> <label for="{{ field.id_for_label }}">{{ field.label_tag }}</label> {{ field }} {{ field.errors }} </div> {% endfor %} {% csrf_token %} <button type="submit" class="btn btn-dark">送信</button> </form> {% endif %} {% endblock %}
ああそうか。modelsの下に関数作って(これは教えてもらった)htmlでif文でフィルターかけたんだ。これで公開期限がすぎた質問はフィルターで表示できないようにしたんでしたね・・・。
これを応用すると・・・。
こうかな???
<p><a href="http://localhost:8000/polls/">現在投票中のアンケート一覧{% if question.is_date_limit %}{% for questions in question %}<li>{{ questions.question_text }}</li>{% endfor %}{% endif %}</a></p>
あ~~!全部消えよりました!!!でもおかしいなぁ。pollsアプリケーションでちゃんと動作してたんだからなあ・・・。
import sys
で書いたけどclass内関数まで呼び出せていないのかなあ???? ・・・というわけでclass内関数を呼び出せてないと思ってそっち方面を散々あたったのですが・・・。違いました。
結論から言うとできた!!!
ちなみにif文のフィルターのかけ方が間違っていて、
<p><a href="http://localhost:8000/polls/">現在投票中のアンケート一覧{% for questions in question %}{% if questions.is_date_limit %}<li>{{ questions.question_text }}</li>{% endif %}{% endfor %}</a></p>
としてfor文の後ifをはさみquestionをquestionsにすることで解決いたしました!
やった!!!!
これでプログラム的な課題はあと1つ!!!!そしたらcssの作成じゃ!!!! それは次回以降に回します。 ただ解決できなかったらいつか修正することにしてcss書いちゃいます。
python、djangoで掲示板を作ってみたい① - ニートがベルマーレ好きすぎて会社起こしたけど今後は未定
python、djangoで掲示板を作ってみたい② - ニートがベルマーレ好きすぎて会社起こしたけど今後は未定
python、djangoで掲示板を作ってみたい③ - ニートがベルマーレ好きすぎて会社起こしたけど今後は未定
python、djangoで掲示板を作ってみたい④ - ニートがベルマーレ好きすぎて会社起こしたけど今後は未定
python、djangoで掲示板を作ってみたい⑤ - ニートがベルマーレ好きすぎて会社起こしたけど今後は未定
python、djangoで掲示板を作ってみたい⑥ - ニートがベルマーレ好きすぎて会社起こしたけど今後は未定
python、djangoで掲示板を作ってみたい⑦ - ニートがベルマーレ好きすぎて会社起こしたけど今後は未定
python、djangoで掲示板を作ってみたい⑧ - ニートがベルマーレ好きすぎて会社起こしたけど今後は未定
python、djangoで掲示板を作ってみたい⑨ - ニートがベルマーレ好きすぎて会社起こしたけど今後は未定