1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Django しょほ

Last updated at Posted at 2020-01-02

Macです。

####環境
venvで環境作ってdjangoインストールします。
$python -m venv <environmentName>
$cd <environmentName>
$source bin/activate
$pip install --upgrade pip
$pip install django==2.0.1
$django-admin startproject <projectName> .
$python manage.py startapp <applicationName>
2019年末でdjangoはバージョン3系です。何もしないでインストールするとそれになり、adminにログインできなくなる場合があるので、2系にしとくのが無難です。

以下で行きます。
environmentName = reh
projectName = rehabili
applicationName = reha



###settings.pyでDjangoの環境設定をいじります。

rehabili/python:setting.py
# LANGUAGE_CODE = 'en-us'
LANGUAGE_CODE = 'ja'

# TIME_ZONE = 'UTC'
TIME_ZONE = 'Asia/Tokyo'

###データベースへの作成 `python manage.py migrate`
###スーパーユーザの追加 `python manage.py createsuperuser` 適当に指示に従います。
###開発サーバの起動 `python manage.py runserver`

http://127.0.0.1:8000/ or http://localhost:8000/ をブラウザで開いてロケットが出てれば成功


###モデルの作成
reh/models.py
from django.db import models


class SamplePost(models.Model):
    postname = models.CharField('name', max_length=999)
    postfrom = models.CharField('from', max_length=999, blank=True)
    postlength = models.IntegerField('length', blank=True, default=0)

    def __str__(self):
        return self.postname


class SamplePost2(models.Model):
    postname2 = models.ForeignKey(SamplePost, verbose_name='postname', related_name='samplepost2', on_delete=models.CASCADE)
    comment = models.TextField('comment', blank=True)

    def __str__(self):
        return self.comment

####管理画面に追加

reh/admin.py
from django.contrib import admin
from reh.models import SamplePost, SamplePost2

admin.site.register(SamplePost)
admin.site.register(SamplePost2)

####アプリの追加

rehabili/python:setting.py
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'reh', #ここに作成したアプリ名を追加
]

makemigratoinsでデータベースに追加するための前処理をします。最後のアプリケーション名はなくても大丈夫ですが、プロジェクトが大きくなると多分長くなります。 `python manage.py makemigrations reh`
データベースに追加 `python manage.py migrate`

####管理画面へログイン
先ほど作ったスーパーユーザーでログイン
http://localhost:8000/admin/
Screen Shot 2019-12-31 at 13.51.38.png

####管理画面を修正
ここを参考にしました。管理画面の一覧から修正できる項目が増えます。
https://qiita.com/kaki_k/items/7b178ad39394a031b50d

reh/admin.py
from django.contrib import admin
from reh.models import SamplePost, SamplePost2


class SamplePostAdmin(admin.ModelAdmin):
    list_display = ('id', 'postname', 'postfrom', 'postlength',)  # 一覧に出したい項目
    list_display_links = ('id', 'postname',)  # 修正リンクでクリックできる項目

admin.site.register(SamplePost, SamplePostAdmin)


class SamplePost2Admin(admin.ModelAdmin):
    list_display = ('id', 'comment',)
    list_display_links = ('id', 'comment',)
    raw_id_fields = ('postname2',)   # 外部キーをプルダウンにしない(データ件数が増加時のタイムアウトを予防)

admin.site.register(SamplePost2, SamplePost2Admin)

####URL スキームの設計
アプリフォルダ内にurls.pyを作成し、プロジェクトのurls.pyからインクルードします。

reh/views.py
from django.shortcuts import render
from django.http import HttpResponse


def reh_list(request):
    return HttpResponse('reh一覧')

reh/urls.py
from django.urls import path
from reh import views

app_name = 'reh'
urlpatterns = [
    path('list/', views.reh_list, name='reh_list'),
]

rehabili/urls.py
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('reh/', include('reh.urls')),
    path('admin/', admin.site.urls),
]

以下のURLが生きてきます
http://127.0.0.1:8000/reh/list/

####フォームを作る

少し横道にそれて、普通にフォームを作ります。ただしこの作り方だとDBに反映できません。

reh/views.py

### 追記です
def formInit(request):
    params = {
        'title':'Hello World',
        'msg':'名前を入力してください',
    }
    return render(request,'reh/hello.html', params)



def formTest(request):
    msg = request.POST['msg']
    params = {
        'title':'Hello World',
        'msg':'hello '+msg+'!',
    }
    return render(request,'reh/hello.html', params)
reh/urls.py
from django.urls import path
from reh import views

