utamaro’s blog

誰かの役に立つ情報を発信するブログ

なぜ8日をようかというのか疑問に思って調べてみた。

なぜ8日をようかと読むのか

yahoo知恵袋からです。 https://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q1239742622

八を「や」、日を「か」と読んで「やか」となったのが、時が経つにつれて「やうか」に変化し、それが現在では「ようか」と読まれるようになりました。 蛇足かもしれませんが…八を「はち」と読むのは音読みで、「や」と読むのは訓読みです。かつ日を「にち」と読むのは音読みで、「か」と読むのは訓読みです。「ようか(やか)」は「八日」を単に訓読みで読んだだけと言えます。

goo辞書 https://dictionary.goo.ne.jp/jn/226193/meaning/m0u/

《「やか」の音変化》

どうやら、「やか」からの変化で良いみたいです。

「やか」から「ようか」に変化するとか、ほんとに?って疑いたくなってしまいますね。

真ん中の「う」がなんで入るかわからないですもん。

おなじように「7日」を「なのか」の「の」がなぜ入っているのかとか。

これはあれですかね。言いやすいからでしょうか?(これについては全く調べてないです)

日本語は不思議ですね。

左側に表示するナビゲーションメニューについて調べたときに参考にしたサイト

ナビゲーションのメニューがまとまっているサイトです。

http://photoshopvip.net/97481

こういったサイトはよく見ます。とても助かりますね。

この中で使えそうだなと思ったものを紹介したいと思います。

まずはこれです。

https://codepen.io/MrsColombo/pen/mEeQwy

  • htmlがきれいで、templateの構文を使ってforでリストを生成できそうだと思った
  • cssで書かれているので、scssに直しやすい
  • jsが複雑じゃない

もちろん、少し修正は必要ですが、少ない工数できれいなメニューを作れそうです。 (左側に固定するメニューではないようで残念です…)

明るいサイトに合いそうです。

どんどん紹介します。


これですが、見た目はよいですが、少し片手落ちだと思いました。

https://codepen.io/maggiben/pen/rCIFu

クリックした際に、右側の矢印がアニメーションされない。つまり、なんであるのかわからないです。

このくらいならcssを追加して対応できそうです。

リストがabsolute指定されているので、要件によっては少し修正が必要かもしれません。

fixedではないということは、スクロール時に残らないということです。

スクロールするとリストが途切れているように見えてしまいます。

参考にする場合はcssの変更が必要そうですね。


いいかな?と思いましたがコードを見たら大変そうだったやつです。

https://codepen.io/andytran/pen/rsegt

haml(htmlではない)で書かれているので、htmlに直したほうが良いでしょう。 hamlで書きたい場合はそのままで無問題

ほとんどclassやidを使っていないので、独自定義するスタイルに影響しそうです。 (reset.scssとか、cssフレームワークとか)

↓のように、タグにスタイルを入れているので、ページ内でリストを使っている場合は影響しそうです。 (許容範囲内かな?)

nav ul li a {
  display: block;
  padding: 10px 15px;
  color: #fff;
  text-decoration: none;
  transition: 0.2s linear;
  border-left: 2px solid transparent;
}
nav ul li a:hover {
  background: #fff;
  padding-left: 20px;
  border-left: 2px solid #1abc9c;
  color: #1abc9c;
}

右側の矢印がアニメーションしてません。これは修正ですね。

参考文献という英単語を調べたときに使ったサイト

結論から

参考文献 = 「Works Cited」 or 「reference」 or 「bibliography」

英単語を調べるのに、以下のサイトが役に立ちました。 https://eikaiwa.dmm.com/uknow/questions/19454/

といってもDMM英会話なんですけど。

読んだ時期によって解答が消えてたりするかもしれないので、引用をのせますね。

大学のレポートの最後に付ける、レポート内で使った資料のリストのことを、Works Citedと言います。worksは、もちろん仕事だったり研究だったりを示しますので、それが「文献」となります。一方「参考」というのは「(自分が)参考にした」つまり「(文献が)参考にされた」という、分詞形容詞-edを使ってcitedとなり、worksの後ろに付けます。MLAスタイルでも、APAスタイルでも、全てレポートの最後にはworks citedを付けてくださいね。

