Djangoを勉強してみる_モデルを学ぶ_その8(入門編)

Pocket

前回の続きで、Djangoについて学んでいきます。

今回もモデルについて勉強していきます。

Djangoの勉強内容は以下の本を参考にしています。

参考

Python Django3超入門 (日本語) 単行本 – 2020/6/13 掌田 津耶乃 (著)

モデル
クエリを作成する

コードは以前の記事を参考にしてください。

Djangoを勉強してみる(入門編)
Djangoを勉強してみる(入門編その2)
Djangoを勉強してみる_urlを学ぶ(入門編)
Djangoを勉強してみる_テンプレートを学ぶ(入門編)
Djangoを勉強してみる_テンプレートを学ぶ_その2(入門編)
Djangoを勉強してみる_フォームを学ぶ_その1(入門編)
Djangoを勉強してみる_フォームを学ぶ_その2(入門編)
Djangoを勉強してみる_フォームを学ぶ_その3(入門編)
Djangoを勉強してみる_モデルを学ぶ_その1(入門編)
Djangoを勉強してみる_モデルを学ぶ_その2(入門編)
Djangoを勉強してみる_モデルを学ぶ_その3(入門編)
Djangoを勉強してみる_モデルを学ぶ_その4(入門編)
Djangoを勉強してみる_モデルを学ぶ_その5(入門編)
Djangoを勉強してみる_モデルを学ぶ_その6(入門編)
Djangoを勉強してみる_モデルを学ぶ_その7(入門編)

今回の目的

前回はデータベース中身から必要なものを検索する機能を勉強しました。

今回はデータベースのリレーションシップについて勉強していきます。

リレーションシップとは

リレーションシップとは、データベース間のリレーション(関係。つながり)のことです。

ちゃんとしたWebアプリケーションを作ろうと思うと、データベース間での連携が必要になってきます。

例えば、ブログの記事で考えると記事1つにつき、タグなどが複数ついていることはよくあることです。

例)記事:Djangoの勉強 ⇔ タグ:Django、勉強

この記事とタグのデータベースを関連付けすることがリレーションシップです。

リレーションシップの種類

リレーションシップには4種類あります。

【種類】

  1. 1対1対応:テーブルAのレコード1つに対して、テーブルBのレコード1つが紐づいているという関連付けです。
    例えば、リンゴ1つに対して、100円というような感じです。

  2. 1対多対応:テーブルAのレコード1つに対して、テーブルBのレコードが複数紐づいているという関連付けです。
    例えば、リンゴ1つに対して、複数の種類のリンゴ(ふじ、王林)のような感じです。

  3. 多対1対応:2番の逆になります。複数の種類のリンゴがリンゴという1つのカテゴリーに紐づいている感じです。
  4. 多対多:テーブルAの複数のレコード対して、テーブルBの複数のレコードに紐づいているという関連付けです。
    例えば、果物(リンゴ、桃、ミカン)というカテゴリーに対して、複数の種類(ふじ、王林)、(白鳳、桃山)、(あけぼの、甘夏)のような感じです。

Djangoでリレーションシップの使い方

まずは、1対多モデルのリレーションシップの使い方です。
Djangoのmodels.pyで次のように書きます。

1対多モデル

●主モデル(1側)

class A(models.Mode):

●従モデル(多側)

class B(models.Mode):
 項目 = models.ForeignKey(モデル名)

主モデル側はいつも通りです。
従モデル側の方に「models.ForeignKey」という項目を追加します。

「ForeignKey」とは、外部キーのクラスのことです。外部キーとはこのモデルに割り当てられているテーブル以外のテーブルのキーという意味です。

続いて1対1モデルのリレーションシップの使い方です。

1対1モデル

●主モデル

class A(models.Mode):

●従モデル

class B(models.Mode):
 項目 = models.OneToOneField(モデル名)

従モデル側の項目に「models.OneToOneField」を追加します。

最後に多対多モデルのリレーションシップの使い方です。

多対多モデル

●主モデル

class A(models.Mode):

●従モデル

class B(models.Mode):
 項目 = models.ManyToManyField(モデル名)

従モデル側の項目に「models.ManyToManyField」を追加します。

以上が、リレーションシップの使い方になります。

それでは実際にこの中で最もよく使われている、「1対多」をやりたいと思います。

今回のイメージは、ブログの投稿記事です。
一つのユーザ(主側)に対して、複数の記事(従側)を紐づけします。