app_name = 'reh'
urlpatterns = [
    path('list/', views.reh_list, name='reh_list'),
    path('formInit/', views.formInit, name='formInit'),
    path('formTest/', views.formTest, name='formTest'),
]
reh/template/reh/hello.html
{% load static %}
<!doctype html>
<html lang="ja">
    <head>
        <meta charset="utf-8">
        <title>{{ title }}</title>
    </head>
    <body>
        <h1>{{ title }}</h1>   
        <p>{{ msg }}</p>
        <!--普通のHTMLと同様にactionを指定します-->
        <form action="{% url 'reh:formTest' %}" method = "post"> 
            {% csrf_token %} <!--CSRF対策-->
            <label for = "msg">何か入れて</label>
            <input id = "msg" type="text" name ="msg">
            <input type="submit" value="input">
        </form>
    </body>
</html>

dddd.jpg

ブラウザ上のみでは普通に動きます。
このままじゃDBに反映できないので、Djangoのforms.py、Formクラスを使います。
差分の部分のみ書きます。

reh/views.py
from .forms import formInitForm

def formInit(request):
    # params = {
    #     'title':'Hello World',
    #     'msg':'名前を入力してください',
    # }
    # return render(request,'reh/hello.html', params)

    params = {
        'title':'Hello World',
        'msg':'名前を入力してください',
        'form': formInitForm(),
    }
    if (request.method=='POST'):
        params['msg'] = 'こんにちは!'+request.POST['name']+'さん!<br>'+request.POST['area']+'にお住まいで<br>年齢は'+request.POST['age']+'歳なんですね!<br>よろしくお願いします。'
        params['form']= formInitForm(request.POST)

    return render(request,'reh/hello.html', params)    

# def formTest(request):
#     msg = request.POST['msg']
#     params = {
#         'title':'Hello World',
#         'msg':'hello '+msg+'!',
#     }
#     return render(request,'reh/hello.html', params)


reh/urls.py
    path('formInit/', views.formInit, name='formInit'),
    # path('formTest/', views.formTest, name='formTest'),

テンプレート内はコメントアウトでも中のpython実行されちゃうんで、差分は各自確認ください。

reh/template/reh/hello.html
{% load static %}
<!doctype html>
<html lang="ja">
    <head>
        <meta charset="utf-8">
        <title>{{ title }}</title>
    </head>
    <body>
        <h1>{{ title }}</h1>   

        <p>{{msg|safe}}</p>     
        <form action= "{% url 'reh:formInit' %}" method = "post"> 
            {% csrf_token %} 
            <ul>
            {{form.as_ul}} <!--ここがforms.pyの項目-->    
            </ul>
            <input type="submit" value="input"> 
        </form>

    </body>
</html>

aaa.jpg

####CRUD/ create, read, update, delete
さて、横道から戻して、一覧から修正や削除、追加ができるようにします。
まずは一覧を作ります。

いくつかテンプレートhtml作るので、baseを作ります。適当にcss当ててます。

reh/template/reh/base.html
{% load i18n static %}
<!DOCTYPE html>{% get_current_language as LANGUAGE_CODE %}
<html lang="{{ LANGUAGE_CODE|default:'en-us' }}">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<style>
h4{
  font-size: 20px;
  display: inline-block;
  margin-right: 30px;
}
.container{
    width: 100%;
    max-width: 800px;
    margin: 60px auto;
}
.btn{
  text-decoration: none;
    padding: 5px 10px;
    border: 1px solid #ccc;
    border-radius: 5px;
}
button.btn{
    font-size: 16px;
    display: inline-block;
    line-height: 1;
}
th,td{
  min-width: 100px;
  text-align: center;
}
table{
  border-collapse:collapse;
  margin:0 auto;
}
th{
  color:#005ab3;
  min-width: 120px;
}
td{
  border-bottom:1px dashed #999;
}
th,tr:last-child td{
  border-bottom:2px solid #005ab3;
}
td,th{
  padding:10px;
}
form input{
  padding: 5px;
    font-size: 20px;
    margin-bottom: 20px;
}
form label{
    padding: 5px;
    font-size: 20px;
    margin-bottom: 20px;
    min-width: 90px;
    display: inline-block;
}
.flex{
  display: flex;
}
</style>
{% block extra_css %}{% endblock %}
<title>{% block title %}My rehs{% endblock %}</title>
</head>
<body>
  <div class="container">
    {% block content %}
      {{ content }}
    {% endblock %}
  </div>
{% block extra_js %}{% endblock %}
</body>
</html>
reh/template/reh/reh_list.html
{% extends "reh/base.html" %}

{% block title %}一覧{% endblock title %}