この解答が一番役にたったのですが、もちろんこの解答が正しいのかどうかも調べてます。

まずは、citedが「引用」「参考」という意味で使われるのかどうか。

これは英辞郎on webで調べました。 https://eow.alc.co.jp/search?q=%22cite%22&ref=hk

ついでにweblioでも調べてます。 https://ejje.weblio.jp/content/cite

ここまでで、どうやら「citeという単語が参考という意味で使われる」というのが解答が正しそうというのがわかりました。

次に、「レポートの最後でworks cited」と使うのかどうかを調べました。

参考文献がどんな使われ方をするのかは、調べなくてもよかったのですが、解答を読んで気になったので調べてみました。

まず↓のサイトでは「works」や「cite」という単語で検索しても出てきませんでした。

http://user.keio.ac.jp/~kiyota/kozo/Courses/References.html

Weblio英語勉強コラムのページです。 http://english-columns.weblio.jp/?p=5632

MLA(Modern Language Association style)は使用頻度が特に多い文献スタイルで、文学や言語の分野での使用が多くみられます。参考書目としての表記は「Works Cited」です。

ヒットしましたね。

ですが、そのすぐ下に↓のような文がありました。

APA(American Psychological Association)はMLAと比べ一般的に読みやすく表記されたスタイルで、社会科学やビジネスの分野での使用が多く見られます。参考書目としての表記は「Reference」です。

どうやら、referenceという単語もあるみたいです。

さらに、MLAフォーマット、APAフォーマットのように、どのように参考文献を書くかによって単語が変わるようです。

すごく面倒です。統一してほしいですよ…

ここまででやめても良かったのですが、ついでに英語サイトを調べてみました。

「works cited reference」で調べたときに出たサイトです。

http://www.citethisforme.com/blog/2017/06/27/69196

どうやら、「works cited」「reference」の他に「Bibliography」という単語もあるようです。

英語は読めないので、google翻訳の訳ですが、大方このような感じでした。

「bibliographyは、論文を書く際に参考にしたものだけではなく、準備段階で参考にしたものも含める」

のだそうです。

結局、参考文献という単語は「works cited」か「reference」を使うと良いと思います。

「bibliography」の場合はもっと準備段階も含めたい場合に使うと良いと思います。

Djangoのモデルに定義していないフィールドを追加する方法

こんな感じのModelを定義しているときに、追加でフィールドを入れたくなったときがありました。

class Sample(models.Model):
    uuid = models.UUIDField(unique=True)
    created_at = models.DateTimeField(auto_now_add=True)
    modified_at = models.DateTimeField(auto_now=True)

    class Meta:
        db_table = 'sample'

いれたフィールドをtemplateで使用して画面に表示するといった具合で使いました。

↓のコードで対応することができました。

model.__setattr__('icon', 'icon/' + sample.author.username)

iconを表示する際にusernameの前にフォルダ名が必要だったのです。

ですが、Djangoのタグを使っていて文字列の連結ができないし、カスタムタグで拡張することもできない。(少なくとも私には見つけられませんでした。)

最初はmodelはorderdictだからmodel['icon']で対応できると思ったのですが、ダメでした。

Djangoでページングを表示するための関数

Djangoでページング処理を作成する際に作った関数を紹介します。

コードの紹介になるので、紹介はコードにコメントにて行います。

前後のページを表示するための関数

# self.limit: データ表示数
def page_data(self, count, page):
    # count: データ数
    # page: 現在のページ番号
    current_page = page
    if count == 0 or count < self.limit:
        # データ数が0の場合に対応
        prev_page = 1
        next_page = 1
        page_limit = 1
    else:
        # ページの最後尾の数値をみつける。
        page_num = int(count / self.limit)
        # 割り切れない場合は+1して、あまりを表示できるようにする
        page_limit = page_num if count % self.limit == 0 else page_num + 1

        # 前のページが1未満にならないようにする
        prev_page = 1 if (current_page - 1) < 1 else current_page - 1
        # 次のページがページ番号の限界を超えないようにする
        next_page = page_limit if (current_page + 1) > page_limit else current_page + 1
    return {
        'prev': prev_page,  # 前のページ
        'current': current_page,  # 現在のページ
        'next': next_page,  # 次のページ
        'limit': page_limit,  # ページの限界
        'next_page': 'home',  # {% url next_page %}のように使用する
    }