それではやっていきます。

1対多のリレーションシップを作成する

まずは、複数の記事を作成するモデルを作成します。

モデルのイメージは次のようにします。

タイトル:記事のタイトル
コンテンツ:記事の中身
投稿日時:投稿した日時

1.models.pyを編集

ファイル:sample_app>hello>models.py

コード:

from django.db import models

class Friend(models.Model):
    name = models.CharField(max_length=100)
    mail = models.EmailField(max_length=200)
    gender = models.BooleanField()
    age = models.IntegerField(default=0)
    birthday = models.DateField()

    def __str__(self):
        return '<User:id=' + str(self.id) + ',' + self.name + '(' + str(self.age) + ')>'

#以下を追加----
class Message(models.Model):
    friend = models.ForeignKey(Friend, on_delete=models.CASCADE)
    title = models.CharField(max_length=100)
    content = models.CharField(max_length=300)
    pub_date = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return '<Message:id=' + str(self.id) + ', ' + self.title + '(' + str(self.pub_date) + ')>'

    class Meta:
        ordering = ('pub_date',)

従側のモデルにMessageというクラスを新規作成しました。

作り方は上で説明した通り「models.ForeignKey」を使って、Friendクラスに関連付けしています。

引数に使われている「on_delete=models.CASCADE」とは、主側のデータを削除した時に関連しているMessageクラス側のデータも併せて削除するという意味になります。

その他の項目はモデルのイメージになります。

あと見慣れない「ordering = (‘pub_date’,)」はpub_data順に並べる設定です。

2.マイグレーションをする

モデルを新規作成したのでマイグレーションします。

python manage.py makemigrations hello
python manage.py migrate

マイグレーションが終わったら、管理サイトで管理できるようにします。

3.admin.pyを編集

ファイル:sample_app>hello>admin.py

コード:

from django.contrib import admin
from .models import Friend
from .models import Message #追加

admin.site.register(Friend)
admin.site.register(Message) #追加

ちゃんと管理できているか確認するなら、サーバを起動して管理サイトで確認してください。

このまま先に進みます。次はMessageクラスを利用するページを作成します。

4.forms.pyを編集

ファイル:sample_app>hello>forms.py

コード:

from django import forms
from .models import Friend
from .models import Message #追加

class FriendForm(forms.ModelForm):
    class Meta:
        model = Friend
        fields = ['name', 'mail', 'age', 'gender', 'birthday']

class FindForm(forms.Form):
    find = forms.CharField(label='Find', required=False)

#以下を追加-----
class MessageForm(forms.ModelForm):
    class Meta:
        model = Message
        fields = ['title', 'content', 'friend']

フォームとして、タイトル、コンテンツ、フレンズを準備しました。pub_dataは自動で設定されるため準備は不要です。

次はmessage関数を作ります。

5.views.pyを編集

ファイル:sample_app>hello>views.py

コード:

from .models import Friend, Message
from .forms import FriendForm, MessageForm
from django.core.paginator import Paginator

def message(request, page=1):
    if(request.method == 'POST'):
        obj = Message()
        form = MessageForm(request.POST, instance=obj)
        form.save()

    data = Message.objects.all().reverse()
    paginator = Paginator(data, 5)
    params = {
        'title': 'Message',
        'form': MessageForm(),
        'data': paginator.get_page(page),
    }
    return render(request, 'hello/message.html', params)

必要な部分だけを追加しています。

messageメソッドの内容としては、POSTが送られてきた時に、モデルのMessageクラスのインスタンスを作成して、POSTで送られてきた値をMessageFormに入れて保存しています。

GETの場合は、Messageモデルのすべてのデータをpub_data順に並べ替えていたものをreverseを使って逆順にしています。

そのデータを引数として、Paginatorインスタンスを作成しています。
Paginatorとは、データが多い場合に指定したデータ数毎にページを分割する機能のことです。今回の場合は、5データごとにページを分割するように指定しています。

Paginatorについて詳しく知りたい場合は以下を参照してください。

https://docs.djangoproject.com/ja/3.0/ref/paginator/

最後にmessage用のテンプレートを作成します。

6.message.htmlを新規作成

ファイル:sample_app>hello>templates>hello>message.html

コード:

