Pythonで日付計算をするにはdateutilを使うと簡単

Pythonの標準のdatetimeモジュールだと月の計算を自前で用意しなければならなかったりして、日付計算が面倒になるんだけど、dateutilモジュールのrelativedelta関数を使うと日付計算が簡単になって便利。

インストール

pip install python-dateutil

now = datetime.datetime.utcnow()

from dateutil import relativedelta
#一ヶ月後の日付を求める
date += relativedelta(months=1)

#一週間後の日付を求める
date += relativedelta(months=1)

#明日の日付を求める
date += relativedelta(days=1)

[Django] ユニークなファイル名で画像をアップロードする tips

uuidを使ったファイル名でアップロードすることにより、ファイル名がかぶるのを防ぐことができる。

import uuid
...
def get_file_path(instance, filename):
    ext = filename.split('.')[-1]
    name = "%s.%s" % (uuid.uuid4(), ext)
    return os.path.join('upload_to_dir', name)


class YourModel(models.Model):
    data = models.ImageField(upload_to=get_file_path,null=True)
    created_date = models.DateTimeField(auto_now = True)

[Django] Userをカスタマイズする

Custom User Modelの作成

AbstractBaseUserを継承したModelを作成します。このModelが標準のUser Modelの機能を満たすためには下記の事項を満たす必要があります。

  • Modelがユニークなキーを持っていること。
  • Modelがユニークなフィールド(username,email,,,etc)を持っていること。
  • get_full_name(),get_short_name()を実装していること。

AuthUser


class AuthUser(AbstractBaseUser, PermissionsMixin):
    def get_short_name(self):
        ...

    def get_full_name(self):
        ...

    username = models.CharField(unique=True, max_length=30)
    email = models.EmailField(unique=True)
    date_joined = models.DateTimeField(auto_now_add=True)
    is_active = models.BooleanField(default=True, null=False)
    is_staff = models.BooleanField(default=False, null=False)

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = ['username']
    objects = AuthUserManager()

USERNAME_FIELDはそのユーザーのユニークなキーを記述します。ここではemailがユニークなフィールドとします。

REQUIRED_FIELDSはユーザーを作成するために必要なキーを記述します。

objects = AuthUserManager()標準のBaseUserManagerを使う代わりにAuthUserManagerを使うということをDjangoに知らせています。 これによって今後create_user,create_superuserのメソッドを呼ぶときにAuthUserManagerクラスのcreate_user,create_superuserのメソッドが呼ばれるようになります。

AuthUserManagerの実装は以下のようになります。

AuthUserManager

class AuthUserManager(BaseUserManager):
    def create_user(self, username, email, password):
        if not email:
            raise ValueError('Users must have an email')
        if not username:
            raise ValueError('Users must have an username')

        user = self.model(username=username, email=email, password=password)
        user.is_active = True
        user.set_password(password)
        user.save(using=self._db)
        return user

    def create_superuser(self, username, email, password):
        user = self.create_user(username=username, email=email, password=
        password)
        user.is_staff = True
        user.is_superuser = True
        user.save(using=self._db)

次に、DjangoにUserモデルではなく、AuthUserを使用するということをsettings.pyに以下のコードを記述して知らせてあげましょう。

AUTH_USER_MODEL = 'yourapp.AuthUser'

Done!

以上でUserを拡張したAuthUserを作成できました。
Enjoy coding!

Parseで特定のデバイスにPUSH通知を送信する

Push通知を特定のデバイストークンを持つデバイスに送信するコードのメモ。

CURL

curl -X POST \
  -H "X-Parse-Application-Id: ..." \
  -H "X-Parse-REST-API-Key: ..." \
  -H "Content-Type: application/json" \
  -d '{
        "deviceType": "ios",
        "deviceToken": "...",
        "channels": [
          ""
        ]
      }' \

https://api.parse.com/1/installations

Python

import json,httplib

connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.request('POST', '/1/push', json.dumps({
    "where": {
        "deviceToken":'SPECIFIC_DEVICE_TOKEN'
    },
    "data": {
        "alert": 'HELLO'
    }
}), {
    "X-Parse-Application-Id": "...",
    "X-Parse-REST-API-Key": "...",
    "Content-Type": "application/json"
})
result = json.loads(connection.getresponse().read())
print u'{}'.format(result)


Core DataでDBのMigrationを行う。

Core Dataで一旦作成してしまったテーブルに変更を行うとConflict Errorが発生してアプリがクラッシュしてしまいます。
App Storeに出す前の開発段階だと既存のsqliteファイルを削除してアプリを実行すれば、このクラッシュはとりあえず防ぐことはできますが、すでに既存のスキーマがプロダクションで動作している場合はそういうわけにもいきません。どうすればいいのでしょうか?

そんなときはCore DataのMigration機能を使いましょう。Migration機能を使うとDBに保存されているデータを保持したまま、テーブルの作成やカラムの変更を行うことが出来るようになります。

以下にMigrationの手順を示します。

(1/2) AppDelegateの修正

AppDelegate.swiftのpersistentStoreCoordinator…の箇所に以下の++のコードを追加してください。

    lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator? = {
           var coordinator: NSPersistentStoreCoordinator? = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel)
           let url = self.applicationDocumentsDirectory.URLByAppendingPathComponent("medicalcheck.sqlite")
           var error: NSError? = nil
           var failureReason = "There was an error creating or loading the application's saved data."

            // optionsを追加

            ++ let options = [NSMigratePersistentStoresAutomaticallyOption: true,
            ++   NSInferMappingModelAutomaticallyOption: true]


           if coordinator!.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: url, options: options, error: &error) == nil {
               coordinator = nil
            ...

NSMigratePersistentStoresAutomaticallyOptionは自動的にMigrationを行うという意味で、NSInferMappingModelAutomaticallyOptionはMigrateされたDBを基に自動的にマッピングモデル(.xcdatamodel)のファイルを作成するという意味です。

これで AppDelegateの編集は完了です。

(2/2) 新しいModelのバージョンを作成

.xcdatamodelのファイルを選択して,変更したいEntitiyを選択します。次にMenu > Editor > Add Model Versionを選択します。 すると、新しいバージョン名を入力する画面が表示されますので新しいバージョン名を適当に入力してFinishを押します。

新しいバージョンが作成できたら、.xcdatamodeldの箇所に新しいバージョンのxcdatamodelファイルが作成できてますのでカラムを編集したり、Entityを編集してみましょう。

最後に右側のInspectorウインドウのModel Versionのcurrentの参照先を新しいバージョンに設定します。

Done!

Migration作業はこれで終わりです。 これでDBの変更を恐れずにガンガン開発できるようになります。