テンプレートのコードをなくしてしまったので紹介できません。orz

returnで返しているデータからhtmlタグを作成するとできます。

範囲でページを表示するための関数

もう少しスマートに作成する方法がありそうです。

def get_page_list(self, data_size, current_page):
    PAGE_RANGE_SIZE = 5  # ページ番号を表示する数
    if data_size % self.limit == 0:
        page_limit = int(data_size / self.limit)
    else:
        # 割り切れない場合は+1して、あまりを表示できるようにする
        page_limit = int(data_size / self.limit) + 1
    page_list = []
    # ↓ startとendを計算して、あとでループに使用する
    start = current_page - 2
    if start < 1:
        start = 1

    end = start + PAGE_RANGE_SIZE
    if end > page_limit:
        end = page_limit + 1
        # ↓ を入れないとページ番号がずれる
        start = end - PAGE_RANGE_SIZE
        if start < 1:
            start = 1

    # ページ番号を取得する
    for pi in range(start, end):
        page_list.append(pi)
    return {
        'current': current_page,  # 現在のページ
        'limit': page_limit,  # ページ番号の限界
        'nums': page_list,  # ページ番号のリスト
        'next_page': 'home',  # {% url next_page %}のように使用する
    }

テンプレートを作成する。

bulmaというcssフレームワークを使用していますが、基本は同じかと思います。

横に長くなってしまって見づらいです。どうにかしたいところです。

<ul class="pagination-list">
    {% if page.current != 1 %}
    <!-- 現在のページが先頭なら表示しない -->
    <li><a class="pagination-link" href="{% url page.next_page %}?{%query_transform request page=1%}"><<</a></li>
    {% endif %}
    {% for num in page.nums %}
    <li>
        <!-- 現在のページの場合はクラスを追加する -->
        <a class="pagination-link {% if num == page.current %} is-current {% endif %}" href="{% url page.next_page %}?{%query_transform request page=num%}">{{num}}</a>
    </li>
    {% endfor %}
    {% if page.current != page.limit %}
    <!-- 現在のページが最後尾なら表示しない -->
    <li><a class="pagination-link" href="{% url page.next_page %}?{%query_transform request page=page.limit%}">>></a></li>
    {% endif %}
</ul>

query_transformというのは独自に作ったtagです。

これを使うと、クエリストリングをスマートに作成できます。

@register.simple_tag
def query_transform(request, **kwargs):
    updated = request.GET.copy()
    for k, v in kwargs.items():
        updated[k] = v

    return updated.urlencode()

これはどこかの記事で紹介していた気がします。

stackoverflowで載っていたものを使っています。

pythonでjwtを使う際に作ったutilについて

作成したjwtのutilを紹介します。

作成したutilですが、まだまだ修正途中のものです。使用する場合は注意してください。

jwtについての詳細についてはこちらを参照してください。

https://jwt.io/introduction/

コードと解説の距離が離れると読みづらいと思いますので、できる限りコメントを書きました。

そちらを見てください。

import datetime
from datetime import datetime, timedelta

import jwt
import pytz


class JwtContent(object):

    JWT_EXPIRE_DAY = 1

    JWT_ALGORITHM = "HS256"

    JWT_SECRET_KEY = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

    JWT_COOKIE_NAME = "Authentication"

    COOKIE_EXPIRE_FORMAT = "%a, %d-%b-%Y %H:%M:%S GMT"