<!DOCTYPE html>
<html lang="ja">
<head>
    <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <!-- Bootstrap CSS -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/5.0.0-alpha1/css/bootstrap.min.css" integrity="sha384-r4NyP46KrjDleawBgD5tp8Y7UzmLA05oM1iAEQ17CSuDqnUK2+k9luXQOfXJCJ4I" crossorigin="anonymous">

    <title>{{ title }}</title>
</head>
<body class = "container">
    <h1>{{ title }}</h1>
    <form action="{% url 'message' %}" method="post">
        {% csrf_token %}
        {{ form.as_p }}
        <input type="submit" value="send" class="btn btn-primary">
    </form>
        <table class="table">
            <tr>
                <th>title</th>
                <th>name</th>
                <th>datetime</th>
            </tr>
        {% for item in data %}
            <tr>
                <td>{{ item.title }}</td>
                <td>{{ item.friend.name }}</td>
                <td>{{ item.pub_date }}</td>
            </tr>
        {% endfor %}
        </table>
        <ul class="pagination justify-content-center">
            {% if data.has_previous %}
            <li class="page-item">
                <a class="page-link" href="{% url 'message' %}">
                    &laquo; first</a>
            </li>
            <li class="page-item">
                <a class="page-link" href="{% url 'message' %}{{data.previous_page_number}}">
                    &laquo; prev</a>
            </li>
            {% else %}
            <li class="page-item">
                <a class="page-link">&laquo; first</a>
            </li>
            <li class="page-item">
                <a class="page-link">&laquo; prev</a>
            </li>
            {% endif %}
            <li class="page-link">
                <a class="page-link">
                    {{data.number}}/{{data.paginator.num_pages}}</a>
            </li>
            {% if data.has_next %}
            <li class="page-item">
                <a class="page-link" href="{% url 'message' %}{{data.next_page_number }}">
                    next &raquo;</a>
            </li>
            <li class="page-item">
                <a class="page-link" href="{% url 'message' %}{{data.paginator.num_pages }}">
                    last &raquo;</a>
            </li>
            {% else %}
            <li class="page-item">
                <a class="page-link">next &raquo;</a>
            </li>
            <li class="page-item">
                <a class="page-link">last &raquo;</a>
            </li>
            {% endif %}
        </ul>
</body>
</html>

結構長いコードですが、一番確認したいのは主モデルデータを取り出しているところです。

<td>{{ item.title }}</td>
<td>{{ item.friend.name }}</td>
<td>{{ item.pub_date }}</td>

このように、messageモデルには存在しない「name」のデータをfriendモデルから取り出すことができます。

これがデータベースのリレーションシップを使った時の効果になります。

以上で設定が終わったので、動作確認してみます。

動作確認

python manage.py runserver

ブラウザで以下にアクセスします。

http://localhost:8000/hello/message

message画面が表示されます。

 

次に以下のデータを入力して保存します。

Title:20200921サンプルタイトル
Content:20200921サンプルコンテンツ
Friend:<User:id=1,テストデータ1(36)>

nameがテストデータ1なのでわかりにくいですが、新しくブログの記事データを作成することができて、かつ一人のユーザに対して多数の記事データを紐づけることができています。

ちなみに、主モデル側でも従モデルのデータを取り出すことが可能です。

その場合は次のように記載します。

7.index.htmlを新規作成

ファイル:sample_app>hello>templates>hello>index.html

コード:

<!DOCTYPE html>
<html lang="ja">
<head>
    <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <!-- Bootstrap CSS -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/5.0.0-alpha1/css/bootstrap.min.css" integrity="sha384-r4NyP46KrjDleawBgD5tp8Y7UzmLA05oM1iAEQ17CSuDqnUK2+k9luXQOfXJCJ4I" crossorigin="anonymous">

    <title>{{ title }}</title>
</head>
<body class = "container">
    <h1>{{ title }}</h1>
    <p>{{ msg|safe }}</p>
    <a href="{% url 'create' %}" class="btn btn-primary">新規作成</a>
    <table class="table">
        <tr>
            <th>ID</th>
            <th>NAME</th>
            <th>GENDER</th>
            <th>MAIL</th>
            <th>AGE</th>
            <th>BIRTHDAY</th>
            <th>MESSAGES</th> #追加
        </tr>
    {% for item in data %}
        <tr>
            <td>{{ item.id }}</td>
            <td>{{ item.name }}</td>
            <td>{% if item.gender == False %}male{% endif %}
                {% if item.gender == True %}female{% endif %}</td>
            <td>{{ item.mail }}</td>
            <td>{{ item.age }}</td>
            <td>{{ item.birthday }}</td>

