#事前知識
- anaconda navigatorはPython開発のためのディストリビューション(コンパイル済みのソフトウェアの集まり)
- jwtという認証トークンを使用する
- djoserとはjwtトークンを簡単に使用するためのサードパーティー
- django-cors-headersはReactからのアクセスを許可するために必要になってくる
- Pillowは画像データを扱うために使用する
#仮想環境を構築する
- Environments項目のCreateを選択
- Nameを入力し、Packages(Python 3.7)を選択
- 再生ボタンをクリックし、ターミナルを開く
- anaconda navigatorにて仮想環境(python3.7)の作成し、必要なものをインストール(下記コマンド)
$ pip install django==3.0.7
$ pip install djangorestframework==3.10
$ pip install djangorestframework-simplejwt==4.6.0
$ pip install djoser
$ pip install django-cors-headers
$ pip install Pillow
上記のコマンドにより各ライブラリ?のインストールが完了したら、anaconda navigatorとターミナルを閉じて、anaconda navigatorで作成した仮想環境とPycharmのプロジェクトに紐付ける
#仮想環境とPycharmを紐付ける
- 空のディレクトリ(筆者はapi_insta)を作成し、Openを選択し、Pycharmで開く
- Preferences...を選択し、Projectの中のPython Interpreterを選択
- 右上の設定ボタン(歯車マーク)を選択し、Addを選択
- Existing envirionmentにチェックを入れ、右にある...を選択
- /Users/ホームディレクトリ/opt/anaconda3/envs/API_insta/bin/pythonを選択しOK
#プロジェクトを作成する
$ django-admin startproject api_insta .
##アプリを作成する
$ django-admin startapp api
#現時点でのローカル環境を起動する
- manage.pyを右クリックし、Run 'manage'を選択
- 右上のmanageをクリックし、Edit Configulations...を選択
- Parametersという項目にrunserverを追加してOK
- 右上の再生ボタンをクリックで、ローカル環境を起動
##モデルの作成
UserManagerではデフォルトではuser nameをpasswordで認証する様になっているのでemailとpasswordで認証するようにオーバーライドする必要がある
from django.db import models
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager, PermissionsMixin
from django.conf import settings
def upload_avatar_path(instance, filename):
ext = filename.split('.')[-1]
return '/'.join(['avatars', str(instance.userProfile.id)+str(instance.nickName)+str(".")+str(ext)])
def upload_post_path(instance, filename):
ext = filename.split('.')[-1]
return '/'.join(['posts', str(instance.userPost.id)+str(instance.title)+str(".")+str(ext)])
class UserManager(BaseUserManager):
def create_user(self, email, password=None):
if not email:
raise ValueError('email is must')
user = self.model(email=self.normalize_email(email))
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, email, password):
user = self.create_user(email, password)
user.is_staff = True
user.is_superuser = True
user.save(using= self._db)
return user
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(max_length=50, unique=True)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
objects = UserManager()
USERNAME_FIELD = 'email'
def __str__(self):
return self.email
class Profile(models.Model):
nickName = models.CharField(max_length=20)
userProfile = models.OneToOneField(
settings.AUTH_USER_MODEL, related_name='userProfile',
on_delete=models.CASCADE
)
created_on = models.DateTimeField(auto_now_add=True)
img = models.ImageField(blank=True, null=True, upload_to=upload_avatar_path)
def __str__(self):
return self.nickName
class Post(models.Model):
title = models.CharField(max_length=100)
userPost = models.ForeignKey(
settings.AUTH_USER_MODEL, related_name='userPost',
on_delete=models.CASCADE
)
created_on = models.DateTimeField(auto_now_add=True)
img = models.ImageField(blank=True, null=True, upload_to=upload_post_path)
liked = models.ManyToManyField(settings.AUTH_USER_MODEL, related_name='liked', blank=True)
def __str__(self):
return self.title
class Comment(models.Model):
text = models.CharField(max_lengt=100)
userComment = models.ForeignKey(
settings.AUTH_USER_MODEL, related_name='userComment',
on_delete=models.CASCADE
)
post = models.ForeignKey(Post, on_delete=models.CASCADE)
def __str__(self):
return self.text
- normalze_email(email)はemailを正規化してuserをいう変数を作成している
- set_password(password)はpasswordをハッシュ化している
- データベースに保存
- UserManagerをオーバーライドした場合はcreateSuperUserもオーバーライドする必要がある
- Userモデルもemailバージョンにオーバーライドする
##Active, Staff, Superuserの違いについて
Active: is_activeに指定する真偽値でアカウントの有効無効の切り替え(無効にするとログインできなくなる)
Staff: is_staggに指定する真偽値でstaff権限の有効無効の切り替え(staff権限はadminのダッシュボードにログインする権限)
Superuser: is_superuserに指定する真偽値で有効無効の切り替え(superusreはstaff権限に加え、データベースの内容の変更などの全権限を付与する)
#settings.pyを編集
from datetime import timedelta #追記
INSTALLED_APPS = [
#省略
'rest_framework', #追記
'djoser', #追記
'api.apps.ApiConfig', #追記
'corsheaders', #追記
]
MIDDLEWARE = [
'corsheaders.middleware.CorsMiddleware', #追記
#省略
]
#以下を追記
CORS_ORIGIN_WHITELIST = [
"http://localhost:3000"
]
WSGI_APPLICATION = 'api_insta.wsgi.application'
#以下を追記
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticated',
],
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework_simplejwt.authentication.JWTAuthentication',
],
}
#以下を追記
SIMPLE_JWT = {
'AUTH_HEADER_TYPES': ('JWT',),
'ACCESS_TOKEN_LIFETIME': timedelta(minutes=60),
}
TIME_ZONE = 'Asia/Tokyo' #UTCから変更
AUTH_USER_MODEL = 'api.User' #追記
MEDIA_ROOT = os.path.join(BASE_DIR, 'media') #追記
MEDIA_URL = '/media/' #追記
- jwtトークンの有効期限を設定するためにtimedeltaを導入
- INSTALLED_APPに導入したアプリを追加
- djangoは.(ドット)で繋ぐことができるため、api.apps.ApiConfigとはapiディレクトリのapps.pyのApiConfigのことを指す
- MIDDLEWAREにcorsに関するコードを追記
- reactからのアクセスを許可するためにCORS_ORIGIN_WHITELISTを追加する
- djangoのデフォルトの認証関連を設定する
- views.pyを特定のユーザーだけに見せるようにするためにDAFAULT_PERMISSION_CLASSEを設定する
- jwtを使用した認証をしたいため、DEFAULT_AUTHENTICATION_CLASSES
- SIMPLE_JWTによってトークンの有効期限を60分に指定している
- djangoにデフォルトのUserモデルではなく、カスタマイズしたUserモデルを使用するように明示的にする必要がある
- プロジェクト直下にmediaディレクトリを作成し、画像の保存先を明示的にする(MEDIA_ROOTとMEDIA_URL)
- migrateコマンドはデフォルトでsqlite3に変換してくれる
###データベースに反映させる
$ python manage.py makemigrations
$ python manage.py migrate
#ダッシュボードで追加したモデル内容を確認する
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from django.utils.translation import gettext as _
from . import models
class UserAdmin(BaseUserAdmin):
ordering = ['id']
list_display = ['email']
fieldsets = (
(None, {'fields': ('email', 'password')}),
(_('Personal Info'), {'fields': ()}),
(
_('Permissions'),
{
'fields': (
'is_active',
'is_staff',
'is_superuser',
)
}
),
(_('Important dates'), {'fields': ('last_login',)}),
)
add_fieldsets = (
(None, {
'classes': ('wide',),
'fields': ('email', 'password1', 'password2')
}),
)
admin.site.register(models.User, UserAdmin)
admin.site.register(models.Profile)
admin.site.register(models.Post)
admin.site.register(models.Comment)
- オーバーライドせずに作成したモデル(PostやProfileモデルなど)はadmin.site.registerによってadmin dashboardで確認したい項目を追加できる
$ python manage.py createsuperuser
- 管理者権限をもったユーザーの作成
#シリアライザーの作成
####シリアライザーとは
データベースからクライアント側にオブジェクトを渡す時にjsonに変換してくれたり、クライアント側からemailやpasswordなどをデータベースに渡す時に精査(validation)してくれたりするもの。
又、新規でモデルを作成した際にセットで作るもの。(User, Profile, Post, Commentの4つのシリアライザーを作成する)
- アプリケーションディレクトリ(startappコマンドで作成したディレクトリ)直下にserializers.pyを作成
from django.contrib.auth import get_user_model
from rest_framework import serializers
from .models import Profile, Post, Comment
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = get_user_model()
fields = ('id', 'email', 'password')
extra_kwargs= {'password': {'write_only': True}}
def create(self, validated_data):
user = get_user_model().objects.create_user(**validated_data)
return user
- get_user_modelはdjangoの標準の関数でアクティブなUserモデルを取得できる
#tips - gitignoreに関して(https://note.com/masato1230/n/na63ac4e7ccdd)