Pythonを勉強していくうちに機械学習を使ってちょっとやってみたいことが出来たのでWebサイトを作るためにDjangoも勉強することに。
- Googleの画像検索みたいに画像をアップロードすると一致する画像と名前を返す。
- 画像アップロード時に対象の主なジャンル(フィギュア/ねんどろいど等)を選択可能にする。
- 一致した名前がヤフオク、メルカリで何円ぐらいで取引されているか検索して結果を表示する。
自分が勤めているのはリサイクルショップなわけですが、買取の商品などで箱などの付属品がないと正直なところ何かわからないです。タイミングよく担当者か分かる人間がいるといいのですが、いないと「なんじゃこりゃ」になるわけです。そのままの状態で適切な値段がつけられないと、お客様は不満に思って、次につながらないという残念な事になってしまいます。そういう時の状況をなんとかしたくて作ろうと思ったわけです。
それよりどっちかというと別部門の人から「Googleの画像検索みたいにスマホで商品写真を撮ってそれが何かわかるようなのって作れない?」という事を聞かれたのがきっかけでもあります。その部門はネット部門だったので販売する時に何かわからないと値付けも満足に出来なくて余計に大変です。(この辺は部門間の連携をうまくすれば良いかもしれないけど、いろいろあるんですよ)
という事で勉強がてら作ってみることにします。
参考にしたのはこの書籍
あまりDjangoの書籍って売ってませんね。需要が低いのかな?
まずはこの書籍を参考にDjangoでテキスト入力と画像アップロードが出来るWebサイトを作ります。この書籍には画像アップロードの事が書かれていなくて色々と調べて作成しました。
とりあえず今回の出来上がりはこんな感じです。
アップロード前 | アップロード後 |
![]() |
![]() |
入力項目として、「名前」「メールアドレス」「年齢」「血液型」「画像」をテキストボックス、コンボボックス、ファイルアップロードを使います。
これらを入力して「Click」ボタンをクリックしてファイルをアップロードして入力した内容を表示します。画像はサムネイル作成して表示します。
![]() |
プロジェクト構成は左図の通り プロジェクト名:django_sample アプリ名:hello で作成します。 |
ここでは作成するアプリ「hello」の追加とアップロードしたイメージの保存先を設定します。
まず、作成するアプリの追加
1 2 3 4 5 6 7 8 9 |
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'hello', #作成するアプリを追加します。 ] |
次にイメージの保存先を定義します。
フォルダ「django_sample」の直下に「media」フォルダを作成します。それをここで定義します。
一緒にTIME_ZONEも変更します。既存で設定されているTIME_ZONEは削除します。
1 2 3 4 |
MEDIA_ROOT = os.path.join(BASE_DIR, 'media') MEDIA_URL = '/media/' TIME_ZONE = 'Asia/Tokyo' |
ここではアプリのパスとアプリのurls.pyをincludeします。
同時にイメージ保存先の定義をします。
最後の2行である「if settings.DEBUG:~」という部分がないとイメージの保存が出来ないそうです。
1 2 3 4 5 6 7 8 9 10 |
urlpatterns = [ path('admin/', admin.site.urls), path('hello/',include('hello.urls')), #この行を追加します。 ] #以下を追加します。 from django.conf import settings from django.conf.urls.static import static if settings.DEBUG: urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) |
「CHOICE」は血液型のコンボボックスの選択内容、
「HelloForm」でWebサイトで実際に表示される項目の定義をします。
「name」「mail」は「forms.CharField」で文字列の入力にします。
「age」は「forms.IntegerField」で数値の入力にします。
「blood」は「forms.ChoiceField」でコンボボックスの入力にして選択内容に「CHOICE」を設定します。
「photo」は「forms.ImageField」で画像入力にします。「required=False」で必須項目でなくします。(required)を定義しないと必須項目になります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
from django import forms CHOICE = ( ('', '-----'), ('0', 'A'), ('1', 'B'), ('2', 'O'), ('3', 'AB'), ) class HelloForm(forms.Form): name = forms.CharField(label='name') mail = forms.CharField(label='mail') age = forms.IntegerField(label='age') blood = forms.ChoiceField(widget=forms.Select, choices=CHOICE) photo = forms.ImageField(required=False) |
「image」はアップロードされた画像ファイルを扱うときに呼び出します。「upload_to」は実際にファイルがコピーされるフォルダです。この場合「settings.py」で定義した「MEDIA_URL」の直下に「hello」を作成しその下に画像ファイルがコピーされます。
「thumbnail」はサムネイル表示する時の設定です。「processors」で画像のサイズ、「format」で形式、「options」で画像の質を設定します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
from django.db import models from imagekit.models import ImageSpecField from imagekit.processors import ResizeToFill class Photo(models.Model): image = models.ImageField(upload_to='hello') thumbnail = ImageSpecField(source='image', processors=[ResizeToFill(300, 300)], format="JPEG", options={'quality': 60} ) |
「params」で設定している値を「index.html」に渡して内容を表示させます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
from django.shortcuts import render from .forms import HelloForm from .models import Photo def index(request): if request.method == 'GET': return render(request, 'hello/index.html', { 'title': 'Hello', 'message': 'your data:', 'form': HelloForm(), }) elif (request.method == 'POST'): form = HelloForm(request.POST, request.FILES) filename = request.FILES['photo'].name if not form.is_valid(): raise ValueError('invalid form') photo = Photo() photo.image = form.cleaned_data['photo'] photo.save() params = { 'title': 'Hello', 'message': 'your data:', 'form': HelloForm(), 'photos': photo.thumbnail } blood = "" if(request.POST['blood'] == "0"): blood = "A" elif (request.POST['blood'] == "1"): blood = "B" elif (request.POST['blood'] == "2"): blood = "O" elif (request.POST['blood'] == "3"): blood = "AB" params['message'] = '名前:' + request.POST['name'] + '<br>メール:' + request.POST['mail'] + '<br>年齢:' + request.POST[ 'age'] + '<br>血液型:' + blood + '<br>画像:' params['form'] = HelloForm(request.POST) return render(request,'hello/index.html',params) |
今度はアプリのurls.pyを修正します。同じファイル名でプロジェクトとアプリにあるとか正直、混乱のもとです。同じ役割なので同じファイル名でも仕方ないですが(´・ω・`)
1 2 3 4 5 6 |
from django.urls import path from . import views urlpatterns = [ path('', views.index, name='index'), ] |
「load static」は「hello/static」フォルダにあるファイルを読み込みます。基本的にstaticフォルダはCSSなどのファイルを作成しておきます。今回は作成していないです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
{% load static %} <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>{{title}}</title> <link rel="stylesheet" type="text/css" href="{% static 'hello/css/style.css' %}" /> </head> <body> <h1>{{title}}</h1> <p>{{message|safe}}</p> <table> <form action="{% url 'index' %}" method="post" enctype="multipart/form-data"> {% csrf_token %} {{ form.as_table }} <div> <img src="{{ photos.url }}" /> </div> <tr><td></td><td><input type="submit" value="click"></td></tr> </form> </table> </body> </html> |
1 |
{{title}} |
「views.py」で設定した「params」の「title」の値を「<title>」タグとの内容として表示します。
1 |
{{message|safe}} |
「views.py」で設定した「params」の「message」の値を表示します。「safe」でエスペープします。
1 |
{% csrf_token %} |
これはクロスサイトリクエストフォージ対策です。Djangoではあらかじめ用意されているのでこの1文で完了です。
1 |
{{ form.as_table }} |
「views.py」で設定した「params」の「form」の値を表示します。「.as_table」でテーブル形式で表示させます。
1 |
{{ photos.url }} |
「views.py」で設定した「params」の「photos」の画像を表示します。