#以下を追加--- <td><ul> {% for ob in item.message_set.all %} <li>{{ ob.title }}</li> {% endfor %} </ul></td>
#ここまで----
<td><a href="{% url 'edit' item.id %}">編集</a></td> <td><a href="{% url 'delete' item.id %}">削除</a></td> </tr> {% endfor %} </table> </body> </html>

このように、繰り返しのfor文を使って「message_set.all」をセットします。
「_set」とは逆引きするための名前として扱われます。
逆引きとは、ForeignKeyのような関連項目がない主テーブルのモデルクラス側から十テーブル側を取り出すための項目名のことです。

今回は従モデル側のtitleを表示するようにしています。

以上で設定が終わりなのでindex画面を見てみます。

 

MESSAGESという項目に、従モデル側のtitleを表示することができました。

以上でDjangoの基本の機能の勉強は終了です。
これまで学んだ機能を使ってWebアプリケーションを作成して記事に載せていきたいと思います。

本日はここまでです。ありがとうございました。

P.S.

勉強を継続することが苦手ですか?

少し前からココナラというサービスで習慣化のテクニックについて教えるサービスを始めました。

もし、いつも3日坊主で終わってしまうという方や、ダイエットを続けたい、勉強したい、運動したいなど何か習慣化したいと思っている方がいましたら全力でサポートしますので、まずは覗いてみてください。

すでに何人かの方に実践してもらって効果が出ているという感想をいただいてます。

人生変わる?【習慣化の方法】を教えます 【残り1名】ダイエット、勉強、運動を続けることが苦手ですか?

Pocket

Djangoを勉強してみる_モデルを学ぶ_その7(入門編)

Pocket

前回の続きで、Djangoについて学んでいきます。

今回もモデルについて勉強していきます。

Djangoの勉強内容は以下の本を参考にしています。

参考

Python Django3超入門 (日本語) 単行本 – 2020/6/13 掌田 津耶乃 (著)

モデル
クエリを作成する

コードは以前の記事を参考にしてください。

Djangoを勉強してみる(入門編)
Djangoを勉強してみる(入門編その2)
Djangoを勉強してみる_urlを学ぶ(入門編)
Djangoを勉強してみる_テンプレートを学ぶ(入門編)
Djangoを勉強してみる_テンプレートを学ぶ_その2(入門編)
Djangoを勉強してみる_フォームを学ぶ_その1(入門編)
Djangoを勉強してみる_フォームを学ぶ_その2(入門編)
Djangoを勉強してみる_フォームを学ぶ_その3(入門編)
Djangoを勉強してみる_モデルを学ぶ_その1(入門編)
Djangoを勉強してみる_モデルを学ぶ_その2(入門編)
Djangoを勉強してみる_モデルを学ぶ_その3(入門編)
Djangoを勉強してみる_モデルを学ぶ_その4(入門編)
Djangoを勉強してみる_モデルを学ぶ_その5(入門編)
Djangoを勉強してみる_モデルを学ぶ_その6(入門編)

今回の目的

前回はCRUDのDelete(削除)画面を作成しCRUDのすべての基本をやりました。

今回は作成したデータから必要なものを取り出す検索について勉強していこうと思います。

検索画面を作ってみる

Djangoでは検索する機能のことを「フィルター」と呼びます。
フィルターを簡単にできるメソッドがDjangoでは用意されています。

そのメソッドは以下のように定義します。

変数 = Model名.objects.filter(フィルターの内容)

検索するためには、次のような作業を行います。

・検索するデータを入力する
・検索されたデータが一覧で表示される

それではやっていきます。

まずは、検索のためのurlを作成します。

1.urls.pyを編集

ファイル:sample_app>hello>urls.py

コード:

from django.urls import path
from . import views

urlpatterns = [
    path('',views.index, name='index'),
    path('create/', views.create, name='create'),
    path('edit/<int:num>',views.edit, name='edit'),
    path('delete/<int:num>',views.delete, name='delete'),
    path('find/',views.find, name='find'), #追加
]

いつもの書き方なので説明は省略します。

続いて、検索用のフォームを準備します。

2.forms.pyを編集

ファイル:sample_app>hello>forms.py

コード:

from django import forms
from .models import Friend

