python、djangoで掲示板を作ってみたい④
ということで1つのページでコメントの投稿、画像の投稿、投稿画面の表示、投稿画像の表示ができるように改造してみましたよ!!!
完成したサイトはこちら。このサイトの制作日記の④になります! http://160.16.55.98/board/
python、djangoで掲示板を作ってみたい④
admin.py
#!/usr/bin/env python # -*- coding: utf-8 -*- from django.contrib import admin from .models import Post class PostAdmin(admin.ModelAdmin): search_fields = ['text'] admin.site.register(Post, PostAdmin)
画像投稿もPostモデルに集約してしまうのでこれだけで十分です。
forms.py
#!/usr/bin/env python # -*- coding: utf-8 -*- from django import forms from django.views import generic from .models import Post class PostForm(forms.ModelForm): #fileアップロード部分のラベルを消去 file = forms.FileField( label='' ) class Meta: model = Post fields = ('name', 'text', 'file')
以前はmodels.pyにUploadFileというclassを作ってそこからformを生成していました
#class UploadModelForm(forms.ModelForm): #class Meta: #model = UploadFile #fields = '__all__'
しかし画像投稿フォームはPostに統合したため上のコードは削除しました。
ちなみに
#fileアップロード部分のラベルを消去 file = forms.FileField( label='' )
デフォルトで画像ファイルの横にmodelsで指定した名前のファイルという文字が出てしまうんですよ。 ちなみにmodelsの方の文字を消してもfield名が表示されてしまうので、forms.pyでlabel=''として名前をhtml上で見えないようにしているのです。
#!/usr/bin/env python # -*- coding: utf-8 -*- from django.db import models from django.utils import timezone class Post(models.Model): class Meta: verbose_name = '投稿' verbose_name_plural = '投稿リスト' name = models.CharField('名前', max_length=20) text = models.TextField('本文') date = models.DateTimeField('日付', default=timezone.now) file = models.FileField('ファイル', blank=True, null=True) def __str__(self): return self.text
fileフィールドがPostクラスに統合されましたよ。 マイグレートするときにエラーが出るのでblank=True, null=Trueとしましたよ。 これで画像なしでも投稿できるはずなんですが・・・なぜか今のことろ画像が無いと投稿できません。
urls.py
#!/usr/bin/env python # -*- coding: utf-8 -*- from django.urls import path from . import views app_name = 'board' urlpatterns = [ path('', views.FormAndListView.as_view(), name='board'), ]
1画面に機能を集約しているのでurls.pyもこれだけです。
views.py
#!/usr/bin/env python # -*- coding: utf-8 -*- from .models import Post#, UploadFile from django.urls import reverse_lazy from django.shortcuts import render from .forms import PostForm#, uploadModelForm from django.views import generic class FormView(generic.CreateView): model = Post form_class = PostForm template_name = 'board/board.html' success_url = reverse_lazy('board:board') class ListView(generic.ListView): model = Post def get_queryset(self): return Post.objects.order_by('-date') class FormAndListView(FormView, ListView,): def get(self, request, *args, **kwargs): 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} return render(request, 'board/board.html', context)
特に改造しておりません。
管理画面から画像を投稿してみたところちゃんと見られました。
問題発生
ここで問題発生。 問題①
画像なしで投稿ができない。
問題②
送信ボタンを押すとエラーが出る。 掲示板へのコメントの投稿も画像の投稿も別々なら成功しているのでMixするとエラーが発生してしまうのですね。 おそらくviews.pyの問題だと思うのですが・・・。
統合前は動作していた
def __str__(self): return self.file.url
これがあることで
The 'file' attribute has no file associated with it.
Error during template rendering
<li{% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message|capfirst }}</li>
エラーが出てしまう。ここらへんにエラーのカギがありそうなんですよねえ・・・。
超単純な付け忘れ
と思ったら問題②は
def __str__(self): return self.file.url
はこれを消したら解決。これはOKです。もともとreturn self.textを使いたかったし。
そして問題①は超単純でした。
<form action="" method="POST" enctype="multipart/form-data"> {{ form.as_p }} {% csrf_token %} <button type="submit">送信</button> </form>
enctype="multipart/form-data"
がないと画像の送信ができずにエラーが出るのです。これ最初はコピペしてアップロードしてたし、普段使わないから意識してなかった・・・。
enctype="multipart/form-data"についてぐぐりました
せっかくだからなぜこれが必要なのか検索
enctype='multipart/form-data'ってなんだ? - MUGENUP技術ブログ
html - ファイルをアップロードするときにフォームenctype = multipart/form-dataが必要なのはなぜですか?
ここら辺がよさげ。
昔は HTTPの最初のバージョン0.9にはヘッダがありませんでした。HTTPの仕様策定が進められるに従って、HTTPで転送する本文のメタデータを表現するために電子メールのメッセージ仕様(RFC822)のヘッダ形式を借りてくる形で追加されました。
Webを支える技術 P.126
HTMLタグ/フォームタグ/送信時のデータ形式を指定する - TAG index
普段のフォームでもデフォルトでenctype=""となっておりその場合URLエンコードを指定を指定しているそうです。
読み: ゆーあーるえる 英語名: Uniform Resource Locator
URLとは、インターネット上の情報資源の場所を示すもの。インターネットの技術を標準化する組織であるIETFがRFC 1738等で規定している。 インターネットのブラウザでURLを指定すれば、情報資源にアクセスできるようになっているが、もし情報資源がそのアドレスから移動すれば、参照できなくなる。URLは、スキームを指示する「http」などから始まり、ホスト名、パス名という順に記載される。スキーム名はhttp以外にもftpやmailtoなどさまざまなものがある。 URLの上位概念にURIがあり、URIはURLとURNで構成されている。URLが情報資源の場所を表しているのに対し、URNは情報資源の名前を表している。URLとURNは補完関係あるといえる。 URNでは情報資源の名前を把握することで、直接アクセスできる手段ではないが、情報資源に名前が付与されることよって永続的に把握することができる。URNは、「urn:」で始まり名前空間識別子、名前空間固有文字列と続けて表記される。
あー。フォーム送信時に画像のurlを探しに行くんだけどそれは普通のURLじゃないからenctype="multipart/form-data"で指定して探せるようにしないといけないって感じなのかな。 なんか直観的な理解なのが悔やまれます・・・。
python、djangoで掲示板を作ってみたい① - ニートがベルマーレ好きすぎて会社起こしたけど今後は未定
python、djangoで掲示板を作ってみたい② - ニートがベルマーレ好きすぎて会社起こしたけど今後は未定
python、djangoで掲示板を作ってみたい③ - ニートがベルマーレ好きすぎて会社起こしたけど今後は未定
python、djangoで掲示板を作ってみたい④ - ニートがベルマーレ好きすぎて会社起こしたけど今後は未定
python、djangoで掲示板を作ってみたい⑤ - ニートがベルマーレ好きすぎて会社起こしたけど今後は未定
python、djangoで掲示板を作ってみたい⑥ - ニートがベルマーレ好きすぎて会社起こしたけど今後は未定
python、djangoで掲示板を作ってみたい⑦ - ニートがベルマーレ好きすぎて会社起こしたけど今後は未定
python、djangoで掲示板を作ってみたい⑧ - ニートがベルマーレ好きすぎて会社起こしたけど今後は未定
python、djangoで掲示板を作ってみたい⑨ - ニートがベルマーレ好きすぎて会社起こしたけど今後は未定