{% block content %}
    <h4>一覧</h4>
    <table class="table table-striped table-bordered">
      <thead>
        <tr>
          <th scope="col">ID</th>
          <th scope="col">NAME</th>
          <th scope="col">FROM</th>
          <th scope="col">LENGTH</th>
        </tr>
      </thead>
      <tbody>
        {% for reh in rehs %} <!-- ① -->
        <tr>
          <th scope="row">{{ reh.id }}</th>
          <td>{{ reh.postname }}</td>
          <td>{{ reh.postfrom }}</td>
          <td>{{ reh.postlength }}</td>
        </tr>
        {% endfor %}
      </tbody>
    </table>
{% endblock content %}

① {% for reh in rehs %} の部分で一覧を読み込みますので、views.pyを修正します。

reh/views.py
def reh_list(request):
#    return HttpResponse('一覧')

    #ここでSamplePostをid順に全て持ってきてrehsに格納
    rehs = SamplePost.objects.all().order_by('id')

    #renderメソッドの第3引数に辞書を入れられるので、上で持ってきたrehsという名前でrehsを入れる。
    return render(request, 'reh/reh_list.html', {'rehs': rehs})

これで http://localhost:8000/reh/list/ に一覧が表示されます。

次に追加ボタンを作成します。

reh/template/reh/reh_list.html
{% extends "reh/base.html" %}

{% block title %}一覧{% endblock title %}

{% block content %}
    <h4>一覧</h4>
    <!-- ここに追加 -->
    <a href="{% url 'reh:reh_add' %}" class="btn">追加</a>
    <table class="table table-striped table-bordered">
      <thead>
        <tr>
          <th scope="col">ID</th>
          <th scope="col">NAME</th>
          <th scope="col">FROM</th>
          <th scope="col">LENGTH</th>
        </tr>
      </thead>
      <tbody>
        {% for reh in rehs %} <!-- ① -->
        <tr>
          <th scope="row">{{ reh.id }}</th>
          <td>{{ reh.postname }}</td>
          <td>{{ reh.postfrom }}</td>
          <td>{{ reh.postlength }}</td>
        </tr>
        {% endfor %}
      </tbody>
    </table>
{% endblock content %}

{% url 'reh:reh_add' %} reh_add をurls.pyに追加します。
reh_edit というviewを追加します。views.pyのreh_editを呼び出すようにします。

reh/urls.py
path('list/add/', views.reh_edit, name='reh_add'),
reh/views.py
def reh_edit(request, reh_id=None):
    reh_temp = SamplePost()

    if request.method == 'POST':
        #追加ページでフォームをPOSTする場合の処理
        form = SamplePostForm(request.POST, instance=reh_temp)
        #POSTされたformのバリデーション
        if form.is_valid():
            reh_temp = form.save(commit=False)
            reh_temp.save()
            #formの保存が終わったら一覧に戻ります
            return redirect('reh:reh_list')

    else: #GET時、一覧から追加ボタンを押した時はこちらを表示
        #SamplePostインスタンスからフォームを作成
        form = SamplePostForm(instance=reh_temp)

    #辞書にformとreh_id=Noneを入れてrenderメソッドで編集用ページ遷移させます
    return render(request, 'reh/reh_edit.html', dict(form=form, reh_id=reh_id))

上でのformのモデルをforms.pyで作ります。

reh/forms.py
from django.forms import ModelForm
from reh.models import SamplePost

class SamplePostForm(ModelForm):
    #すでにSamplePostで定義してあるプロパティを使用する場合はMetaクラスで
    class Meta:
        model = SamplePost
        # 明示的もしくはモデルの一部のプロパティだけ使う場合
        fields = ('postname', 'postfrom', 'postlength', )

編集用ページテンプレートを作成します。

reh/template/reh/reh_edit.html
{% extends "reh/base.html" %}

{% block title %}タイトル{% endblock title %}

{% block content %}
  <!-- formのアクションとして、formの値をreh_editビューに送ります -->
  <form action="{% url 'reh:reh_add' %}" method="post">      
    {% csrf_token %}
    #後述するforms.pyを呼びます
    {{ form.as_ul }}
    <div>
      <button type="submit" class="btn">送信</button>
    </div>
  </form>
  <a href="{% url 'reh:reh_list' %}" class="btn">戻る</a>
{% endblock content %}

次に簡単な削除を(確認画面とかなしでいきなり消えるので簡単)

reh_idを取得してそれを消します。

templateにボタンを追加し、id付きで次に作るviewに飛ばします。

reh/template/reh/reh_list.html
{% extends "reh/base.html" %}

{% block title %}一覧{% endblock title %}

