Help us understand the problem. What is going on with this article?

Django しょほ

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
# 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
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

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした