Why not login to Qiita and try out its useful features?

We'll deliver articles that match you.

You can read useful information later.

2
6

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 5 years have passed since last update.

[django] 基本メモ(単語帳を作る)

Last updated at Posted at 2018-03-31

django単語帳(備忘録)

djangoの基本的なコマンドを使って単語帳を作る。

プロジェクト生成

command
django-admin startproject prj
cd prj
python manage.py startapp vocaApp

次のような構造になる。

tree
C:.
│  manage.py
│
├─prj
│  │  settings.py
│  │  urls.py
│  │  wsgi.py
│  │  __init__.py
│  │
│  └─__pycache__
│          settings.cpython-36.pyc
│          __init__.cpython-36.pyc
│
└─vocaApp
    │  admin.py
    │  apps.py
    │  models.py
    │  tests.py
    │  views.py
    │  __init__.py
    │
    └─migrations
            __init__.py

設定

settings.pyを変更。
defaultはsqliteになっているがpostgresqlを使う。
postgresqlなかったらインストールし、
pip install psycopg2でpsycopg2を手に入れる。

settings.py
INSTALLED_APPS = [
    'vocaApp.apps.VocaappConfig',
...
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': 'postgres',
        'USER': 'postgres',
        'PASSWORD': '...',
        'HOST': 'localhost',
        'PORT': '5432',
    }
}
...
TIME_ZONE = 'Asia/Tokyo'
prj/urls.py
...
from django.urls import path, include

urlpatterns = [
    path('', include('vocaApp.urls')),
...

モデル

モデルー>DB
migrateするとvocaApp_prjのようなテーブルが生成される。

models.py
class Vocabulary(models.Model):
    # 自動増加id
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=50)
    mean = models.TextField(max_length=100)
    example = models.TextField(max_length=300, blank=True, null=True)
    mem_count = models.IntegerField(blank=True, null=True, default=0)
    check = models.NullBooleanField(blank=True, null=True, default=False)
    # 生成時のtimestamp
    created_date = models.DateTimeField(auto_now_add=True)
    # 変更時のtimestamp
    modified_date = models.DateTimeField(auto_now=True)

DB->モデル(djangoを使うならモデルー>DBの方が良い、既存のテーブルからdjangoにするとき使う。)
先にpgadminなどでテーブルを作った後inspectdbでmodelスクリプトを得てmodels.pyにコピー

command
python manage.py inspectdb vocaApp_prj

フォーム

データを受けるModelFormを作成

forms.py
from django import forms
from .models import *

class VocaForm(forms.ModelForm):
    class Meta:
        model = Vocabulary
        fields = '__all__'

ビュー

ビジネスロジックとhtmlにrenderするviews.py

views.py
from django.views import generic
from django.shortcuts import render, redirect
from django.views.decorators.http import require_http_methods
from .forms import *
from .models import *

# Create your views here.
class Voca(generic.FormView):
    template_name = "index.html"
    form_class = VocaForm
    success_url = '/'

    def get_context_data(self, **kwargs):
        ctx = super().get_context_data(**kwargs)
        ctx['vocabulary'] = Vocabulary.objects.all().order_by("created_date")
        return ctx

    def form_valid(self, form):
        form.save()
        return super().form_valid(form)

@require_http_methods(["POST"])
def update(req):
    form = VocaForm(req.POST)
    name = form["name"].value()
    result = Vocabulary.objects.filter(name=name)
    if result:
        try:
            if form.is_valid():
                result[0].name = name
                result[0].mean = form["mean"].value()
                result[0].example = form["example"].value()
                result[0].mem_count = int(form["mem_count"].value())
                result[0].check = bool(form["check"].value())
                result[0].save()
                return redirect("/")
            else:
                raise Exception("Form validation failed")
        except Exception as e:
            return render(req, 'index.html', {"form" : form,
                                              "vocabulary" : Vocabulary.objects.all().order_by("created_date")})
    else:
        error_msg = "There is no vocabulary that name is %s"%name
        return render(req, 'error.html', {"error_msg" : error_msg})

@require_http_methods(["GET"])
def delete(req):
    id = req.GET["id"]
    Vocabulary.objects.filter(pk=id).delete()
    return redirect("/")

URL

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

urlpatterns = [
    path('', views.Voca.as_view()),
    path('update', views.update),
    path('delete', views.delete)
]

テンプレート

html templateの作成

templates/index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Voca</title>
    {% load static %}
    <script src="{% static 'js/jquery-3.3.1.min.js' %}"></script>
</head>
<body>
<table border="1" style="border-collapse: collapse;">
    <thead>
        <tr>
           <th id="name">単語</th>
           <th id="mean">意味</th>
           <th id="example">例文</th>
           <th>記憶カウント</th>
           <th>チェック</th>
           <th>削除ボタン</th>
        </tr>
    </thead>
    <tbody>
    <!-- None処理してないのでvocabularyを何も登録しないとエラー発生 -->
    {% for voca in vocabulary %}
        <tr>
            <td><span class="c1">{{ voca.name }}</span></td>
            <td><span class="c2">{{ voca.mean }}</span></td>
            <td><span class="c3">{{ voca.example }}</span></td>
            <td><span class="c4">{{ voca.mem_count }}</span></td>
            <td><span class="c5">{{ voca.check }}</span></td>
            <td><input type="button" value="削除" onclick="deleteById({{ voca.id }})"></td>
        </tr>
    {% endfor %}
    </tbody>
</table>
<form action="" method="post">
    {% csrf_token %}
    {{ form.as_p }}
    <input type="reset" value="リセット">
    <input type="submit" value="挿入">
    <input type="button" value="修正" onclick="update()">
</form>
<script src="{% static 'js/local.js' %}"></script>
</body>
</html>
error.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Error</title>
</head>
<body>
{{ error_msg }}
</body>
</html>

Javascript

static javascript

static/js/local.js
// thを押して単語の意味などを隠す
var nameVisable = true
var meanVisable = true
var exampleVisable = true

$("#name, #mean, #example").click(function() {
    if ($(this).attr("id") === "name") {
        if (nameVisable) {
            $(".c1").hide()
            nameVisable = false
        } else {
            $(".c1").show()
            nameVisable = true
        }
    } else if ($(this).attr("id") === "mean") {
        if (meanVisable) {
            $(".c2").hide()
            meanVisable = false
        } else {
            $(".c2").show()
            meanVisable = true
        }
    } else if ($(this).attr("id") === "example") {
        if (exampleVisable) {
            $(".c3").hide()
            exampleVisable = false
        } else {
            $(".c3").show()
            exampleVisable = true
        }
    };
})

// 単語の名前を押すとFormに値をセット
$(".c1").click(function() {
    $("input[name='name']").val($(this).html())
    var i = 0
    $.each($(this).parent().siblings(), function() {
        if (i === 0) {
            $("textarea[name='mean']").val($(this).find("span").html())
        } else if (i === 1) {
            $("textarea[name='example']").val($(this).find("span").html())
        } else if (i === 2) {
            $("input[name='mem_count']").val($(this).find("span").html())
        } else if (i === 3) {
            if ($(this).find("span").html() === "True") {
                $("select[name='check'] option[value='2']").attr('selected','selected');
            } else if ($(this).find("span").html() === "False") {
                $("select[name='check'] option[value='3']").attr('selected','selected');
            }
        }
        i++
    })
})

// delete 単語
function deleteById(id) {
    $.get("/delete", {"id" : id})
    location.href = "/"
}

// update 単語
function update() {
    $("form").attr("action", "/update").submit()
}

最終フォルダーのtree構造

最後にprjのtree構造は以下のようになる。

tree構造
C:.
│  manage.py
│  run.py
│
├─vocaApp
│  │  admin.py
│  │  apps.py
│  │  forms.py
│  │  models.py
│  │  tests.py
│  │  urls.py
│  │  views.py
│  │  __init__.py
│  │
│  ├─migrations
│  │  │  0001_initial.py
│  │  │  __init__.py
│  │  │
│  │  └─__pycache__
│  │          0001_initial.cpython-36.pyc
│  │          __init__.cpython-36.pyc
│  │
│  ├─static
│  │  └─js
│  │          jquery-3.3.1.min.js
│  │          local.js
│  │
│  ├─templates
│  │      error.html
│  │      index.html
│  │      __init__.py
│  │
│  └─__pycache__
│          admin.cpython-36.pyc
│          apps.cpython-36.pyc
│          forms.cpython-36.pyc
│          models.cpython-36.pyc
│          urls.cpython-36.pyc
│          views.cpython-36.pyc
│          __init__.cpython-36.pyc
│
└─vocabulary
    │  settings.py
    │  urls.py
    │  wsgi.py
    │  __init__.py
    │
    └─__pycache__
            settings.cpython-36.pyc
            urls.cpython-36.pyc
            wsgi.cpython-36.pyc
            __init__.cpython-36.pyc

Build & Run

build & run

command
python manage.py makemigrations
python manage.py migrate
python manage.py runserver

Fake Migrate

テーブルがおかしくなりやり直したいとき

command
python manage.py migrate --fake vocaApp zero
2
6
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

Qiita Conference 2025 will be held!: 4/23(wed) - 4/25(Fri)

Qiita Conference is the largest tech conference in Qiita!

Keynote Speaker

ymrl、Masanobu Naruse, Takeshi Kano, Junichi Ito, uhyo, Hiroshi Tokumaru, MinoDriven, Minorun, Hiroyuki Sakuraba, tenntenn, drken, konifar

View event details
2
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?