{% block content %}
    <h4>一覧</h4>
    <!-- ここに追加 -->
    <a href="{% url 'reh:reh_add' %}" class="btn">追加</a>
    <table class="table table-striped table-bordered">
      <thead>
        <tr>
          <th scope="col">ID</th>
          <th scope="col">NAME</th>
          <th scope="col">FROM</th>
          <th scope="col">LENGTH</th>
          <th scope="col">操作</th>
        </tr>
      </thead>
      <tbody>
        {% for reh in rehs %} <!-- ① -->
        <tr>
          <th scope="row">{{ reh.id }}</th>
          <td>{{ reh.postname }}</td>
          <td>{{ reh.postfrom }}</td>
          <td>{{ reh.postlength }}</td>
      <td>
            <!-- aタグのリンク先にreh_del viewにして、引数にIDつける -->
            <a href="{% url 'reh:reh_del' reh_id=reh.id %}" class="btn">削除</a>
          </td>
        </tr>
        {% endfor %}
      </tbody>
    </table>
{% endblock content %}
reh/views.py

def reh_del(request, reh_id):
    #指定したIDのインスタンスがある場合はそれを、ない場合は404(django.http.Http404)呼び出し、
    #その後deleteして一覧にリダイレクト。
    reh = get_object_or_404(SamplePost, pk=reh_id)
    reh.delete()
    return redirect('reh:reh_list')

URLはこれですね。

reh/urls.py
path('list/del/<int:reh_id>/', views.reh_del, name='reh_del'),

最後に修正ボタンを。
一覧ページにボタンをつけましょう。

reh/template/reh/reh_list.html
{% extends "reh/base.html" %}

{% block title %}一覧{% endblock title %}

{% block content %}
    <h4>一覧</h4>
    <!-- ここに追加 -->
    <a href="{% url 'reh:reh_add' %}" class="btn">追加</a>
    <table class="table table-striped table-bordered">
      <thead>
        <tr>
          <th scope="col">ID</th>
          <th scope="col">NAME</th>
          <th scope="col">FROM</th>
          <th scope="col">LENGTH</th>
          <th scope="col">操作</th>
        </tr>
      </thead>
      <tbody>
        {% for reh in rehs %} <!-- ① -->
        <tr>
          <th scope="row">{{ reh.id }}</th>
          <td>{{ reh.postname }}</td>
          <td>{{ reh.postfrom }}</td>
          <td>{{ reh.postlength }}</td>
      <td>
            <!-- 修正ボタン追加 これも引数にidを。追加を同じviewを使います。 -->
            <a href="{% url 'reh:reh_mod' reh_id=reh.id %}" class="btn ">修正</a>
            <a href="{% url 'reh:reh_del' reh_id=reh.id %}" class="btn">削除</a>
          </td>
        </tr>
        {% endfor %}
      </tbody>
    </table>
{% endblock content %}

views.pyのreh_editを修正します。

reh/views.py
def reh_edit(request, reh_id=None):
    #追加の場合との場合わけは、idを引数に必要とするかどうかなのでそれを利用
    #reh_tempに値が入っているかであとは追加と同じ処理
    if reh_id:
        #修正場合の処理。インスタンスは既存の値
        reh_temp = get_object_or_404(SamplePost, pk=reh_id)
    else:
        #こっちが新規で追加する場合の処理。インスタンスは初期値になっている
        reh_temp = SamplePost()

    if request.method == 'POST':
        form = SamplePostForm(request.POST, instance=reh_temp)
        if form.is_valid():
            reh_temp = form.save(commit=False)
            reh_temp.save()
            return redirect('reh:reh_list')

    else:
        form = SamplePostForm(instance=reh_temp)

    return render(request, 'reh/reh_edit.html', dict(form=form, reh_id=reh_id))

reh/urls.py
path('list/mod/<int:reh_id>/', views.reh_edit, name='reh_mod'),

編集用ページテンプレートも追加のみでなく修正にも対応させます。

reh/template/reh/reh_edit.html
{% extends "reh/base.html" %}

{% block title %}タイトル{% endblock title %}

{% block content %}
    <!-- views.pyと同様に、reh_idの有無で判断します -->
    {% if reh_id %}
    <form action="{% url 'reh:reh_mod' reh_id=reh_id %}" method="post">
    {% else %}
    <form action="{% url 'reh:reh_add' %}" method="post">
    {% endif %}
      {% csrf_token %}
      <ul>
      {{ form.as_ul }}
      </ul>
      <div class="flex">
          <button type="submit" class="btn">送信</button>
          <a href="{% url 'reh:reh_list' %}" class="btn">戻る</a>
      </div>
    </form>
{% endblock content %}

以下のようなものができたと思います。
Screen Shot 2020-01-02 at 16.52.02.png

Screen Shot 2020-01-02 at 16.52.12.png
1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?