class FriendForm(forms.ModelForm):
    class Meta:
        model = Friend
        fields = ['name', 'mail', 'age', 'gender', 'birthday']

#以下を追加--- class FindForm(forms.Form): find = forms.CharField(label='Find', required=False)

検索用にテキストを入力するフォームを準備しました。

次は検索用のテンプレートを新規に準備します。

3.find.htmlを編集

ファイル:sample_app>hello>templates>hello>find.html

コード:

<!DOCTYPE html>
<html lang="ja">
<head>
    <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <!-- Bootstrap CSS -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/5.0.0-alpha1/css/bootstrap.min.css" integrity="sha384-r4NyP46KrjDleawBgD5tp8Y7UzmLA05oM1iAEQ17CSuDqnUK2+k9luXQOfXJCJ4I" crossorigin="anonymous">

    <title>{{ title }}</title>
</head>

<body class = "container">
    <h1>{{ title }}</h1>
    <p>{{ msg | safe }}</p>
    <form action="{% url 'find' id %}" method=post>
    {% csrf_token %}
    {{ form.as_p }}
    <tr><th></th><td>
        <input type="submit" value="検索" class="btn btn-primary"></td></tr>
    </form>

    <hr>
    <table class="table">
        <tr>
            <th>id</th>
            <th>name</th>
            <th>mail</th>
        </tr>
    {% for item in data %}
        <tr>
            <th>{{ item.id }}</th>
            <td>{{ item.name }}{{ item.age }}</td>
            <td>{{ item.mail }}</td>
        </tr>
    {% endfor %}
    </table>
</body>
</html>

次はfind関数を作成します。

4.views.pyを編集

ファイル:sample_app>hello>views.py

コード:

from .forms import FindForm #追加

def find(request):
    if (request.method == 'POST'):
        form = FindForm(request.POST)
        find = request.POST['find']
        data = Friend.objects.filter(name__contains=find)
        msg = 'Result:' + str(data.count())
    else:
        msg = 'seardh words...'
        form = FindForm()
        data = Friend.objects.all()

    paramas = {
        'title': '検索画面',
        'msg': msg,
        'form': form,
        'data': data,
    }
    return render(request, 'hello/find.html', paramas)

必要な部分だけコードを書いています。

find関数の中身は次のようになっています。

まずはお決まりの、リクエストのメソッドがPOSTの場合に処理します。
処理の中身は、FindFormにPOSTされたデータを入れてインスタンスを作成します。

次に検索文字をfind変数に代入して、データベースの「name」の中からその文字を含むデータを取り出してdata変数に代入します。

nameのあとの「__contains」はあいまい検索をする時に使うものです。
もし「__contains」を記載しない場合、nameで完全一致したものを検索します。

name以外で検索したい場合は、モデル(models.py)で定義した変数名をしてすることで実現できます。例えばメールアドレスで検索する場合は「mail」となります。

最後にデータの数をカウントしてmsg変数に代入してます。

もしPOSTが無い場合はすべてのデータを表示する処理をelseに書いています。

以上で設定が終わったので、動作確認してみます。

動作確認

python manage.py runserver

ブラウザで以下にアクセスします。

http://localhost:8000/hello/find

検索画面が表示されます。

テキスト「2」を入力して検索ボタンをクリックします。

ちゃんと2が入っているデータだけが検索できました。

今回の目的である検索をすることができました。

次回からさらにデータベースを利用する方法ついて勉強していこうと思います。

補足

最後に補足として、検索の範囲を広げたい時の話しをします。

先ほどの検索で「name」や「mail」といった1つの項目でしか検索することができません。もし、すべてのデータから検索したい場合は別の書き方をする必要があります。

その場合の書き方が次になります。

