MawaLog

一日一日、楽しく生きる。技術と音楽が好き。

herokuでデプロイしたDjangoアプリをムームードメインで独自ドメインに設定する手順メモ

Heroku: Up and Running: Effortless Application Deployment and Scaling

Heroku: Up and Running: Effortless Application Deployment and Scaling

1:ムームードメインドメイン取得

ドメイン取得これは普通に買うと良い。ムームードメインはたぶん更新費用が安めっぽいのでここで買った。

例:example.comとする。

2:herokuコンソールでセッティング1

herokuに行く

  • heroku>settings>「Add domain」
  • DNS Target」というのが出てくるのでこれをメモ

3:ムームーに戻ってDNS設定

  • ムームDNS設定変更=>「変更」=>「■カスタム設定」欄の「カスタム設定」ボタンを押す
  • サブドメイン:www,種別:CNAME,内容:www.example.com.herokudns.com(「DNS Target」に書いてあるドメインぽいもの)
  • 「セットアップ情報変更」を押す

4: heroku CLIでコマンド打つ

$heroku domains:add www.example.com

#herokuコンソールでも確認可能
$ heroku domains

5:herokuコンソールで確認

しばらく待ってるとSSL設定もしてくれる。

関連してhttp=>httpsにリダイレクトさせるには??

この辺が良さそう stackoverflow.com

Djangoのherokuへのデプロイメモ。

Heroku: Up and Running: Effortless Application Deployment and Scaling

Heroku: Up and Running: Effortless Application Deployment and Scaling

コメント

Djangoデプロイ時の自分用の最小コンパクトメモ。ローカル開発完了後。

コマンド履歴

外部連携を設定
・AWS S3にcollectstatic
・WSGIにwhitenoise設定

↓
これもローカルで動くことを確認
#以下は全て@rootディレクトリ
#(manage.pyやProcfileがあるディレクトリ)

Procfile
runtime.txt
composer.json
requirements.txt
を設置
↓
$ pip install -r requirements.txt
↓

#herokuが動くか確認
$ heroku --version

#gitを初期化
$git init

↓
.gitignore 設置
#@Procfileとかmanage.pyがあるディレクトリで実行
$ git add . 
$ git commit -m "deploy1"
(初回のみコミットファイル大量に出力)

$ heroku create
$ heroku config:set DISABLE_COLLECTSTATIC=1
$ git push heroku master
(これでとりあえず完了)

$ heroku run python manage.py migrate
$ heroku run python manage.py createsuperuser
(忘れがち)
#エラー対応
#ログを取る
$ heroku logs -t

#ローカルでデバッグ
$ heroku local

Django-Celeryにスケジュールをセットして動くようにする@ローカル

コメント

Celery(セロリ)のスケジューラーを使います

追記部分

#settings.py

from datetime import timedelta

CELERYBEAT_SCHEDULE = {
    'add-every-300-seconds': {
        'task': '<app名>.tasks.test_def',
        'schedule': timedelta(seconds=300),
        'args': (16, 16)
    },
}

CELERY_TIMEZONE = 'Asia/Tokyo'

なんかどうも5分に1回の起動が最短ペースの模様。数秒に一回だとcelery側でエラーがでた。

つぎに走らせる関数

#<app名>.tasks.py

@shared_task
def test_def():
    print("scheduler is fine!")
celery.beat.SchedulingError: Couldn't apply scheduled task add-every-300-seconds: test_def() takes 0 positional arguments but 2 were given

こうしていると、このエラーがでる。どうもスケジューラー経由の実行だと、たくさん規定の引数をぶちこむようだ。

note.nkmk.me

なので、 ↓
こうする。*argsをつけて可変長で引数を受け入れられるようにする。

#<app名>.tasks.py

@shared_task
def test_def(*args):
    print("scheduler is fine!")

これでよし。

Cerelyの起動もスケジューラー利用時は-Bオプションをつける

$ celery -A [proj名] worker -l info


こうする

$ celery -A [proj名] worker -l info -B

これでうまく動いた!^^/

参考

Periodic Tasks — Celery 4.2.0 documentation

Django-Celery-Redisのherokuへのデプロイメモ。

Heroku: Up and Running: Effortless Application Deployment and Scaling

Heroku: Up and Running: Effortless Application Deployment and Scaling

コメント

Django+Celeryで非同期処理ができるようになり、最終関門はherokuデプロイです。情報が少ないし公式ドキュメントだけだと(たぶん)エラーになり・・・ついにできました!その時のメモ。

手順1 Procfileに追加→Redis動かすワーカー起動を指示

Procfile

web: gunicorn [プロジェクト名].wsgi:application -b 0.0.0.0:$PORT
worker: celery worker -A [プロジェクト名].celery -l INFO
#↑この行が追加された
#ローカルで必要だった、$celery -A [プロジェクト名] worker -l infoをherokuが勝手にやってくれるイメージです