class JwtUtil(object):

    @staticmethod
    def create_token(payload, is_revoke=False):
        """
        payloadを使用してjwtトークンを発行する
        :param is_revoke: Trueにするとtokenを有効期限切れにする
        :param payload: dict object
        :return: jwtでエンコードされたトークン
        """
        timezone = pytz.timezone('Asia/Tokyo')
        now = datetime.now(tz=timezone)
        if is_revoke:
            delta = timedelta(days=-JwtContent.JWT_EXPIRE_DAY)
        else:
            delta = timedelta(days=+JwtContent.JWT_EXPIRE_DAY)
        result = now + delta
        payload["exp"] = result
        encode_data = jwt.encode(
            payload,
            JwtContent.JWT_SECRET_KEY,
            algorithm=JwtContent.JWT_ALGORITHM
        )
        return encode_data.decode('utf-8')

    @staticmethod
    def is_expired_token(jwt_token):
        if jwt_token is None:
            return True, None, None
        try:
            decode_data = jwt.decode(
                jwt_token,
                JwtContent.JWT_SECRET_KEY,
                algorithms=[JwtContent.JWT_ALGORITHM]
            )
            return False, decode_data, None
        except jwt.ExpiredSignatureError as e:
            # 有効期限切れ
            return True, None, e
        except jwt.InvalidTokenError as e:
            # decodeが実行できなかった
            return True, None, e
        except Exception as e:
            return True, None, e

    @staticmethod
    def is_expired_session_token(request, cookie_name):
        """
        requestからトークンのクッキーを取り出してそのクッキーの有効期限を判定する
        :param cookie_name:
        :param request:
        :return: 成功時デコードされたデータ(dict object). 失敗時True
        """
        jwt_token = request.COOKIES.get(cookie_name)
        return JwtUtil.is_expired_token(jwt_token)

    @staticmethod
    def set_jwt_cookie(response, jwt_cookie_data, cookie_name):
        """
        responseオブジェクトにjwtトークンキーをセットする
        jwtのexpireはcommon.config.JWT_EXPIRE_DAYによって変わる
        また、タイムフォーマットはAsia/Tokyoのゾーンとしている
        セキュリティのため、httponlyをtrueにしている
        :param response:
        :param jwt_cookie_data:
        :return:
        """
        timezone = pytz.timezone('Asia/Tokyo')
        expire_datetime = datetime.now(tz=timezone) + timedelta(days=+JwtContent.JWT_EXPIRE_DAY)
        expire_datetime_str = expire_datetime.strftime(
            JwtContent.COOKIE_EXPIRE_FORMAT
        )
        response.set_cookie(
            cookie_name,
            jwt_cookie_data,
            expires=expire_datetime_str, httponly=True
        )
        return response

    @staticmethod
    def delete_jwt_cookie(response, cookie_name):
        response.delete_cookie(cookie_name)
        return response

データが存在しない場合にデータを追加するSQL

テーブル内にデータが存在しない場合に限って、データを追加する方法を紹介します。

クエリについては日本語で解説をするよにも、まずはコードを見たほうが早いと思うので、先に載せます。

こちらが、データを追加するクエリです。

INSERT INTO tag (
    name,
    created_at,
    modified_at
)
SELECT
    'test',
    now(),
    now()
WHERE
    NOT EXISTS (
        SELECT
            1
        FROM
            tag
        WHERE
            name = 'test'
    )

上記のクエリは、tagを追加する際に、すでにタグが存在していたら追加しないというクエリです。

これは、select insert文というものです。そして、not existを使って、存在しない場合を条件で追加しています。

where 1で真になるので、データがある場合でinsertが実行されます。

おまけ

一般的なinsert文はこのようなクエリだと思います。

insert into tag (
    xxxx,
    yyyy,
    zzzz
) values (
    1,
    2,
    3
)

じゃあ、このクエリにwhereをつければよいのでは?と考えるかもしれませんが、それは構文エラーになります。

一応クエリを載せておきます。

INSERT INTO tag (
    name,
    created_at,
    modified_at
) values (
    'test',
    now(),
    now()
)
WHERE
    NOT EXISTS (
        SELECT
            1
        FROM
            tag
        WHERE
            name = 'test'
    )