RESTful API作ってみる(1)
はじめに
PythonのREST APIが高速とのことでチャレンジしてみました。
扱う内容
1. Modelの簡単なRelation.
2. Serializer構築
3. POSTする
Modelの準備
GitHookの簡単なリレーションモデル。
commitとcommitされたファイル群の情報Modelです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | # 曜日マスタ # 通知する曜日。マスタとして保持する必要はないかもしれない DAYS_OF_WEEK = ( (0, 'Monday'), (1, 'Tuesday'), (2, 'Wednesday'), (3, 'Thursday'), (4, 'Friday'), (5, 'Saturday'), (6, 'Sunday'), ) class DayOfWeek(models.Model): name = models.CharField(_('dayofweek.name'), choices=DAYS_OF_WEEK, null=False, max_length=255) # コミットする人 # 通知する時間帯や曜日をもたせる class Author(models.Model): name = models.CharField(_('author.name'), null=False, max_length=255) email = models.CharField(_('author.email'), null=False, max_length=255) notice = models.BooleanField(_('author.notice'), default=True) notice_start_time = models.TimeField(_('author.notice_start_time'), null=True) notice_end_time = models.TimeField(_('author.notice_end_time'), null=True) days = models.ManyToManyField(DayOfWeek, related_name='author') # コミット情報 # ハッシュキー、コミット者、コメント、日時を持つ class Commit(models.Model): key = models.CharField(_('commit.hash'), null=False, max_length=255, unique=True) author = models.ForeignKey(Author, on_delete=models.CASCADE) commited_at = models.DateTimeField(_('commit.commited_at'), blank=False, max_length=255, null=False) comment = models.CharField(_('commit.comment'), null=False, max_length=255) # コミットファイル # ファイルパスとモード情報(新規,更新,削除)を持つ class File(models.Model): path = models.CharField(_('file.path'), null=False, max_length=255) mode = models.CharField(_('file.mode'), null=False, max_length=255) commit = models.ForeignKey(Commit, on_delete=models.CASCADE) |
次にSerializerの定義。SerializerとはAPIでデータ連携するためのインターフェース。フォームviewと同じような役割です。
Serializer
まずはファイル情報
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | class FileSerializer(serializers.ModelSerializer): class Meta: model = File fields = ('mode', 'path') 次に本命のコミット貯蓄情報 class CommitSerializer(serializers.ModelSerializer): # 紐づくファイル群(複数) files = FileSerializer(many=True, source="file_set") # AuthorはemailでPOSTしたいので別カラムを用意 author_email = serializers.CharField(max_length=255, default='') # 追加フィールドのためにgetを作成 # これが無いとGET時にエラー def get_author_email(self, obj): return obj.author_email() # 同上 def get_files(self, obj): return obj.author_email() # 複数レコード同時作成 (不完全?) def __init__(self, *args, **kwargs): many = kwargs.pop('many', True) super(CommitSerializer, self).__init__(many=many, *args, **kwargs) # 新規レコード作成用API def create(self, validated_data): # すでに存在するか判定 try: commit = Commit.objects.get(key=validated_data["key"]) except Commit.DoesNotExist: commit = None if commit is None: commit = Commit() # POSTされた情報で構築 commit.key = validated_data['key'] # PrimaryKeyでないので一旦ObjectをDBから取得して関連付ける author = Author.objects.get(email=validated_data['author_email']) commit.author = author commit.commited_at = validated_data['commited_at'] commit.comment = validated_data['comment'] commit.save() # ファイル群を生成 # Commitに紐付ける for file in validated_data['file_set']: cf = File() cf.mode = file['mode'] cf.path = file['path'] cf.commit = commit cf.save() commit.save() return commit # POSTされるフィールド定義 # fieldsにアクセス可能なフィルド名の定義 class Meta: model = Commit fields = ('key', 'author_email', 'commited_at', 'comment', 'files') |
次にルーティング定義。
1 2 3 4 5 6 7 8 9 | from django.urls import path from . import views from .views import CommitViewSet from rest_framework import routers router = routers.DefaultRouter() router.register(r'commits', CommitViewSet) urlpatterns = router.urls |
POSTして動作確認
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | <?php $url = 'http://***********************/api/commits/'; $files = array(); $file = array('mode'=>'M', 'path'=>'README.md'); array_push($files, $file); $data = array( 'key' => md5(time()), 'author_email' => 'test@test.com', 'commited_at' => date('Y-m-d H:i:s'), 'comment' => 'TEST', 'files' => $files ); echo json_encode($data, JSON_UNESCAPED_UNICODE+JSON_UNESCAPED_SLASHES)."\n"; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_VERBOSE, 1); curl_setopt($ch, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE); curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json')); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data)); $result = curl_exec($ch); curl_close($ch); echo json_encode($result, JSON_UNESCAPED_UNICODE+JSON_UNESCAPED_SLASHES); |
djangoのadminからデータが登録されているのを確認して完了
Author Profile
スターフィールド編集部
SHARE