手順2 heroku localで動くか動作確認

(どこでもOK)$redis-server #redis起動は同じく必要
(仮想環境)$heroku local

ここまではローカルのsettings.pyで動かしました。これでデプロイ下準備は完了。

手順3 heroku-redisアドオンを追加

$heroku addons:create heroku-redis:hobby-dev

elements.heroku.com

手順4 アドオンが追加されたか確認

$ heroku redis:info
=== redis-xxxx-123456 (REDIS_URL) #仮の名前に変更してます
Plan:               Hobby Dev
Status:             available
Created:            2018-06-15 13:19 UTC
Version:            3.2.11
Timeout:            300
Maxmemory:          noeviction
Maintenance:        not required
Maintenance window: Thursdays 17:30 to 21:30 UTC
Persistence:        None
HA Status:          Unavailable

これはwebのherokuコンソールでも確認可能です。

手順5 Django用のheroku-redis接続パッケージをインストール

django-redis-cacheというモジュールが必要。公式ページに記載されてました。

pip install django-redis-cache

pip freeze > requirements.txt

手順6 settings.pyのCelery設定をデプロイ先のheroku-redisに接続されるようにする

#settings.pyローカルで動いた参考例(引用です)

BROKER_URL = 'redis://localhost'
CELERY_RESULT_BACKEND = 'redis'
CELERY_TASK_SERIALIZER = 'json'
CELERY_RESULT_SERIALIZER = 'json'
CELERY_ACCEPT_CONTENT = ['json']

引用元

Celery 3.1 を Django で使う

↓こう変える

#↓ここから追記↓

import os

CACHES = {
    "default": {
         "BACKEND": "redis_cache.RedisCache",
         "LOCATION": os.environ.get('REDIS_URL'),
    }
}

BROKER_URL = os.environ.get("REDIS_URL")
CELERY_RESULT_BACKEND = os.environ.get("REDIS_URL")

#↑ここまでが変更点↑

#BROKER_URL = 'redis://localhost' #localのときだけ
#CELERY_RESULT_BACKEND = 'redis' #localのときだけ
CELERY_TASK_SERIALIZER = 'json'
CELERY_RESULT_SERIALIZER = 'json'
CELERY_ACCEPT_CONTENT = ['json']

REDIS_URLという環境変数はheroku:redisを導入しときに勝手に設定されるのです。

手順7 いつものようにherokuにデプロイ

$git add.
$git commit -m "celery"
$git push heroku master
$heroku ps:scale worker=1
#↑workerプロセスを起動するためにこれがいる!

手順8 logをとってうまく行ってるかチェック

$heroku logs -t

参考資料

"Connecting in Django"の箇所 devcenter.heroku.com

自分の完成形とちょっと違うけど、参考になりました github.com

DjangoからCeleryへのタスクがつながらず、サーバーがずーっと応答しない!ときのCeleryセッティングのチェック項目

コメント

Celery(セロリ)が動きそうで動かないことがあります。djangoローカルサーバーがviewを呼び出したまま止まるのでエラーも吐かないのでなにをしてるかよくわかりませんでした。チュートリアル記事も何度も見直したのに動かない・・・こないだは動いたのに・・・なぜだ・・・これを次回から回避できます。

チェック項目

  • その1:pip install celeryは済んでいる

  • その2:pip install redisは済んでいる

  • その3:settings.pyにBROER_URLなどの記載は済んでいる

#settings.py参考例(引用です)

BROKER_URL = 'redis://localhost'
CELERY_RESULT_BACKEND = 'redis'
CELERY_TASK_SERIALIZER = 'json'
CELERY_RESULT_SERIALIZER = 'json'
CELERY_ACCEPT_CONTENT = ['json']

引用元

Celery 3.1 を Django で使う

  • その4:settings.pyがあるディレクトリの__init__.pyceleryに必要なコードを追記してある(今回はこれが抜けてた!追記すると動いた^^;)
#__init__.py

from __future__ import absolute_import, unicode_literals
from .celery import app as celery_app

__all__ = ['celery_app']
  • その5:task.pyに非同期処理する関数を@shared_taskデコレータつきで書いてる

  • その6:settings.pyがあるディレクトリのcelery.pyの追加と書き込みは済んでいる

  • その7:$brew install redisは済んでいる

  • その8:$redis-serverは動いている

  • その9:$celery -A [proj名] worker -l infoでワーカーは動いている

その8とその9あたりは、下記を参照ください

k-mawa.hateblo.jp

と、いうわけでおおまかに書いても9個もチェック項目があるという・・・

Django:social-auth-app-djangoとUUIDフィールドで苦労した話

Anthology

Anthology

コメント

