ランダムおすすめ記事

ホームページ作りました

 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)


特に改造しておりません。

管理画面から画像を投稿してみたところちゃんと見られました。

f:id:sr2460:20190124181815p:plain

問題発生

ここで問題発生。 問題① f:id:sr2460:20190124182007p:plain

画像なしで投稿ができない。

問題② f:id:sr2460:20190124182322p:plain

送信ボタンを押すとエラーが出る。 掲示板へのコメントの投稿も画像の投稿も別々なら成功しているので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エンコードを指定を指定しているそうです。

URLエンコード | 用語集 | KDDI株式会社

読み: ゆーあーるえる 英語名: 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で掲示板を作ってみたい⑨ - ニートがベルマーレ好きすぎて会社起こしたけど今後は未定

python、djangoで掲示板を作ってみたい⑩ - ニートがベルマーレ好きすぎて会社起こしたけど今後は未定

python、djangoで掲示板を作ってみたい⑪ - ニートがベルマーレ好きすぎて会社起こしたけど今後は未定