小村のポートフォリオサイト開発(14) DjangoRestFramework ここまでのリファクタリング
こんばんは、小村だよ!
[DRF レスポンスデータ]みたいな感じで検索したらこのブログがヒットしてびっくりしたよ!
じゃー今日も下記のポートフォリオサイトを構築していくよ
- サイト:Little Village
前回はAPIのレスポンスのフォーマットを決めたね
目次
- 現状整理
utils.hatena.py
作成views.entry.py
修正
記録
現状整理
まずは現状の
views.entry.py
の中身が下記fat viewもいいところだね!
基本的にviewはコントローラー部分だけ書くべきなのでめちゃんこよくない例です。
このソースをリファクタリングしていきたいと思います
# coding: utf-8 import time import os import requests import xmltodict from rest_framework import status from rest_framework import viewsets from rest_framework.decorators import action from rest_framework.response import Response from ..models import Entry from ..serializer import EntryAllSerializer, EntryCreateAndUpdateSerializer class EntryViewSet(viewsets.ModelViewSet): queryset = Entry.objects.all() serializer_class = EntryAllSerializer @action(detail=False, methods=['post']) def capture(self, request): url = self.getHatenaApiUrl('entry') auth = self.getHatenaApiAuth() hatena_entry_ids = [] response = { 'created_count': 0, 'updated_count': 0, 'deleted_count': 0, 'failed_count': 0, 'failed_hatena_entry_ids': [], } while url != '': # 連続で呼び出すの怖いので0.5秒間間を空ける time.sleep(0.5) hatena_list = requests.get(url, auth=auth) dict_data = xmltodict.parse(hatena_list.text, encoding='utf-8') entries = [] if 'feed' in dict_data: if 'entry' in dict_data['feed']: entries = dict_data['feed']['entry'] for entry in entries: if not isinstance(entry, dict): continue # hatena_entry_id取得 hatena_entry_id = entry['id'][ entry['id'].rfind('-') + 1:] if 'id' in entry else '' hatena_entry_ids.append(hatena_entry_id) # category取得 if 'category' in entry: if isinstance(entry['category'], list): category = entry['category'][0]['@term'] else: category = entry['category']['@term'] else: category = '' # title取得 title = entry['title'] if 'title' in entry else '' # summary取得 summary = entry['summary']['#text'] if 'summary' in entry else '' # content_md取得 content_md = entry['content']['#text'] if 'content' in entry else '' # content_html取得 content_html = entry['hatena:formatted-content']['#text'] if 'hatena:formatted-content' in entry else '' # draft取得 draft = entry['app:control']['app:draft'] if 'app:control' in entry else '' # updated_at取得 updated_at = entry['updated'] if 'updated' in entry else None # edited_at取得 edited_at = entry['app:edited'] if 'app:edited' in entry else None # 更新用パラメータ param = { 'hatena_entry_id': hatena_entry_id, 'category': category, 'title': title, 'summary': summary, 'content_md': content_md, 'content_html': content_html, 'draft': draft, 'updated_at': updated_at, 'edited_at': edited_at, } entry = Entry.objects.filter( hatena_entry_id=hatena_entry_id).first() if not entry: # 新規作成 mode = 'create' serializer = EntryCreateAndUpdateSerializer(data=param) else: # 更新 mode = 'update' serializer = EntryCreateAndUpdateSerializer( entry, data=param) if serializer.is_valid(): serializer.save() if mode == 'create': response['created_count'] = response['created_count'] + 1 else: response['updated_count'] = response['updated_count'] + 1 else: response['failed_count'] = response['failed_count'] + 1 response['failed_hatena_entry_ids'].append(hatena_entry_id) # 次のURLを取得 url = '' if 'link' in dict_data['feed']: if isinstance(dict_data['feed']['link'], list): for link in dict_data['feed']['link']: if isinstance(link, dict): if '@rel' in link: if link['@rel'] == 'next': url = link['@href'] # はてなIDが存在しなければ論理削除 response['deleted_count'] = Entry.objects.exclude( hatena_entry_id__in=hatena_entry_ids).delete() return Response(response, status.HTTP_200_OK) def getHatenaApiUrl(self, action): HATENA_API_URL_HEADER = 'https://blog.hatena.ne.jp' HATENA_API_USER = os.environ.get('HATENA_API_USER') HATENA_API_BLOG = os.environ.get('HATENA_API_BLOG') HATENA_API_URL_FUTTER = 'atom' url = [ HATENA_API_URL_HEADER, HATENA_API_USER, HATENA_API_BLOG, HATENA_API_URL_FUTTER, action ] return os.path.join(*url) def getHatenaApiAuth(self): HATENA_API_USER = os.environ.get('HATENA_API_USER') HATENA_API_KEY = os.environ.get('HATENA_API_KEY') return (HATENA_API_USER, HATENA_API_KEY)
utils.hatena.py
作成
ということでutilsフォルダ内にhatena.pyを作成して、はてなブログAPI関係の処理は全てここにまとめようと思います
これによりHatenaApiをインスタンス化して
getAllEntries
を実行するといい感じに加工された記事データが取得できるようになりました
import os import requests import xmltodict class HatenaApi(): HATENA_API_USER = os.environ.get('HATENA_API_USER') HATENA_API_BLOG = os.environ.get('HATENA_API_BLOG') HATENA_API_KEY = os.environ.get('HATENA_API_KEY') HATENA_API_URL_HEADER = 'https://blog.hatena.ne.jp' HATENA_API_URL_FUTTER = 'atom' def getAllEntries(self): all_entries = [] url = self.getHatenaApiFirstUrl('entry') while url != '': hatenaApiData = self.getHatenaApi(url) for entry in self.getApiEntries(hatenaApiData): all_entries.append(self.formatEntry(entry)) url = self.getHatenaApiNextUrl(hatenaApiData) return all_entries def getHatenaApi(self, url): auth = self.getHatenaApiAuth() hatena_list = requests.get(url, auth=auth) dict_data = xmltodict.parse(hatena_list.text, encoding='utf-8') return dict_data def getApiEntries(self, hatenaApiData): return self.getDictValue(hatenaApiData, ['feed', 'entry']) def formatEntry(self, entry): format_entry = {} format_entry['hatena_entry_id'] = self.getHatenaEntryId(entry) format_entry['category'] = self.getCategory(entry) format_entry['title'] = self.getDictValue(entry, ['title']) format_entry['summary'] = self.getDictValue( entry, ['summary', '#text']) format_entry['content_md'] = self.getDictValue( entry, ['content', '#text']) format_entry['content_html'] = self.getDictValue( entry, ['hatena:formatted-content', '#text']) format_entry['draft'] = self.getDictValue( entry, ['app:control', 'app:draft']) format_entry['updated_at'] = self.getDictValue( entry, ['updated'], None) format_entry['edited_at'] = self.getDictValue( entry, ['app:edited'], None) return format_entry def getHatenaEntryId(self, entry): id_all = self.getDictValue(entry, ['id']) id = id_all[id_all.rfind('-') + 1:] if id_all else '' return id def getCategory(self, entry): category_all = self.getDictValue(entry, ['category']) if isinstance(category_all, list): category = category_all[0] else: category = category_all return self.getDictValue(category, ['@term']) def getHatenaApiFirstUrl(self, action): url = [ self.HATENA_API_URL_HEADER, self.HATENA_API_USER, self.HATENA_API_BLOG, self.HATENA_API_URL_FUTTER, action ] return os.path.join(*url) def getHatenaApiNextUrl(self, hatenaApiEntries): url = '' links = self.getDictValue(hatenaApiEntries, ['feed', 'link']) if isinstance(links, list): for link in links: if self.getDictValue(link, ['@rel']) == 'next': url = self.getDictValue(link, ['@href']) return url def getHatenaApiAuth(self): return (self.HATENA_API_USER, self.HATENA_API_KEY) def getDictValue(self, dictData, keys, emptyValue=''): for key in keys: if isinstance(dictData, dict): if key in dictData: dictData = dictData[key] else: return emptyValue return dictData
views.entry.py
修正
あとは今までのentry.pyから上記処理を呼び出して、登録・更新・削除を行うようにします
もうちょっと短くなると思ってたのですが、思いのほか処理減らなかったな……
でもまぁかなり読みやすくなったのでよし!!!
# coding: utf-8 from rest_framework import status from rest_framework import viewsets from rest_framework.decorators import action from rest_framework.response import Response from ..models import Entry from ..utils import HatenaApi from ..serializer import EntryAllSerializer, EntryCreateAndUpdateSerializer class EntryViewSet(viewsets.ModelViewSet): queryset = Entry.objects.all() serializer_class = EntryAllSerializer @action(detail=False, methods=['post']) def capture(self, request): hatena_api = HatenaApi() all_entries = hatena_api.getAllEntries() all_entries_sort = sorted(all_entries, key=lambda x: x['edited_at']) response = { 'created_count': 0, 'updated_count': 0, 'deleted_count': 0, 'failed_count': 0, 'failed_hatena_entry_ids': [], } hatena_entry_ids = [] for param in all_entries_sort: hatena_entry_id = param['hatena_entry_id'] hatena_entry_ids.append(hatena_entry_id) # 更新用パラメータ entry = Entry.objects.filter( hatena_entry_id=hatena_entry_id).first() if not entry: # 新規作成 mode = 'create' serializer = EntryCreateAndUpdateSerializer(data=param) else: # 更新 mode = 'update' serializer = EntryCreateAndUpdateSerializer( entry, data=param) if serializer.is_valid(): serializer.save() if mode == 'create': response['created_count'] = response['created_count'] + 1 else: response['updated_count'] = response['updated_count'] + 1 else: response['failed_count'] = response['failed_count'] + 1 response['failed_hatena_entry_ids'].append( hatena_entry_id) # はてなIDが存在しなければ論理削除 response['deleted_count'] = Entry.objects.exclude( hatena_entry_id__in=hatena_entry_ids).delete() return Response(response, status.HTTP_200_OK)
おわりに
リファクタリングが完了しました!
取込系の処理に関してはひとまずこれでよさそうかなーと思います
あ、でもテスト作ってないや。ユニットテスト作らなきゃだね
次回当たりユニットテスト作っていきたいと思います!
ではでは、ちゃお~~~!
小村のポートフォリオサイト開発(13) DjangoRestFramework レスポンスデータフォーマット
こんばんは、小村だよ!
下記のポートフォリオサイトを構築していくよ
- サイト:Little Village
前回記事の論理削除対応をしたね
今回はAPIのレスポンスのフォーマットを決めていきたいと思います
目次
- APIのレスポンスのフォーマットを決める
- 記事取込処理の正常系レスポンスを決める
- 全体共通のエラー時のレスポンスを決める
記録
APIのレスポンスのフォーマットを決める
参考:Udemy REST WebAPI サービス 設計 26. データの内部構造
参考:WebAPIでエラーをどう表現すべき?15のサービスを調査してみた」についてまとめた
- APIのレスポンスは、業務上では下記のようなフォーマットで返してました
{ result: 1 or 0 data: { ... } }
改めて今回調べたところ、resultなどは返さないのが一般的のようですね?
何が一番いいのか色々見ましたが最終的にUdemyで上記講座に書かれていた方針でいきます
{ code: xx detail: '' }
記事取込処理の正常系レスポンスを決める
ではでは、今回の記事取込処理のレスポンスを決めていきましょう
まず、正常に処理が行われたときは下記を返すようにしましょうか
http_status: 200 { created_count: x, updated_count: x, deleted_count: x, failed_count: x, failed_ids: [x, x, x] }
正常かどうかはレスポンスヘッダで確認します。
HTTP 200 OK はリクエストが成功した場合に返すレスポンスコードですね
それから作成、更新、削除件数を返します。
最後に入力チェックではじかれた件数とIDを返すようにしましょうか
そんな感じにViewsを修正します
修正して実行した結果が最後の図。問題なさそうですね!
全体共通のエラー時のレスポンスを決める
エラーが発生した際の処理も決めたいと思います
上記を参考にException Handlerをカスタマイズしたいと思います
- 参考サイトを参考に、
utiles.handler.py
を作成して図のように記載
これをsettingsに上記画像のように書くのだけど、そこで2時間くらいエラーと戦いました。
結果として、上記の書き方です。
- エラーで詰まったら飯食うの大事。一瞬で解けた。フォルダパスの書き方が原因だった
実装してエラー吐いた結果がこれ
本当は出力を
message
にしたかったのにdetail
で出てしまうのは自分の実力不足でする……業務の方のシステムだとdetailなんて吐いてないので、実装覗いてきて改良します
おわりに
やっとこさ取込機能に関する機能の実装は一通りおしまい!
あとはリファクタリングしたらweb側の実装に戻れます!
あともうちょいだ!がんばろー!
ではでは、ちゃお~~~!
小村のポートフォリオサイト開発(12) DjangoRestFramework はてなブログの記事 論理削除対応
こんばんは、小村だよ!
下記のポートフォリオサイトを構築していくよ
- サイト:Little Village
前回はてなブログ記事をすべてDBに書き込むことに成功しました
今回は論理削除対応と銘打って進めていきます
目次
- 削除日時を追加
- 削除日時を入れる処理追加
記録
削除日時を追加
自前のDBはバックアップとしての機能も期待しています。
そのため、はてなブログの記事が消えたとしても、削除はしません
そのかわりに、削除されていたら削除日を更新して記事の表示はしないようにします
ではまずmodelに削除日を用意しましょう
追加した後のマイグレーションファイルは下記のようになりました
削除日時を入れる処理追加
参考:(Django, DRF(Django REST Framework)での論理削除)https://qiita.com/t_toriumi/items/19c590ef3cda8438e741
上記サイトが参考になりそうですね!
サイトを参考に下記のように修正しました。
まずは
views
取込処理をしているなかで存在する
hatena_entry_id
を蓄え、最後になければdelete
かけてますここは特に問題ないですね
本題の
models
あらたに
QuerySet
とModelManager
の概念が加わってます。こちら業務で使ってますが詳しくは調べたことないのであとで調べてみますね
動作としては
delete()を実行すると論理削除する
delete_hard()を実行すると物理削除する
Entry.objectsでデータを覗くと論理削除データは省かれる
Entry.entireでデータを覗くと論理削除データも含む
という動きになります。どちゃくそ便利!
動作確認
そしたらはてなブログで記事を消して、ふたたび取り込みます
再取り込み後のデータが下記。ちゃんと削除日時が入ってますね!
DjangoのQuerySet
とModelManager
について
Modelsで出てきた
QuerySet
とModelManager
について調べてみます業務で使ってるのでなんとなくは使えてますが、改めて意味を調べてみます
Manager
今までなんとなしに
Entry.objects.all()
とかでデータを取得できてたのはこのManagerのおかげデフォルトでobjectsにアクセスした際、動くようになっているようですね。
今回のように
entire
の中でManagerを入れると、Entry.entireでアクセスできるようになります。そうしてアクセスした際の動きを、下記のQuerySetなどで制御するようですね。
QuerySet
QuerySetは実際にDBにアクセスせずにデータを加工したりする仕組みのようです。へー!
models.QuerySetが用意されていて、その中に基本のgetやfilterやexcludeなどが用意されてます
そのうえで、今回のような決まりきった削除などの更新処理も定義できるようですね。
DBにアクセスする際の抽出条件や処理条件を定義する役目ということでしょうね。
おわりに
論理削除の処理と合わせて、Djangoの基礎知識についても知れました
上記記事について熟読ができてないので、改めて後で読んでみようと思います。
次は、APIの返り値の設定をしていきたいと思います。
ではでは、ちゃお~~~!
小村のポートフォリオサイト開発(11) DjangoRestFramework はてなブログの記事のデータ格納(3)
こんばんは、小村だよ!
下記のポートフォリオサイトを構築していくよ
- サイト:Little Village
前回ひとまずはてなブログ記事をひとまずDBに書き込むことに成功しました
今回はそれを実働レベルに持っていきます!
目次
- 管理メニューのタイトル表示を修正
- はてな記事全件取得するまで回す
記録
管理メニューのタイトル表示を修正
前回、はてな記事を自前のDBに格納することができました
それを管理ページから確認した結果が下記
なにがなんだかわからないね!
というわけで管理画面表記を変更します
admin.py
を下記の通り変更
from django.contrib import admin from .models import Entry @admin.register(Entry) class Entry(admin.ModelAdmin): list_display = ( 'entry_id', 'hatena_entry_id', 'title', 'updated_at', 'edited_at', )
-
edited
:更新日時updated
:公開日時
という謎な仕様が判明したので合わせてmodelも変更してますが割愛
最終的な管理画面が下記。見やすくなったね!
はてな記事全件取得するまで回す
このURLが存在する間、ぐるぐる回るようにコードを修正します。
そして間違えて永久に(2分ぐらい)APIを呼び続けてしまった/(^q^)\
垢BANされないか心配だ!
そんなわけで、今後に備えて念のためAPIを呼ぶ感覚に0.5秒の感覚を設けました
修正箇所がこちら
これにより下記の通り過去投稿した全記事を格納できました!
振られるIDが投稿日時の降順なの気になるな……後日修正しよう
おわりに
記事の取得処理はもう大詰め!
とはいえ今のままだとすべての処理をViewsに書いてるから汚い汚い
リファクタリングちゃんとしなくちゃね!
ではでは今日はこの辺で!ちゃお~~~!
小村のポートフォリオサイト開発(10) DjangoRestFramework はてなブログの記事のデータ格納(2)
こんばんは、小村だよ!
下記のポートフォリオサイトを構築していくよ
- サイト:Little Village
目次
- はてな記事を
entry
に書き込み - 出たエラーとその対策
記録
はてな記事をentry
に書き込み
引き続きもくもくとコーディングして下記になりました!
はてなブログのIDが一致するものがあれば更新をかけて、なければ新規作成します
# coding: utf-8 import os import requests import xmltodict from rest_framework import viewsets from rest_framework.decorators import action from rest_framework.response import Response from ..models import Entry from ..serializer import EntryAllSerializer, EntryCreateAndUpdateSerializer class EntryViewSet(viewsets.ModelViewSet): queryset = Entry.objects.all() serializer_class = EntryAllSerializer @action(detail=False, methods=['post']) def capture(self, request): url = self.getHatenaApiUrl('entry') auth = self.getHatenaApiAuth() hatena_list = requests.get(url, auth=auth) dictData = xmltodict.parse(hatena_list.text, encoding='utf-8') entries = dictData['feed']['entry'] for entry in entries: if not isinstance(entry, dict): continue # hatena_entry_id取得 hatena_entry_id = entry['id'][ entry['id'].rfind('-') + 1:] if 'id' in entry else '' # category取得 if 'category' in entry: if isinstance(entry['category'], list): category = entry['category'][0]['@term'] else: category = entry['category']['@term'] else: category = '' # title取得 title = entry['title'] if 'title' in entry else '' # summary取得 summary = entry['summary']['#text'] if 'summary' in entry else '' # content_md取得 content_md = entry['content']['#text'] if 'content' in entry else '' # content_html取得 content_html = entry['hatena:formatted-content']['#text'] if 'hatena:formatted-content' in entry else '' # draft取得 draft = entry['app:control']['app:draft'] if 'app:control' in entry else '' # published_at取得 published_at = entry['published'] if 'published' in entry else None # edited_at取得 edited_at = entry['app:edited'] if 'app:edited' in entry else None # updated_at取得 updated_at = entry['updated'] if 'updated' in entry else None # 更新用パラメータ param = { 'hatena_entry_id': hatena_entry_id, 'category': category, 'title': title, 'summary': summary, 'content_md': content_md, 'content_html': content_html, 'draft': draft, 'published_at': published_at, 'edited_at': edited_at, 'updated_at': updated_at, } entry = Entry.objects.filter( hatena_entry_id=hatena_entry_id).first() if not entry: # 新規作成 serializer = EntryCreateAndUpdateSerializer(data=param) else: # 更新 serializer = EntryCreateAndUpdateSerializer(entry, data=param) if serializer.is_valid(): serializer.save() print('valid-OK') else: print('valid-NG') return Response(entries) def getHatenaApiUrl(self, action): HATENA_API_URL_HEADER = 'https://blog.hatena.ne.jp' HATENA_API_USER = os.environ.get('HATENA_API_USER') HATENA_API_BLOG = os.environ.get('HATENA_API_BLOG') HATENA_API_URL_FUTTER = 'atom' url = [ HATENA_API_URL_HEADER, HATENA_API_USER, HATENA_API_BLOG, HATENA_API_URL_FUTTER, action ] return os.path.join(*url) def getHatenaApiAuth(self): HATENA_API_USER = os.environ.get('HATENA_API_USER') HATENA_API_KEY = os.environ.get('HATENA_API_KEY') return (HATENA_API_USER, HATENA_API_KEY)
serializer
は下記
# coding: utf-8 from rest_framework import serializers from ..models import Entry class EntryAllSerializer(serializers.ModelSerializer): class Meta: model = Entry fields = '__all__' class EntryCreateAndUpdateSerializer(serializers.ModelSerializer): class Meta: model = Entry fields = ( 'entry_id', 'hatena_entry_id', 'title', 'summary', 'content_md', 'content_html', 'draft', 'published_at', 'edited_at', 'updated_at', )
entry
モデルに10件のレコードが登録されることが確認できました。再度実行して更新されることも確認。ひゃっほ!
出たエラーとその対策
- やっていく中でエラーとの格闘が勃発したのでそのメモ
TypeError: 'in <string>' requires string as left operand, not collections.OrderedDict
下記のコードが原因で発生。辞書型の
entry
にcategory
というkeyがあるかを確認しようとしているしむらー!ぎゃくぎゃく!!!
if entry in 'category':
- 正解は下記
if 'category' in entry:
おわりに
APIの第一歩がようやく踏み出せた感ありますね!
この先やっていくこととして
あたりの作業がまっております。がんばるぞい!
ではでは。ちゃお~~~!
小村のポートフォリオサイト開発(9) DjangoRestFramework はてなブログの記事のデータ格納
こんばんは、小村だよ!
下記のポートフォリオサイトを構築していくよ
- サイト:Little Village
よろしくね!
目次
- 不要なmodel削除
- models作成
views.blog.py
の内容をviews.entry.py
に移植- はてな記事を
entry
に書き込み
記録
運用ルールの決定
APIで取得したデータを眺めながら、いくつか運用ルールを決めました
今後の記事を書く際に気を付けたいと思います
記事タイトルは最大100文字
- それ以上の場合は切って格納
カテゴリは1記事につき1つ
- 複数ある場合は最初の1つのみDBに格納
不要なmodels削除
これから本格的にmodelを用意するので、これまでテストで使用していたmodelを用済みです!
さくっと削除しましょう!
下記の通り、Userモデルを削除し、紐づいていた処理を全て削除しました!
models作成
ではでははてなブログの記事を格納するモデルを作っていくよ!
一般的にこういった記事はEntryという名前が多いのでそれに習います
もともと存在していたしていた
Entry
モデルを下記の通り修正
from django.db import models class Entry(models.Model): CHOICE_DRAFT = (('yes', '下書き'), ('no', '公開')) entry_id = models.AutoField(verbose_name='記事Id', primary_key=True) hatena_entry_id = models.BigIntegerField(verbose_name='はてな記事Id', unique=True) category = models.CharField(verbose_name='カテゴリ', max_length=100, null=True, blank=True, default='') title = models.CharField(verbose_name='タイトル', max_length=200, null=True, blank=True, default='') summary = models.CharField(verbose_name='サムネイル文', max_length=1000, null=True, blank=True, default='') content_md = models.TextField(verbose_name='内容_MarkDown', null=True, blank=True, default='') content_html = models.TextField(verbose_name='内容_HTML', null=True, blank=True, default='') draft = models.CharField(verbose_name='下書き区分', max_length=10, choices=CHOICE_DRAFT, null=True, blank=True, default='yes') published_at = models.DateTimeField(verbose_name='公開日時', null=True, blank=True) edited_at = models.DateTimeField(verbose_name='作成日時', null=True, blank=True) updated_at = models.DateTimeField(verbose_name='更新日時', null=True, blank=True) class Meta: db_table = 'entry'
- それから
serializers/entry.py
も下記の通り修正
# coding: utf-8 from rest_framework import serializers from ..models import Entry class EntrySerializer(serializers.ModelSerializer): class Meta: model = Entry fields = '__all__'
この状態でhttp://localhost:8000/api/entries/にアクセスし、更新できることを確認
問題なっしん!
views.blog.py
の内容をviews.entry.py
に移植
はてな記事をentry
用に加工
メインの処理!
取得したはてな記事を
Entry
モデル用に加工するよentry_id
を取得した時点で時間が来てしまったので続きは次に回すよ!
おわりに
中途半端!!!
entryに登録までやりたかったけどできませんでした!
次がんばるぞ~~~!
ではでは、ちゃお~~~!
小村のポートフォリオサイト開発(8) DjangoRestFramework はてなブログの記事の必要データ選定
こんばんは、小村だよ!
下記のポートフォリオサイトを構築していくよ
- サイト:Little Village
よろしくね!
目次
記録
xml形式のデータをjson形式に加工
参考サイトの
xmltodict
を使用してDict型に変換したところで止めるよ!内容を見るとこんな感じ。
辞書形式のデータから必要な情報をピックアップ
ではでは、必要なデータを実際のデータと公式ページ見ながら考えていきます
ふむふむ!!
まず
entry
の中身がリスト型になっていて、最新7件分のブログデータが入ってるね必要そうなものをピックアップするとこんな感じ
項目 | 内容 | 理由 |
---|---|---|
id | ユニークキー | おそらく20桁以内の数値。ブログ記事のユニークキー |
title | 記事タイトル | |
summary.#text | 改行とかない本文 | トップページ用。詳細だとなし |
content.#text | markdown形式の本文 | 文字数制限につき一覧ではなく詳細で取得する必要あり |
hatena:formatted-content.#text | html形式の本文 | 一覧でも全部取得可能 |
category | カテゴリ | |
app:control.app:draft | 下書きか否か | |
published | 公開日 | |
app:edited | 作成日 | |
updated | 更新日 |
- こんな感じかな!
おわりに
今回はちょっと短いですがこの辺で!
次回は実際にmodelsを作成して必要なデータを取得していきたいと思います!
ではでは!ちゃお~~~!