最初にDjangoで運営してるメディアで、TwitterのSocialAuthでいきなりエラーがでてログインできなくなったんですよ!いままでは問題なく動いてたのに!!これが起きてしまったPYPIパッケージはsocial-auth-app-django==2.1.0でしたご注意を!!

HTTPError: 403 Client Error: Forbidden for url: https://api.twitter.com/oauth/request_token

ほっといても直らないし、APIの制限にひっかかることもしてない(Twitterデベロッパー管理画面でチェックしてもなにも制限されてる旨の表示はなし。キーを一回再生成したけど意味なし)らちがあかないので、もうメール認証でユーザーログイン機能を実装しなおそうと思い始めました。

経緯

#usermanage/models.py

class User(AbstractBaseUser, PermissionsMixin):

    uuid = models.UUIDField(default=uuid_lib.uuid4, primary_key=True, editable=False)
    #↑idのかわりにuuidを使ってみている

そうすると、ユーザー新規登録時にエラーがでてしまう。

・・・(中略)・・・
UUID('<uuidの文字列>') is not JSON serializable

なんだこれは・・・Oauthでは出なかったのにぃ・・・と、ググると、Django1.7以前あたりは有名なバグだったらしいが、今はDjango2.0だし、解決されてるよかったね的な公式記事が・・・うーむ。

https://code.djangoproject.com/ticket/24320

一旦諦めてuuidをやめようとするが・・・

うーん。でもuuidをPrimaryKeyにしちゃってるし、今からIDフィールド別途作ってとか・・・危険な感じしかしない・・・と、いうわけで多少安全そう??な(誤解)UUIDフィールドをPrimaryKeyのままCharfieldにしちゃうとシリアライザ−エラーが直ってハッピーなのでは??と仮説を立てる。で、実行。ついでにuuidの文字列がなにかリスクがあるのかもしれないと、数字だけで小さいメディアだし、かぶりにくいだろうタイムスタンプの羅列でチャレンジ。こういう感じ

uuid = models.CharField(max_length=500, default=datetime.datetime.now().strftime("%Y%m%d%H%M%S%f"),
                            primary_key=True, editable=False)

ローカルslqliteでは無事マイグレーションもできて動く!OK!いい感じだ。

で、herokuにデプロイ。migrat...エラーあああ!!!

DETAIL:  Key columns "user_id" and "uuid" are of incompatible types: uuid and character varying.

うーむ。調べるとPostgreではなんかフィールドをUUIDから変えようとするとなる症状らしいっぽい。。。

UUIDのままだと、最初のエラーがでるし、奇策のCharfield作戦は、Postgreに阻まれる。おいおいプロジェクト作り直し??絶望・・・

しかし諦めずに調べると、神記事が現れた!

arthurpemberton.com

これ!!!しかもうまくいきますようにみたいなお祈りも書いてる、、、良い人だ〜〜^^/

#usermanage/models.py に追記する↓

#↓ここから追記開始↓
from json import JSONEncoder
from uuid import UUID

JSONEncoder_olddefault = JSONEncoder.default

def JSONEncoder_newdefault(self, o):
    if isinstance(o, UUID): return str(o)
    return JSONEncoder_olddefault(self, o)

JSONEncoder.default = JSONEncoder_newdefault
#↑追記はここまで↑

class User(AbstractBaseUser, PermissionsMixin):

    uuid = models.UUIDField(default=uuid_lib.uuid4, primary_key=True, editable=False)
    #下記、モデルの続きが書いてある

すると、エラーが消えた!!!ありがとう〜〜〜m( )m

Celeryのchainの使い方メモ

コメント

Celery(セロリ)のメモ。

実装例

並列処理する対象の関数、関数その1、その2があるとして、関数その1が一度終わったら、そのまま引数を引き継いで関数その2に受け渡す例 (具体例:メールを送信する関数1、成功・失敗をプリントする関数2)

app/tasks.py/

#app/tasks.py/

from celery import shared_task


@shared_task
def add(x, y):
    return 2 * x + y

@shared_task
def printer(z):
    string="some string"
    print("pre print==>",string)#redisのログに吐き出される
    return z

app/views.py/

#app/views.py/

from .tasks import *
from celery import chain

#urls.pyと連動したtest

def test(request):
    result = add.delay(3, 8) #通常のcelery関数ひとつ
    while not result.ready():
        print('spam')
    print(result.get()) 
        #プリントデバッグはこれ(これ以外はredisのログを見る)

    result = chain(add.s(4, 4), printer.s()).apply_async()
        #↑関数addに引数4,4を投入、
        #addの返り値"2 * x + y"を
        #関数printerの第一引数になる。
        #add.sのsはシグネイチャーという機能の略らしい
    print(result.get()) #プリントデバッグは同じ

    ・・・以下は通常のDjango.viewsと同じ

参考記事

qiita.com