はじめに
この記事はPythonとそのWebフレームワークであるDjangoへの入門を目的としたハンズオンの資料です。
Python初心者向けに1.5時間程度のボリュームを想定しています。
図解でDjangoのしくみをイメージしつつ手を動かしてビジュアル的に面白そうなものをフロントエンド技術なしに作ってみたいという方はどうぞお付き合いください。
超入門とあるように文法やフレームワークの機能の詳細な説明は目的としていませんのでご了承ください。
作るもの
学びたいことを投稿することができるサービスLearnCloudというものを作っていきます。
機能は以下の二つ
- 利用者それぞれが今学びたいと思っている技術やスキルを投稿する機能
- 利用者の投稿をワードクラウドとして表示する機能
ではさっそく始めていきます。
1. Pythonのインストール
1.1 Linuxへのインストール
1.1.1 Pythonのインストールに必要なツールをインストールする。
Linux(Ubuntu)の場合
sudo apt update
sudo apt install build-essential libbz2-dev libdb-dev \
libreadline-dev libffi-dev libgdbm-dev liblzma-dev \
libncursesw5-dev libsqlite3-dev libssl-dev \
zlib1g-dev uuid-dev tk-dev
Linux(CentOS)の場合
sudo yum groupinstall "development tools"
sudo yum install bzip2-devel gdbm-devel libffi-devel \
libuuid-devel ncurses-devel openssl-devel readline-devel \
sqlite-devel tk-devel wget xz-devel zlib-devel
Python公式サイトでダウンロードのURLを確認しましょう。
以下のリンク先のFilesのテーブル内の一行目”Gzipped source tarball”のリンクを右クリックし「リンクのアドレスをコピー」をすることでダウンロードURLを確認できます。
# ダウンロードURLからPythonのソースコードを取得する
wget https://www.python.org/ftp/python/3.12.3/Python-3.12.3.tgz
# ダウンロードしたファイルを解凍する
tar -xzvf Python-3.12.3.tgz
# ビルド
cd Python-3.12.3
./configure
make
sudo make install
1.1.2 インストールの確認
# 正常にインストールされればバージョンが表示される
python3.12 --version
# (出力) > Python 3.12.3
1.2 Windowsへのインストール
インストール手順は省略させていただきます。
インストールの確認
# Winキーで「cmd」と入力し立ち上がったコマンドプロンプトで以下を入力
python --version
Windowsの場合、Linuxなどのようにpython3やpython3.12といったコマンドが利用できないかもしれません。
その場合は以降の資料におけるpython3.12
などのコマンドはpython
に読み替えてください。
1.3 Macへのインストール
ここではHomebrewを使用したインストール方法を解説します。
# ターミナルを開き、Homebrewがインストール済みかどうか確認する
brew -v
# インストールされていればHomebrew 4.2.19などと表示される。
# インストールされていない場合は以下コマンドでインストールする
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
# brewを使ってPython3.12をインストール
brew install python@3.12
# インストールできたかどうか確認
python3 --version
# Python 3.12.3
1.4 参考URL
- 非公式Pythonダウンロードリンク
- PythonをLinuxに導入・使用する方法を解説【Ubuntu】
- UbuntuでPythonをソースからインストール
- python@3.12 - Homebrew Formulae
2. 開発環境の準備
2.1 VSCodeの準備
省略させていただきます。
2.2 Python仮想環境の準備
Python仮想環境を利用することで、プロジェクトごとにライブラリやパッケージのバージョンを独立して管理できるため、環境によるトラブルを未然に防ぐことができます。
今回は標準のvenvというモジュールを使用します。
2.2.1 作業ディレクトリの作成
Windowsの場合
-
コマンドプロンプトを開く
windowsキーを押下し「cmd」と入力してエンターキーを押下。
-
コマンドプロンプト上で以下のコマンドを入力する
cd %USERPROFILE% mkdir djangohandson
Mac, Linuxの場合、ターミナルを開く
-
ターミナルを起動する
例 F4を押下して「terminal」と入力しエンターキーを押下。
-
terminal上で以下を入力する
今回は作業ディレクトリ名を「djangohandson」としましょう!
# ホームディレクトリに移動 cd ~ # 作業ディレクトリを作成 mkdir djangohandson
2.2.2 仮想環境の作成
2.2.1で作成した作業ディレクトリで以下のコマンドを入力します。
cd djangohandson
python3.12 -m venv [作成する仮想環境の名前]
仮想環境の名前は慣習として.venvが使用されることが多いです。
👉 今回は仮想環境の名前を「.venv」としましょう!
💡 隠しファイル.(ドット)から始まるファイルはOSから隠しファイルと認識され、ファイルエクスプローラー(Finder)上で見えないかもしれない。
その場合は
-
Windowsでは
エクスプローラーの「表示」タブで「隠しファイル」に☑️
-
Macでは ⌘ + ⇧ + .
-
Linuxではls -a
とすると隠しファイルも含めて表示できる。
✏️ pythonコマンドの-mオプションmはモジュールの意味。-m [モジュール名]と指定して、指定したモジュールの機能を直接実行できる。
さきほどの
python3.12 -m venv [Python仮想環境名]
は、venvモジュールの機能を呼び出している。
2.2.3 仮想環境を起動する
仮想環境を起動するときは、作業ディレクトリで以下を入力します。
Windowsの場合
.venv\Scripts\activate
Mac, Linuxの場合
source .venv/bin/activate
# あるいは
. .venv/in/activate
行頭に(.venv)と表示されていれば起動ができています。
2.2.4 仮想環境を終了する
Windowsの場合
.venv\deactivate
Mac, Linuxの場合
deactivate
.venvを削除すればOK
3. Djangoプロジェクトの作成
3.1 Djangoのインストール
3.1.1 pipでDjangoパッケージをインストールする
仮想環境に入っていることを確認して、以下のコマンドを入力します。
# Djangoをインストールする
pip install django
# インストールされたDjangoのバージョンを確認
python -m django --version
以下のpipコマンドで確認できる。
- pip list
- pip freeze
pip freezeは現在のPython環境にインストールされているすべてのパッケージとそのバージョンをリストアップする。
pip freezeした結果をrequirements.txtファイルへ保存することでrequirements.txtに記されたパッケージを一括インストールすることができ、Python環境を簡単に再現することができるようになる。
# pip freezeコマンドの結果をテキストファイルにリダイレクト(>)する
pip freeze > requirements.txt
# requirements.txtに記載されたパッケージを一括インストールする
# (※requirements.txtが置いてあるディレクトに移動して)
pip install -r requirements.txt
たとえば以下のときに便利。
- 別のPCで同じPython環境をつくりたいとき
- プロジェクトメンバに環境を共有したいとき
- CI/CDパイプラインでインストールを自動化したいとき
3.1.2 Djangoプロジェクトのひな形を生成する
Djangoでは開発するWebサイト, Webサービスをプロジェクトという単位で管理します。
Djangoをインストールするとdjango-adminコマンドが使用可能になります。
django-admin startproject [プロジェクト名]
👉 今回はプロジェクト名を「learncloudproject」とすることにしましょう!
コマンドを実行すると、以下のようにいくつかのディレクトリやファイルが生成されます。
3.1.3 開発サーバーを起動してみる
# manage.pyが存在するディレクトリで実行する
# runserverするとサーバープログラムがフォアグラウンドで起動する
python manage.py runserver
# 停止するときはctrl + c
3.1.4 言語設定を変更してみる
settings.pyの以下の部分を変更します。
LANGUAGE_CODE = 'ja' # default 'en-us'
# ついでにタイムゾーンも変更
TIME_ZONE = 'Asia/Tokyo' # default 'UTC'
開発サーバーを再起動し、言語設定が反映されていることを確認しましょう。
ブラウザに表示された内容が日本語に変わっているはずです。
3.1.5 runserverするとコンソール上に気になるメッセージが…
よくみると赤字でこのようなメッセージで表示されています。
Django先生曰く….
未適用のマイグレーションが18個あります。admin, auth, contenttypes, sessions のマイグレーションを適用するまで、プロジェクトは正しく動作しないかもしれません。
これらを適用するには 'python manage.py migrate' を実行してください。
ということらしいので、大人しく従っておきましょう。
# manage.pyがあるディレクトリで以下を実行
# 以下のコマンドでマイグレーションの適用状況を確認することができる。
# [X]が適用済み, [ ]は未適用。
python manage.py showmigrations
# Django先生が教えてくれたコマンド。マイグレーションが実行される。
python manage.py migrate
# マイグレーションが適用されたかどうか、再度確認してみよう。
# サーバー起動時の赤文字が消えたかどうか、確認してみよう。
マイグレーションとは移行を意味し、データベースのスキーマを変更することを意味します。たとえば、テーブルにカラムを追加する等。
マイグレーション機能をフレームワークが提供することで以下のようなメリットがあります。
- リリース済みのサービスへ機能追加する際に、既存のデータを失うことなくスキーマ変更することができる。
- データベースのスキーマ変更履歴をマイグレーションファイルとしてアプリケーションのコードと一緒にバージョン管理することが可能になる。
4. Djangoアプリケーションの作成
DjangoではひとつのWebサービスをひとつのプロジェクトという単位で開発します。
そしてさらにWebサービスの各機能をアプリケーションという単位で分割して開発します。
4.1 アプリケーションの作成
4.1.1 アプリケーションのひな型を生成する
# manage.pyと同じディレクトリ階層で実行する
python manage.py startapp [アプリ名]
👉 今回はアプリケーション名を「app」とすることにしましょう!
コマンドを実行するといくつかのディレクトリやファイルが生成されます。
4.1.2 作成したアプリケーションを設定ファイルに追加する
アプリを追加する際は設定ファイルにアプリを追記する必要があります。
settings.pyを開いてlist変数 INSTALLED_APPSにapps.pyで定義されたクラスAppConfigを追加しましょう。
INSTALLED_APPS = [
(省略),
'app.apps.AppConfig' # 追加する!
]
これでアプリが利用できるようになります。
4.2 Djangoがリクエストを処理する仕組みを知ろう
4.3 トップページにアクセスされたときの処理をつくる
4.3.1 トップページでHello, Django!と表示してみる
4.2の図を見ると必要なものは2つです。
- views.pyに”Hello, Django!”というレスポンスを返す関数を定義する。
- urls.pyにトップページのURL(””)とトップページの処理を定義したview関数の対応関係を記述する。
まず、1です。4.1.1でdjango-adminコマンドによって生成されたviews.pyを開き、以下のように書き換えてみましょう。
# app/views.py
from django.http import HttpResponse
from django.shortcuts import render
def top(request):
return HttpResponse("Hello, Django!")
次に2です。3.1.2でdjango-adminコマンドによって生成されたurls.pyを開き、以下のように書き換えてみましょう。
# learncloudproject/urls.py
from django.contrib import admin
from django.urls import path
from app.views import top
urlpatterns = [
path("", top),
path("admin/", admin.site.urls),
]
書き換えたら再び開発サーバーを起動してHello, Django!と表示されることを確認してみましょう。
4.3.2 テンプレートの機能を知ろう
4.3.3 テンプレートを使用してHTMLを返そう
appディレクトリ配下にtemplatesディレクトリを新規作成し、そこにtop.htmlというファイルを作りましょう。
top.htmlファイルを開き、以下のように書いてみましょう。
<!-- app/templates/top.html -->
<html>
<head>
<meta charset="utf-8" />
<title>LearnCloud</title>
</head>
<body>
<h1>LearnCloudへようこそ!</h1>
<p>テンプレートをつかってHTMLを配信しています。</p>
</body>
</html>
以下のように表示されていればOKです。
4.3.4 テンプレートに変数を埋め込んでみよう
4.3.2で図解したように、テンプレートは受け取ったデータをHTMLに埋め込むことができます。
ここではランダムな整数を生成してテンプレートに埋め込んでみましょう。
# app/views.py
from django.shortcuts import render
import sys # 追加!
def top(request):
context = {"python_version": sys.version}
return render(request, "top.html", context)
<!-- app/templates/top.html -->
<html>
<head>
<meta charset="utf-8" />
<title>LearnCloud</title>
</head>
<body>
<h1>LearnCloudへようこそ!</h1>
<p>テンプレートをつかってHTMLを配信しています。</p>
<p>Pythonのバージョンは{{python_version}}です。</p>
</body>
</html>
以下のように変数をHTMLに埋め込むことができたことを確認できると思います。
ここまでできたら次はデータベースを扱っていきましょう。
5. データベース
5.1 モデルの機能を知ろう
5.2 投稿をデータベースに保存できるようにする
5.2.1 Modelクラスの作成
5.1の図から、データベースへ投稿を保存するためにはmodels.pyにModelクラスを定義すればよさそうです。
models.pyを以下のように書いてみよう。
# app/models.py
from django.db import models
class Posts(models.Model):
id = models.AutoField(primary_key=True)
skill_name = models.CharField(max_length=128)
5.2.2 マイグレーションを実行し、テーブルを作成する
書けたら、このモデルに対応するテーブルをデータベースに作成します。
💡 まず、データベースを用意しなくてはいけないのでは?と思うかもしれませんが、DjangoをインストールするとデフォルトでSQLite3というデータベースがインストールされるため、今回はそちらを使用します。settings.pyを見るとDATABASESという項目に、sqlite3の設定がデフォルトで存在していることが確認できます。そのため、データベース接続に関する設定は不要です。
では、データベースにテーブルを作成していきます。
Djangoではデータベースのマイグレーション機能があるので、今回の「あたらしくPostsというテーブルを作成する」というスキーマ変更をDjangoに認識してもらい、スキーマ変更を実行してもらうことでデータベースにテーブルを作ることができます。
-
スキーマ変更をDjangoに認識してもらう
# manage.pyがあるディレクトリで実行する python manage.py makemigrations # 実行するとapp/migrationsディレクトリにマイグレーションファイルが生成される。
-
スキーマ変更を実行してもらう
# manage.pyがあるディレクトリで実行する # マイグレーションを実行する python manage.py migrate # マイグレーションが適用されたことを確認する python manage.py showmigrations
データベースにテーブルが作成されたことを確認してみましょう。
sqlite3のクライアントツールをインストールすることでsqlite3にログインし、テーブル一覧を確認することができますが、今回は環境に依存しないPythonインタプリタから確認する方法を試してみましょう。
Djangoの機能でPythonインタプリタを起動します。
# manage.pyがあるディレクトリで実行する
python manage.py shell
Pythonインタプリタが起動するので以下のように一行ずつ実行します。
import sqlite3
# データベースファイルに接続
conn = sqlite3.connect('db.sqlite3')
# カーソルオブジェクトを作成
cursor = conn.cursor()
# データベース内のテーブル一覧を取得するSQLクエリを実行
cursor.execute("SELECT name FROM sqlite_master WHERE type='table';")
# クエリ結果を取得
tables = cursor.fetchall()
# クエリ結果を表示
for table in tables:
print(table[0])
#
# 出力例
#
# django_migrations
# sqlite_sequence
# auth_group_permissions
# auth_user_groups
# auth_user_user_permissions
# django_admin_log
# django_content_type
# auth_permission
# auth_group
# auth_user
# django_session
# app_posts ← 作成できている!!!
# app_postsテーブルのスキーマ情報も確認してみる
cursor.execute(f"PRAGMA table_info(app_posts);")
schema_info = cursor.fetchall()
for column in schema_info:
print(f"ColumnName: {column[1]}, DataType: {column[2]}, PrimaryKey: {bool(column[5])}")
#
# 出力例
#
# ColumnName: id, DataType: INTEGER, PrimaryKey: True
# ColumnName: skill_name, DataType: varchar(128), PrimaryKey: False
# ↑Modelクラスの定義どおりに作成できていることが確認できる!!!
# コネクションをクローズ
conn.close()
5.2.3 Pythonシェルからデータを登録してみる
前項で行ったのと同様にPythonシェルを起動します。
Pythonシェル上で以下のように一行ずつ実行します。
from app.models import Posts
# データを一件追加。
Posts.objects.create(skill_name="Python")
# Postsから全件取得し、Pythonの辞書型に変換して表示する
Posts.objects.values()
# 出力結果: <QuerySet [{'id': 1, 'skill_name': 'Python'}]>
何件か追加してみましょう。
5.2.4 トップページで投稿の一覧を表示する
# app/views.py
from django.shortcuts import render
from app.models import Posts
def top(request):
posts = Posts.objects.all()
context = {"posts": posts}
return render(request, "top.html", context)
<html>
<head>
<meta charset="utf-8" />
<title>LearnCloud</title>
</head>
<body>
<h1>LearnCloudへようこそ!</h1>
<h2>投稿一覧</h2>
<table>
<thead>
<th>ID</th>
<th>学びたいこと</th>
</thead>
<tbody>
{% for post in posts %}
<tr>
<td>{{ post.id }}</td>
<td>{{ post.skill_name }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</body>
</html>
6. フォーム
6.1 フォームから学びたいことを投稿できるようにする
DjangoではModelFormという機能が用意されていて、Modelクラスに対応したフォームクラスを作成することで、
- フォームを作成
- フォームに入力されたデータの受け取り
- データベースへの格納
という処理の流れを簡単に実装できます。
ここでは詳しく解説しませんが、Djangoの機能で簡単に実装できることを体感してください。
6.1.1 ModelFormクラスを作成する
まず、app/配下にforms.pyを作成します。
forms.pyを開いて以下のように書いてください。
# app/forms.py
from django import forms
from app.models import Posts
class PostsForm(forms.ModelForm):
class Meta:
model = Posts
fields = ("skill_name",)
labels = {"skill_name": "学びたいこと"}
続いて、ビューも書き換えます。
# app/views.py
from django.shortcuts import redirect, render
from django.views.decorators.http import require_http_methods
from app.forms import PostsForm
from app.models import Posts
@require_http_methods(["GET", "POST"])
def top(request):
if request.method == "GET":
# フォームを生成
form = PostsForm()
posts = Posts.objects.all()
context = {
"form": form, # formをテンプレートに渡す
"posts": posts,
}
return render(request, "top.html", context)
elif request.method == "POST":
# フォームから投稿が送信されたときの処理
form = PostsForm(request.POST)
if form.is_valid():
form.save() # これだけでフォームの情報がデータベースに登録される!
# 登録された投稿を一覧に反映させるため、再度アクセスさせる
return redirect(top)
最後にテンプレートも書き換えます。
<html>
<head>
<meta charset="utf-8" />
<title>LearnCloud</title>
</head>
<body>
<h1>LearnCloudへようこそ!</h1>
<h2>学びたいことを投稿しよう!</h2>
<form method="post">
{% csrf_token %} {{ form.as_p }}
<button type="submit">投稿する!</button>
</form>
<h2>投稿一覧</h2>
<table>
<thead>
<th>ID</th>
<th>学びたいこと</th>
</thead>
<tbody>
{% for post in posts %}
<tr>
<td>{{ post.id }}</td>
<td>{{ post.skill_name }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</body>
</html>
ここまでできたら再度開発サーバーを立ち上げ、実行してみましょう。
フォームが表示され、入力して「投稿する!」ボタンを押下すると一覧に追加されることが確認できると思います。
7. ワードクラウドを表示してみよう
ワードクラウドの作成にはライブラリwordcloudを使用します。
使い方はとっても簡単です。シンプルな使用例がリポジトリに公開されていますので確認してみましょう
確認してみると、英文のようなスペース区切りの文字列を用意してWordCloudクラスのgenerateメソッドに渡してあげればワードクラウドができあがります。
画像化する際はWordCloudクラスのto_imageメソッドが用意されておりPillowというライブラリのImageクラスのインスタンスが返ってきます。
さらに、今回生成したワードクラウド画像はHTMLのimgタグにBase64エンコードしたバイナリ形式の文字列として埋め込んで配信するため、上記に加えてPillowのImageクラスをPNG形式に変換しBase64エンコードして文字列に変換するということを行います。
wordcloudをpipでインストール
# venvに入っていることを確認して実行
pip install wordcloud
# インストールの確認
pip freeze
# 出力結果: wordcloud==1.9.3
ビューに処理を追加
# app/views.py
import base64
from io import BytesIO
from django.shortcuts import redirect, render
from django.views.decorators.http import require_http_methods
from wordcloud import WordCloud
from app.forms import PostsForm
from app.models import Posts
@require_http_methods(["GET", "POST"])
def top(request):
if request.method == "GET":
# フォームを生成
form = PostsForm()
posts = Posts.objects.all()
wordcloud_image = _generate_wordcloud(posts)
context = {
"form": form,
"posts": posts,
"wordcloud_image": wordcloud_image,
}
return render(request, "top.html", context)
elif request.method == "POST":
# フォームから投稿が送信されたときの処理
form = PostsForm(request.POST)
if form.is_valid():
form.save()
# 登録された投稿を一覧に反映させるため、再度アクセスさせる
return redirect(top)
def _generate_wordcloud(posts):
if len(posts) == 0:
return
skill_names = [post.skill_name for post in posts]
text = " ".join(skill_names)
wordcloud = WordCloud(
width=800,
height=400,
background_color="white",
).generate(text)
return _to_image(wordcloud)
def _to_image(wordcloud):
# ワードクラウドを画像に変換
image = wordcloud.to_image()
buffer = BytesIO()
image.save(buffer, format="PNG")
image_png = buffer.getvalue()
buffer.close()
# 画像データをBase64エンコードしてバイナリ型にする
image_base64_binary = base64.b64encode(image_png)
# UTF-8で文字列にデコードしてHTMLに埋め込める形式にする
image_base64_string = image_base64_binary.decode("utf-8")
return image_base64_string
追加セクション
ワードクラウドを日本語対応にする
デフォルトで使用されるフォントが日本語に対応していないため、正しく表示されていません。
ここではどのOSでも対応できるよう、無償で利用できるIPAフォントをダウンロードして利用することにしましょう。
Djangoアプリappディレクトリ下にstatic/fontsディレクトリを作成しそこにフォントファイルを配置することにします。
手順1 IPAフォントのダウンロード
Mac, Linuxの場合
# Djangoプロジェクト配下に移動した状態で実行する
# 静的ファイル用ディレクトリを作成
mkdir app/static/fonts
# 作成したディレクトリへ移動
cd app/static/fonts
# カレントディレクトリにIPAフォント(ゴシック)をダウンロード
# Macでwgetがなければbrew install wget
wget https://moji.or.jp/wp-content/ipafont/IPAexfont/ipaexg00401.zip
# ダウンロードした圧縮ファイルを解凍する
# unzipがなければインストールしてください。
# (例) Ubuntuならsudo apt install upzip
unzip ipaexg00401.zip
Windowsの場合
IPAフォントのダウンロードリンクからIPAフォントをダウンロードし、解凍して、app/static/fontsフォルダ配下に配置してください。
手順2 IPAフォントを使用するようにコードを修正
app/views.pyにosモジュールのインポート追加と_generate_wordcloud関数の内容修正を加えます。
# app/views.py
import os # 追加!!!
def _generate_wordcloud(posts):
if len(posts) == 0:
return
skill_names = [post.skill_name.strip() for post in posts]
text = " ".join(skill_names)
# 日本語対応するためにフォントを指定する
# os.path.join()を使用することで区切り文字の違いなどOSに依存せずパスを生成できる。
font_path = os.path.join("app", "static", "fonts", "ipaexg00401", "ipaexg.ttf")
wordcloud = WordCloud(
font_path=font_path, # font_pathの指定を追加
width=800,
height=400,
background_color="white",
).generate(text)
return _to_image(wordcloud)
これで日本語も表示できていると思います。
WordCloudでスペース区切りの用語も一単語としてみなされるようにしたい
WordCloudクラスのコンストラクタの引数regexpに正規表現を指定することで、1単語としてみなすパターンを自由に指定できる。
たとえば単語の区切り文字を;(セミコロン)に変えて、regexpにセミコロン以外の連続する文字を1単語とみなすようにすれば意図した挙動になる。
(空白区切り以外にするとcollocations=Falseも指定しないとエラーになってしまうため、一緒に指定する。)
# 区切り文字をセミコロンにする
text = ";".join(skill_names)
# (省略)
wordcloud = WordCloud(
font_path=font_path,
width=800,
height=400,
background_color="white",
regexp=r"[^;]+", # 追加で指定
collocations=False, # 追加で指定
).generate(text)
が…….
うまく出現頻度が反映されなくなっている気がする…..?
現在、WordCloudクラスのgenerateメソッドを使用しているところを事前に出現頻度を計算してgenerate_from_frequenciesメソッドを使うようにすればうまくいくかも?(未検証…..)
トラブルシューティングQ&A
Q. VSCodeで「インポート "django.contrib" をソースから解決できませんでした(PylancereportMissingModuleSource)」と表示される。
A. Python仮想環境内のPythonインタプリタが選択できていないor認識されていない可能性があります。
手順1 VSCodeにvenvを見つけてもらう
その場合は、VSCode画面左下の歯車アイコンから「設定」を開き、「設定の検索」フォームに「python.venv」と入力します。
表示された「Python: Venv Folders」という設定の「項目を追加」ボタンを押下し、作成したPython仮想環境を含むホームディレクトリ上のディレクトリ名を追加しましょう。
手順2 適切なPythonインタプリタを選択する
Pythonファイルを開いている場合はVSCode画面右下に現在選択されているPythonインタプリタのバージョンが記載されています。それをクリックすると他のPythonインタプリタが選択できます。
それ以外でもVSCodeのコマンドパレットを開き(Mac: ⌘ + ⇧ + p, Win: ctrl + shift + p)、「>Python: インタープリターを選択」と入力することで同様の操作が可能です。
作成したPython仮想環境のインタプリタを選択するとimport文のエラーが消えると思います。
参考URL
Q. VSCodeで「この大規模なワークスペースをウォッチできません。」と表示される
A. venv内のファイルが監視対象になってしまっている可能性があります。
手順 venvをファイル監視から除外するよう設定を追加する
VSCode画面左下の歯車アイコンから「設定」を開き、「設定の検索」フォームに「files.watcher exclude」と入力します。
表示された「Files: Watcher Exclude」という設定の「パターンを追加」ボタンを押下し、次のパターン「/[作成したPython仮想環境名]/」を追加しましょう。(例) /.venv/****
手順2 それでも警告が表示される場合はOSの制限を調整する
# 現在のOSの設定を確認する
cat /proc/sys/fs/inotify/max_user_watches
sudo vi /etc/sysctl.conf
# 以下の一行を追記する
fs.inotify.max_user_watches=524288
# 設定を適用する
sudo sysctl -p
# 設定が適用されたことを確認する
cat /proc/sys/fs/inotify/max_user_watches
# > 524288