Day9 Django 基礎
# views def index(request) return render(request, 'blogs/index.html')
これはrenderメソッドでrequest情報を元にして、blogs/index.htmlを返すよという意味。
# models.py def __str__(self): return self.title
とすると、モデルで設定したものを、adminで表示する時に使うことができる。
# views def index(request): blogs = Blog.objects.order_by('-created_datetime') return render(request, 'blogs/index.html', {'blogs':blogs}) # views def index(request): blogs = Blog.objects.order_by('-created_datetime') params = { 'blogs':blogs } return render(request, 'blogs/index.html', params)
ここの、{'blogs':blogs}でテンプレートに渡すことをしている。これは辞書型でキーが'blogs'、値がblogsとなる。またparamsで定義すれば、paramsを渡すこともできる。
#html <a href="{% url 'blogs:detail' blog_id=blog.id%}">記事を読む</a>
これはblogsアプリケーション内のdetailという名前(urls.py)を選択しているという意味。
blog_id=blog.idというのはblog_idという変数にblogのidを代入している。blog.idでidを取れるから、それを変数に代入している。これでid情報をurlに渡すことができる。
・GETメソッド:情報の読み取り、取得、(サーバーからデータを返してほしい時)
・POSTメソッド:情報の送信、投稿、(サーバーに対して何かしらのデータを送りたい時。データベースに新しい情報を追加することができる。)
# views def new(request) if request.method == POST: form = BlogForm(request.POST) ・ ・ ・
・request.POST........ユーザーがフォームに入力した情報が含まれている。その情報を元に新しいBlogFormインスタンスを生成するという処理になる。
・form = BlogForm(request.POST)を引数にrequest.POSTを取るだけでこのような処理ができる。これはBlogFormがModelFormを継承しているから。
# views def edit(request, blog_id): blog = get_object_or_404(Blog, id=blog_id) form = BlogForm(instance=blog) return render(request, 'blogs/edit.html', {'form':form, 'blog': blog})
・form = BlogForm(instance=blog).........instance=Blogで編集内容の中身を保持しておく。
def edit(request, blog_id): blog = get_object_or_404(Blog, id=blog_id) if request.method == "POST": form = BlogForm(request.POST, instance=blog) if form.is_valid(): form.save() return redirect('blogs:detail', blog_id=blog_id) else: form = BlogForm(instance=blog) return render(request, 'blogs/edit.html', {'form':form, 'blog': blog})
・form = BlogForm(request.POST, instance=blog)........編集の時には、既に特定の記事のインスタンスがあるため、どのインスタンスに対してフォームを作用させるかを指定する必要がある。それがinstance=blogを引数に取る理由。
今日は以上!
Day8 stackの続き
class InfixToPostfix(object): """ InfixToPostfix つまり中置から後置 get the postfix of the given infix expression """ def __init__(self, expression=None, stack=None): """ :param expression: the infix expression to be converted to postfix :param stack: stack to perform infix to postfix operation """ self.expression = list(expression) self.my_stack = stack @staticmethod def _is_operand(char): """ utility function to find whether the given character is an operator """ # OLD VERSION # return ord(char) >= ord('a') and ord(char) <= ord('z') \ # or ord(char) >= ord('A') and ord(char) <= ord('Z') return True if ord(char) in [ord(c) for c in ascii_letters] else False @staticmethod def _precedence(char): """ utility function to find precedence of the specified character """ if char == '+' or char == '-': return 1 elif char == '*' or char == '/': return 2 elif char == '^': return 3 else: return -1 def infix_to_postfix(self): """ function to generate postfix expression from infix expression """ postfix = [] for i in range(len(self.expression)): if self._is_operand(self.expression[i]): postfix.append(self.expression[i]) elif self.expression[i] == '(': self.my_stack.push(self.expression[i]) elif self.expression[i] == ')': top_operator = self.my_stack.pop() while not self.my_stack.is_empty() and top_operator != '(': postfix.append(top_operator) top_operator = self.my_stack.pop() else: while not self.my_stack.is_empty() and self._precedence(self.expression[i]) <= self._precedence( self.my_stack.peek()): postfix.append(self.my_stack.pop()) self.my_stack.push(self.expression[i]) while not self.my_stack.is_empty(): postfix.append(self.my_stack.pop()) return ' '.join(postfix) @staticmethod def get_code(): """ returns the code of the current class """ return inspect.getsource(InfixToPostfix)
・return True if ord(char) in [ord(c) for c in ascii_letters] else False
この書き方を初めて知った。
・ord()............ord()とはPythonの組み込み関数。1文字のユニコード文字を表す文字列に対し、その文字のユニコードポイントを表す整数を返す。この反対がchr()らしい。
ユニコードポイントとは、世界中の文字にポイントが割り当てられていて、この割り振られている番号のこと。
今日も昨日と同じです。ありがとうございます!
pygorithm/stack.py at master · OmkarPathak/pygorithm · GitHub
Day7 stack
class Stack(object): """ Stack object """ def __init__(self, limit=10): """ :param limit: the stack size """ self.stack = [] self.limit = limit def __str__(self): return ' '.join([str(i) for i in self.stack]) def push(self, data): """ pushes an item into the stack returns -1 if the stack is empty """ if len(self.stack) >= self.limit: # indicates stack overflow return -1 else: self.stack.append(data) def pop(self): """ pops the topmost item from the stack returns -1 if the stack is empty """ if len(self.stack) <= 0: # indicates stack underflow return -1 else: return self.stack.pop() def peek(self): """ returns the topmost element of the stack returns -1 if the stack is empty """ if len(self.stack) <= 0: # stack underflow return -1 else: return self.stack[len(self.stack) - 1] def is_empty(self): """ checks if the stack is empty returns boolean value, True or False """ return self.size() == 0 def size(self): """ returns the current size of the stack """ return len(self.stack) @staticmethod def get_code(): """ returns the code for current class """ return inspect.getsource(Stack)
・__init__(self, limit=10)........上限値らしい。
・self.size().........おそらくデータサイズのこと。
・@staticmethod..........デコレータ だって。インスタンス化しなくても呼び出し可能な関数のことらしいがよくわからんが、やりながら覚えよう。
【Python入門】デコレータの使い方をわかりやすく解説! | 侍エンジニアブログ
・inspect.getsource(Stack)...................活動中のオブジェクトから情報を取得する関数を定義している(inspect)。オブジェクトのソースコードを返す(.getsource)
明日もこちらをやってみます。ありがとうございます!
pygorithm/stack.py at master · OmkarPathak/pygorithm · GitHub
Day6 おもろくなってきたぜい!!
How To Become A Hacker: Japanese
class IndexView(LoginRequiredMixin, View): def get(self, request, *args, **kwargs): queryset = Book.objects.select_related('publisher').prefetch_related('authors').order_by('publish_date') keyword = request.GET.get('keyword') if keyword: queryset = queryset.filter( Q(title__icontains=keyword) | Q(description__icontains=keyword) ) context = { 'keyword': keyword, 'book_list': queryset, } return render(request, 'shop/book_list.html', context) index = IndexView.as_view() class DetailView(LoginRequiredMixin, View): def get(self, request, book_id, *args, **kwargs): book = Book.objects.get(pk=book_id) context = { 'book': book, 'stripe_pub_key': settings.STRIPE_PUBLISHABLE_KEY, } return render(request, 'shop/book_detail.html', context) detail = DetailView.as_view()
・.select_related関数/.prefetch_related関数
クエリを飛ばしすぎることを防ぐためにするらしい。ちょっとまだわからないからざっくりと覚えておく。
上記二つに関しては以下参照。
Django ORM の select_related, prefetch_related の挙動を詳しく調べてみた - akiyoko blog
・Qオブジェクト.......検索フォームをつくる時に使用することが多いらしい。モデルのデータの中からOR検索する時に使われるらしい。
Qオブジェクトの使い方を解説【具体的なコード付き】 - code for Django
class CheckoutView(LoginRequiredMixin, View): def post(self, request, *args, **kwargs): import time start_time = time.time() logger.info("User({}) posted the form.".format(request.user.id)) stripe.api_key = settings.STRIPE_API_KEY token = request.POST['stripeToken'] item_id = request.POST['item_id'] book = get_object_or_404(Book, pk=item_id) try: charge = stripe.Charge.create( amount=book.price, currency='jpy', source=token, description=book.title, ) except stripe.error.CardError as e: # The card has been declined return render(request, 'error.html', { 'message': "Your payment cannot be completed. The card has been declined.", }) logger.info("Charge[{}] created successfully.".format(charge.id)) messages.info(request, "Your payment has been completed successfully.") logger.debug("Finished in {:.2f} secs.".format(time.time() - start_time)) return render(request, 'shop/complete.html', { 'charge': charge, }) checkout = CheckoutView.as_view()
・import time を関数の中に書けることを初めて知った。
・time.time()....現在時刻を取得。returnの単位が秒かつ浮動小数点。
まず、ログとは、プログラムの実行中に起こった出来事の記録。loggingとはログを出力すること。
そして、ログレベルというものがある。そのうちのものがinfoとdebug。
・logger.info()....正常動作の記録
・logger.debug()........動作確認などデバッグの記録
【Python入門】loggingモジュールで処理の記録を残してみよう! | 侍エンジニアブログ
・try: except文......pythonの例外処理や。これは、知ってたけど、今回の写経回初めてで重要だと思ったからログを残しておこうと思った。
今日のソースコード元は以下です。ありがとうございます!
django-book-mysite-sample/views.py at master · akiyoko/django-book-mysite-sample · GitHub
今日は以上!
Day5
# -*- coding:utf-8 -*- #! usr/bin/env python3.7 import requests import json import zipfile import glob from bs4 import BeautifulSoup # 書類一覧APIのエンドポイント url = "https://disclosure.edinet-fsa.go.jp/api/v1/documents.json" # 書類一覧APIのリクエストパラメータ params = { "date" : '2014-03-18' "type" : 2 } # 書類一覧APIの呼び出し res = requests.get(url, params=params, verify=False) # resultデータ取得 res_text = json.loads(res.text) results = res_text["results"] # 決算データに絞る kessan = [] for result in results: if result['docDescription'] is not None: if '四半期' in result['docDescription']: kessan.append(result) # zipファイルの取得 docid = kessan[0]['docID'] url = 'https://disclosure.edinet-fsa.go.jp/api/v1/documents/' + docid pramas = { "type" : 1 } res = requests.get(url, params=params, verify=False) # ファイルへの出力 filename = docid + ".zip" if res.status_code == 200: with open(filename, 'wb') as f: for chunk in res.iter_content(chunk_size=1024): f.write(chunk) # zipファイル解凍 with zipfile.ZipFile(filename) as existing_zip: existing_zip.extractall(docid) # 対象htmの取得 filepath = docid + '/XBRL/PublicDoc' files = glob.glob(filepath + '*.htm') files = sorted(files) target_file = files[1] with open(target_file, encoding='utf-8') as f: html = f.read() # htmデータの取得 soup = BeautifulSoup(html, 'html.parser') tag_p = soup.find_all('p') for p in tag_p: print(p.text)
・エンドポイント.....ネットワークにつながっているパソコンとかサーバとかスマホのこと。ネットワークにつながっている端末のこと。ネットワークの端っこ、末端にいる端末。エンドポイントと言ったら、クライアント側のコンピュータとサーバーも含むよ。
・params の verify=FalseとはSSL証明書の検証に使うらしい!verify=FalseだとSSLErrorになるのを無視するよん。
・JSON.....JSONとはjavascript objects notionのことでテキストベースのデータフォーマットのこと。Javascriptのオブジェクト表記構文のサブセットとなっている。XMLと比べると簡潔に構造化されたデータを記述することができるため、記述が容易で人間が理解しやすいデータフォーマットらしい。
JSONってなにもの? | Think IT(シンクイット)
・json.loads(params)......JSON形式の文字列を辞書に変換するために使う。
・if res.status_code == 200........res.status_codeとはHTTPステータスコードのことで、100番台が処理中、200番台が成功、300番台がリダイレクト、400番台クライアントエラー、500番台がサーバーエラーのこと。
PythonでWebページを取得できたかどうかのエラーチェックと安全な中止の仕方
・chunk......ひとまとまりのデータのこと。
・zipfile.ZipFile(filename)..........ZipFileオブジェクトを通して、zipファイルにアクセスする
・.extractall...............これで解凍される。
・files = glob.glob(filepath + '*.htm')........glob関数を使うことで特定のパターンにマッチするファイルを取得することができる。特定のファイルの「かたまり」を取得するイメージ。
【初心者向け】Pythonのglobを徹底解説!正規表現の書き方も説明 | TechTeacher Blog
・files = sorted(files).......まずソートとは、既存のリストの要素を並び替えるもので、これはリストに対してしか使えない。そして、sorted関数はリスト以外にも、タプル、辞書、集合に使うことができる。
Pythonでリストをソートするsortとsortedの違い | note.nkmk.me
Pythonのsortメソッドとsorted関数の使い方の詳しい解説 | HEADBOOST
本日のコードはこれ!ありがとうございました!
【Python】企業の決算情報をEDINET APIで取得する | 無次元日記
Day4
# -*- coding:utf-8 -*- #! usr/bin/env python3.7 from datetime import date import os import sys import requests import json from zipfile import ZipFile import pandas as pd import glob # XBRLをpython形式に変換するライブラリのフォルダパス sys.path.append(r'任意のフォルダパス') from xbrl_proc import read_xbrl_from_zip import urllib3 from urllib3.exceptions import InsecureRequestWarning urllib3.disable_warnings(InsecureRequestWarning) def get_list(start, end, company_list): """指定した期間、報告書種類、会社で報告書を取得し、取得したファイルのパスの辞書を返す""" #取得期間の日付リストを作成 day_term = [start + timedelta(days=i) for i in range((end - start).days)] # データ抜出時に使用する、有価証券報告書および四半期報告書のコードの設定 ordinance_code = "010" form_code_quart = "043000" # 四半期報告書 form_code_securities = "030000" # 有価証券報告書 # EDINETのAPIで、書類一覧を取得し、各日ごとに必要な書類の項目の抜き出し quart_list = [] # 四半期報告書のリスト securities_list = [] # 有価証券報告書のリスト print('EDINETへのアクセスを開始') for i,day in enumerate(day_term): url = "https://disclosure.edinet-fsa.go.jp/api/v1/documents.json" params = {"data": day, "type": 2} # 進捗表示 if i % 50 == 0: print('{i}日目:{day}を開始'.format(i, day)) # EDINETからの1日の書類一覧を取得 res = requests.get(url, params=params, verify=False) # 必要な書類の項目の抜き出し if res.ok: json_data = res.json() for data in json_data['results']: # 指定した会社の、指定した書類の抜き出し if data['ordinanceCode'] == ordinance_code and data['formCode'] == form_code_quart and data['filerName'].replace('株式会社', '') in company_list: quart_list.append(data) elif data['ordinanceCode'] == ordinance_code and data['formCode'] == form_code_securities and data['filerName'].replace('株式会社', '') in company_list: securities_list.append(data) else: print('アクセス失敗かも{day}'.format(day)) list_dic = {'四半期報告書':quart_list, '有価証券報告書':securities_list} return list_dic
day_term = [start + timedelta(days=i) for i in range((end - start).days)]
・リスト内包表記
list = [function(i) for i in range(params)]
・繰り返し処理
for i,day in enumerate(day_term)
enumerate関数がここで使えるのは今日の学び。
・辞書
params = {"data": day, "type": 2}
・フォーマット
print('{i}日目:{day}を開始'.format(i, day))
json_data = res.json()
・replaceと、繰り返し処理のデータ表示のしかたの例
for sth in data['result'] sth['content_in_result'] == sth[''].replace(' ',' ')
・リストを辞書に含めることができる
quart_list = [] securities_list = [] list_dic = {'四半期報告書':quart_list, '有価証券報告書':securities_list}
def get_zip(list_dic, quart_dir_path, securities_dir_path): """取得したいデータをzipファイルで取得してファイルパスのリストを返す""" dir_path_dic = {'四半期報告書':quart_dir_path, '有価証券報告書':securities_dir_path} file_path_dic = {'四半期報告書':[], '有価証券報告書':[]} # ダウンロードした有価証券報告書のパスを格納する辞書 for key in list_dic.keys(): # 既にzipをDLしている場合のため、既存んおdocIDリストを取得 files = os.listdir(dir_path_dic[key]) existing_docID_list = [file.split('.')[0].split('_')[1] for file in files if os.path.isfile(os.path.join(dir_path_dic[key], file))] print('{key}ファイルのDLを開始'.format(key)) for i, doc in enumerate(list_dic[key]): # zipファイルパスのリストの作成 file_name = doc['filerName'].replace('株式会社', '') + '_' + doc['docID'] file_path = os.path.join(dir_path_dic[key], file_name + ".zip") file_path_dic[key].append(file_path) # 所有していないファイルの場合はDLを行う if doc['docID'] not in existing_docID_list: # ファイルを取得 url_zip = "https://disclosure.edinet-fsa.go.jp/api/v1/documents/" + doc['docID'] params_zip = {"type":1} # 進捗表示 if i % 100 == 0: print('{i}ファイル目を開始'.format(i)) # データのDL res_zip = requests.get(url_zip, params=params_zip, verify=False, stream=True) # zipとして保存 if res_zip.status_code == 200: with open(file_path, 'wb') as f: for chunk in res_zip.iter_content(chunk_size=1024): if chunk: f.write(chunk) f.flush() return file_path_dic
・keys()とは、おそらく、辞書のkeyだな!
for key in file_path_dic.keys():
・これこれ、俺が気になったコードは。まず、リスト内包表記、でifの条件分岐をリストに入れることができるのか。
・split("第一引数"、"第二引数")があって、第一引数にはどこで区切るか。第二引数には初めから数えてどのくらい区切るか、を指定する。で[0]は一番初めのもの。それをさらにsplitして[1]から表示する。というような気がする。わからんが。わかったら直していこう!
existing_docID_list = [file.split('.')[0].split('_')[1] for file in files if os.path.isfile(os.path.join(dir_path_dic[key], file))] list = [something for x in Xs if sth]
次のコードへ。
def zip_to_df(file_path_dic): """ダウンロードしたzipをdfに変換して各会社のdicにして返す""" all_df_dic = {} for key in file_path_dic.keys(): print('{key}データの変換を開始'.format(key)) df_dic = {} for i, company_zip in enumerate(file_path_dic[key]): # 進捗表示 if i % 100 == 0: print('{i}ファイル目を開始'.format(i)) company_name = os.path.splittext(os.path.basename(company_zip))[0].split('_')[0] doc_name = ps.path.splittext(os.path.basename(company_zip))[0].split('_')[1] if company_name not in df_dic: # 会社が辞書中に存在しない場合 df_dic[company_name] = {} df_dic[company_name] = read_xbrl_from_zip(company_zip)[0] elif company_name in df_dic: # 会社が辞書中に存在する場合 df_dic[company_name] = pd.concat( [df_dic[company_name],read_xbrl_from_zip(company_zip)[0]]) all_df_dic[key] = df_dic return all_df_dic # 会社のリストを読み込み company_list = ['ホウスイ','カネコ種苗'] # 取得期間の設定:直近n日分 delta_day = 800 end = date.today() start = date.today() - timedelta(days=delta_day) # ダウンロードしたデータのフォルダパス quart_dir_path = r'四半期報告書を保存する任意のフォルダパス' securities_dir_path = r'有価証券報告書を保存する任意のフォルダパス' # XBRLデータの取得 list_dic = get_list(start,end,company_list) file_path_dic = get_zip(list_dic, quart_dir_path, securities_dir_path) # XBRLからデータ形式を変換 df_dic = zip_to_df(file_path_list) # 営業利益部分抽出 quart = all_df_dic['四半期報告書']['カネコ種苗'] quart_oi = quart[(quart['tag'] == 'OperatingIncome') & (quart['context'] == 'CurrentYTDDuration')] quart_oi[['第N期', '終了日', '値']].sort_values('終了日') quart_oi = quart_oi.rename({'終了日':'Date', '値':'OperatingIncome'}, axis=1).reset_index(drop=True) quart_oi['type'] = '四半期報告書' securities = all_df_dic['四半期報告書']['カネコ種苗'] securities_oi = securities[(securities['tag'] == 'OperatingIncome') & (securities['context'] == 'CurrentYTDDuration')] securities_oi[['第N期', '終了日', '値']].sort_values('終了日') securities_oi = securities_oi.rename({'終了日':'Date', '値':'OperatingIncome'}, axis=1).reset_index(drop=True) securities_oi['type'] = '四半期報告書' oi_df = pd.concat([quart_oi, securities_oi]).sort_values('Date').reset_index(drop=True) # 各四半期ごとの営業利益や、前年同期比の売上高営業利益率の変化を計算 oi_df['tempOperatingIncome'] = oi_df['OperatingIncome'] - oi_df['OperatingIncome'].shift(1) oi_df['CalcOperatingIncome'] = oi_df['OperatingIncome'].mask(oi_df['第N期'] == 0, oi_df['tempOperatingIncome']) oi_df['CalcOperatingIncome'] = oi_df['CalcOperatingIncome'].mask(oi_df['第N期'] == 3, oi_df['tempOperatingIncome']) oi_df['CalcOperatingIncome'] = oi_df['CalcOperatingIncome'].mask(oi_df['第N期'] == 2, oi_df['tempOperatingIncome']) oi_df['CalcOperatingIncome_YoYchangerate'] = oi_df['CalcOperatingIncome'] / oi_df['CalcOperatingIncome'].shift(4) # 棒グラフで可視化 oi_df.plot.bar(x='Date', y='CalcOperatingIncome', rot=45) oi_df.plot.bar(x='Date', y='CalcOperatingIncome_YoYchangerate', rot=45)
明日からは短めのコードをかくこと。
その中で一番ためになったコードを説明してみることにする。
以上!
import requestsができない場合、sysが探索する範囲について
ImportError: No module named requests というエラーがでた。
まず、pip list でインストールされているか確認
(venv)$ pip3 list
次に、pip3 show でインストール先を確認
(venv)$pip3 show
これでインストール先が出る。
次に、インタラクティブモードでpythonの探索範囲がどこになっているか確認する。
(venv)$ python3.7 >>>import sys >>>print(sys.version); print(sys.path) [' ', '------------', '-----------------'] #と何個かリストで返されてくる
そして、リストにインストール先が表示されていなかったら、pathを追加する
>>>sys.path.append('書かれていたインストール先のpath')
それでも直らなかったから、一番初めにかくimport requests の上にimport sysを持ってきたら直った。
つまりsys、requestsの順にしたらErrorが出なくなった。なぜかはわからんが。だんだんやっていくうちにわかってくるだろう。
以上