変数 = モデル名.objectss.filter(Q(1つ目の検索条件) | (Q(2つ目の検索条件))

実際のコードを入れると次のようになります。

from django.db.models import Q #追加

def find(request):
    if (request.method == 'POST'):
        form = FindForm(request.POST)
        find = request.POST['find']
        data = Friend.objects.filter(Q(name__contains=find) | Q(mail__contains=find))
        msg = 'Result:' + str(data.count())
    else:
        msg = 'seardh words...'
        form = FindForm()
        data = Friend.objects.all()

    paramas = {
        'title': '検索画面',
        'msg': msg,
        'form': form,
        'data': data,
    }
    return render(request, 'hello/find.html', paramas)

補足は以上となります。

本日はここまでです。ありがとうございました。

P.S.

勉強を継続することが苦手ですか?

少し前からココナラというサービスで習慣化のテクニックについて教えるサービスを始めました。

もし、いつも3日坊主で終わってしまうという方や、ダイエットを続けたい、勉強したい、運動したいなど何か習慣化したいと思っている方がいましたら全力でサポートしますので、まずは覗いてみてください。

すでに何人かの方に実践してもらって効果が出ているという感想をいただいてます。

人生変わる?【習慣化の方法】を教えます 【残り1名】ダイエット、勉強、運動を続けることが苦手ですか?

Pocket

オンライン英会話イングリッシュベルを始めてみた(11カ月目)

Pocket

今月も「オンライン英会話イングリッシュベルを始めてみた(10カ月目)」の続きです。

2019年10月8日から始めて11ヶ月目の状況について書きたいと思います。

【感想】

11カ月目の感想です。

現在はDME KidsクラスのBook4を引き続きやっています。

最近はよく聞かれる質問のフレーズが分かるようになってきました。

例えば「What kind of ~」、「What do you ~」、「When you want to do ~」、「Do you ~」などです。

聞きなれているフレーズだと何も考えなくてもいいので、その後の単語を聞き取ることに集中できるため少しずつではありますが、英語が話せるようになってきている気がします。

毎回書いていますが、少しずつ効果が出ていることが実感できてうれしくなります。

それでは、今月のサマリーを見ていきます。

【サマリー】

回数:262回→292回

時間:6550分→7300分(121.66時間)

サイト:イングリッシュベル【無料体験実施中】

クラス:DME KIDS

テキスト:Direct Kids Student’s BOOK4 Lesson77→Lesson84

習った英語:一部を下記に記載します

Lesson77:life,pair,invent,stairs,scissors,butcher’s,cut,meat

Lesson78:transport,carry,another,floor,machine,ski lift,cost,rent,top

Lesson79:road,heavy,along,piggy bank,pocket money,spend on,save,sweets

Lesson80:should,toothache,sunglasses,astronaut,nurse

Lesson81:sneeze,handkerchief,tissue,louder,allergy,pollen,dust,cough,medicine,cover,well,cold,runny nose,catch

Lesson82:polite,impolite,laugh at,mistake,saying,inside,to be able,study,elephant

Lesson83:spider,cobweb,find,beach,sand,gym,sandpit,shell,look for,rare

Lesson84:soup,salt,peas,pepper,flour,cup,barbecue,kettle,boil,party

【私がよく教えてもらっている先生】

先月に続き私が教えてもらっている先生をご紹介します。

なぜそのようなことをするかというと、イングリッシュベルを長くやっていると、いい先生や、若干微妙な先生がいます。

もし、皆さんがイングリッシュベルを始めようと思ったときの参考になればと思い紹介します。

・Lorelie
Lorelie先生は、気さくな先生なので楽しい授業をしてくれますので、オンライン英会話が楽しくなったきっかけの先生です。

・Karla
Karla先生は、難しい英語をスラスラ言えた時に、すごい笑顔で褒めてくれます。
それがやる気に繋がるため、よく受講しています。

・Michelle
Michelle先生は、発音を直してくれる先生です。
他の先生では直されて事が無いのですが、この先生は発音を直してくれるので、よく受講しています。

・Mari
Mari先生は、若干日本語の単語が話せるので日本語で話しかけてくれます。
それがちょっと楽しいので、初めてで緊張するという方はおすすめかもしれません。

・Juna
Juna先生は陽気な雰囲気の先生で授業が和みます。
楽しく授業をした時におススメです。

それでは、また来月報告します!

英語で「愛」、「家族」などの抽象的な概念を話せるようになるには、4160時間必要という研究があるそうです。

それレベルを指標にして今後の英語勉強していきたいと思います。

英語の残り学習時間:4038.34時間

以上です。ありがとうございました。

P.S.

ココナラというサービスで習慣化のテクニックについて教えるサービスを提供しています。

もし、いつも3日坊主で終わってしまうという方や、ダイエットを続けたい、勉強したい、運動したいなど何か習慣化したいと思っている方がいましたら全力でサポートしますので、まずは覗いてみてください。

人生変わる?【習慣化の方法】を教えます 。ダイエット、勉強、運動を続けることが苦手ですか?

Pocket