偏った言語信者の垂れ流し

2014-10-28

[][]北海道で #ingress をプレイした感想

出張で10月の後半2週間ほど北海道北見市(北見駅の近く)に滞在してました。

滞在中にIngressをプレイしていました。

平日は基本的に仕事をしていたので、実質プレイしてたのは8日ぐらいでした。

北海道(主に道東や道北)の2014年10月の状況と、行ってきた感想など書いておきます。

もともと3年ほど北海道にいたので地理などは少しわかってる状態です。

北海道気候

北海道は広いので、地域によって寒暖や風の強さ、積雪量などにかなり差があります。

滞在していた北見市の市街地では、昼が10度前後、夜が-4度前後と昼夜の温度差が結構ありました。

季節の変わり目は特に天気が不安定です。最高気温が20度近くある日の翌日に雪が降ったりとか。

峠のほうは降雪してました。帰宅した日(10/28)には札幌でも雪が降ったようです。

外を出歩くにしても、夕方から夜にかけて急激に気温が下がるので、季節問わず服装には注意が必要です。

北海道のポータル

ポータル間の距離は札幌の中心地であれば100m〜200m間隔ぐらいですが、今回行った道東や道北のほうだと1km〜50kmくらい開くことが多かったです。

f:id:nullpobug:20141028203452p:image:h360

申請すればポータルになりそうなものはたくさんあるので、どんどん申請すると良いと思います(いっぱい申請してきました)。

高レベルエージェントも少ないようで、札幌以外では、LV7、LV8のポータルはほとんどなく、LV4〜LV6ぐらいのものが多いです。

そのため、X7とX8の補給は期待できません。道外から行くのであれば、あらかじめ武器は多目に用意しといたほうがいいです(X8を500個ちょっと持って行きましたが使いきった)。

また、北海道では積雪の時期(11月ごろ)になると、春まで通行止めになる道や、閉鎖になる施設が多数あります。

北海道地区 道路情報

一部のポータルはこの閉鎖されるエリアにあり、取り返すことが困難(ほぼ不可能)です。閉鎖の期間は積雪が始まる11月ごろから、雪が溶ける4月、5月ごろまでの約半年になります。

そのため、場所を選べばGuardianの実績は比較的狙いやすいと思います。

低レベルのエージェントでは、一人で構築したポータルから都市間を結ぶリンクを作ろうとしても、リンク可能距離より遠くなることがあるので、LinkAmpを使う必要性があるかもしれません。

私は滞在中に1回だけLinkAmpを使いました(225kmのリンク)

人口が少ないので、大きなCFを作っても関東に比べてMUは極端に少ないです。

f:id:nullpobug:20141028203453p:image:w360

f:id:nullpobug:20141028203454p:image:w360

移動手段

ポータル間距離があるため、徒歩や自転車では厳しいです。エンジン付きの乗り物がメインになります。

私はオートバイで移動してました。東京から仙台まで陸路で移動して、フェリーで苫小牧に渡りました。

f:id:nullpobug:20141011093022j:image:h360

10月の後半は、雪が降っても晴れれば解けるぐらいの時期ですが、夜間早朝は路面が凍結することもあります。

町と町の間が20〜30km程度離れていることが多く、中心地以外は信号がほとんどありません。雪が降ってない時期は道幅が広いので走りやすいです。

f:id:nullpobug:20141028203456j:image:w360

夜間は街灯がない道が多いので、真っ暗な道を走るのが苦手な人にはおすすめできません。

10月末の今の時期だと、日が落ちるのが16時すぎで、17時ごろには真っ暗になります(道東地域は特に早い)。

鹿の飛び出し注意の標識が多く、実際に道の真ん中にいることもあります(一回遭遇した)。熊がいる可能性もあります。

通信環境が悪い

国道沿いでもキャリアと通信方式によってはインターネット接続や通話不可な場所が多数あります。

電柱や街灯がまったくない道が数十キロ続くところもあります。

f:id:nullpobug:20141025144438j:image:w360

ポータルの近くまで行ったのに通信不可、ということもありました(150km移動して行った場所だったので悔しい)

f:id:nullpobug:20141028203458p:image:h360

手持ちがb-mobileのU300のSIMとY!MobileのPocketWifi(GL10P)だったのですが、PocketWifiのほうは市街地以外ではほとんど圏外でした。

また、当然ながら通信手段がない場所で、事故や車両の故障などがおきると助けがなかなか来ない可能性があります。

戦略

リンク作成、CF作成の戦略にも工夫が必要です。ポータル間距離があるため、何度もポータルを往復してポータルキーを集めるのが困難です。

できるだけ移動距離を少なくし、構築できるよう、あらかじめ移動ルートと取得するキーの数を決めておいたほうがいいです。

構築したポータルは熱心なエージェントが近くにいない限り、すぐに取替されるということはそんなに無いです。

物理的に距離が離れているので取り返すにしても時間がかかります。

移動時間を考慮した戦略をとる必要があります。

まとめ

北海道気候が厳しかったりポータル間距離があります。また通信環境が悪いことも多いです。

Ingressを快適にプレイできるかというとそうでもないんですが、観光ついでに楽しむのもいいですし、北海道ならではの戦略もなかなかおもしろいと思います。

というわけで、北海道に行ってお金使ってください。

f:id:nullpobug:20141028203501j:image:w240

f:id:nullpobug:20141028203500j:image:w240

f:id:nullpobug:20141028203459j:image:w240

ごはんもおいしかったよ。

以上。

2014-09-22

[][]Django1.7の管理サイトでアプリケーション名を変更する

Django1.6以前のバージョンでは、管理サイトで表示されるアプリケーション名を変更する方法は通常の使い方では提供されていませんでした。

変えたいのはこの「Myapp」という部分。

f:id:nullpobug:20140922221155p:image

Django1.7ではアプリケーションごとの設定が抽象化、再利用可能な仕組みが導入され、アプリケーション名を設定できるようになりました。

ソースコード

django.apps.AppConfigクラスを継承して、アプリケーション設定のクラスを作成し、アプリケーション名を設定します。

作成したアプリケーション設定のクラスを、アプリケーションデフォルトにします。

試したバージョンはPython3.4, Django1.7です。

myapp/models.py

モデルはいつも通り。

from django.db import models


class Item(models.Model):
    name = models.CharField(max_length=50)
    price = models.PositiveIntegerField(default=0)
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        verbose_name = verbose_name_plural = "商品"
myapp/apps.py

Django1.7で追加されたAppConfigを使います。nameには他のアプリケーションと被らないようにアプリケーションの識別名を代入します。とりあえずはモジュール名で大丈夫です。

verbose_nameにアプリケーションの表示名を代入します。これが管理サイトで表示されます。

from django.apps import AppConfig


class MyAppConfig(AppConfig):
    name = 'myapp'
    verbose_name = "私のアプリケーション"
myapp/__init__.py

default_app_config変数文字列アプリケーション設定のクラスを指定します。

default_app_config = 'myapp.apps.MyAppConfig'

実行結果

「Myapp」の部分を「私のアプリケーション」という表示に変更できました。

f:id:nullpobug:20140922221156p:image

参考

Applications | Django documentation | Django

Django 1.7で追加されるAppConfigの紹介 - 偏った言語信者の垂れ流し

2014-08-31

[][]DjangoでDEBUG=Falseの際にSQLのログを出力する

Djangoクエリのログを出力したい場合、ロギングの設定でdjango.db.backendsのロガーを設定すればできます。

ただし、これはsettings.DEBUG=Trueのときにしか出力されないようになっています。

これはドキュメントにも書かれています。

ロギング — Django 1.4 documentation

Logging | Django documentation | Django

DEBUG=Falseの際でもSQLのログを記録したい場合があり、方法を調べてました。

試したのは、Python 2.7, Django 1.6.6

注意

Djangoデバッグ時にしかクエリログを出力しないようにしているのは、パフォーマンスに問題がある等の理由で意図的なものです。

この記事の方法でログを出力すると、パフォーマンスに問題が出る可能性があることに注意してください。

内部の動き

内部の仕組みとしては、django/db/__init__.pyのBaseDatabaseWrapperクラス、cursorメソッドでCursorクラスをデバッグ用と通常用を切り替えています。

    def cursor(self):
        """
        Creates a cursor, opening a connection if necessary.
        """
        self.validate_thread_sharing()
        if (self.use_debug_cursor or
            (self.use_debug_cursor is None and settings.DEBUG)):
            cursor = self.make_debug_cursor(self._cursor())
        else:
            cursor = util.CursorWrapper(self._cursor(), self)
        return cursor

self.use_debug_cursorの値がTrueであればデバッグ用のCursorクラスが使われるようです。

use_debug_cursorの値を変更するミドルウェアを作成する

connectionオブジェクトのuse_debug_cursorをTrueに設定するミドルウェアを作成します。

myproject/middleware.py
# coding: utf-8
class UseDebugCursorMiddleware(object):
    def process_request(self, request):
        # SQLのログを出力するようにデバッグ用のCursorクラスを使用
        from django.db import connection
        connection.use_debug_cursor = True

settings.pyでミドルウェアを使用する

作成したミドルウェアは、DB接続の前に実行されていないとダメなので、MIDDLEWARE_CLASSESの先頭に設定します。

myproject/settings.py

LOGGINGの設定は通常のクエリログを出力するためのものと同じです。

# 中略

DEBUG = False

# 中略

MIDDLEWARE_CLASSES = (
    'myproject.middleware.UseDebugCursorMiddleware',  # 一番最初にミドルウェアを適用します
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
)

# 中略

LOGGING = {
    'version': 1,
    'handlers': {
        'logfile': {
            'class': 'logging.handlers.RotatingFileHandler',
            'filename': os.path.join(BASE_DIR, 'query.log'),
        },
    },
    'loggers': {
        'django.db.backends': {
            'handlers': ['logfile'],
            'level': 'DEBUG',
        }
    },
}

これでDEBUG=Falseの場合でも、SQLのログをファイルに出力することができました。

2014-07-19

[]Nexus4のタッチスクリーンディスプレイを交換した

去年の秋ごろからNexus4を使っていますが、先日歩いているときに地面に落としてしまい、タッチパネルのガラスが割れてしまいました。

f:id:nullpobug:20140719150330j:image

サイドのボタンは動作して画面は表示されるのですが、タッチパネルはどこをタップしても完全に反応しない状態になってしまいました。

新品や中古が安いならそれを買えばいいかと思って調べましたが、値段が全然下がってなく高いままだったので、修理するほうが良い様子。

修理方法をウェブ検索で調べたところ、以下のページの見つけたので参考にさせて頂きました。

スマホ Nexus4 タッチパネル ディスプレイ の 交換修理|むるしすてむ

分解、パーツ交換は自己責任

交換用パーツの入手

交換用のパーツは国内ではやはり手に入らないようなので、eBayから購入して輸入する必要があります。各種手続きなど面倒なので、代行サービスを探して利用することにしました。

いくつか見てみたところ、eBayの商品の落札から国内発送まですべてやってくれるセカイモンというサービスがあったので、今回はこれを利用することにしました。

eBay公認日本語オークション セカイモン

「USA LCD Display Touch Screen Digitizer Glass Assembly For LG google nexus 4 E960」で検索すると該当のパーツが出てきます。45ドル程度。

セカイモン経由で購入して手数料、送料すべて込みで、7,717円で入手出来ました。

端末の分解とパーツ交換

分解とパーツ交換の作業については、参考にしたページで紹介されていた動画が参考になりました。

http://www.youtube.com/watch?v=ZrEEVqXg8G8

背面のカバーを外すために、星形(T5)の精密ドライバーが必要です。また、中のパーツなどを外すためには、プラスの精密ドライバーが必要です。

背面のカバーはツメの引っかかりを外すのに少し苦労。マイナスの精密ドライバ2本を使って何とか開けました。うまくやらないと側がボロボロになりますね。

f:id:nullpobug:20140719150331j:image

次にタッチスクリーンディスプレイですが、これは粘着剤(両面テープ?)のようなものでかなり強力にくっついてるので、無理やり剥がすしかなかったです。端の部分はガラスを細かく割りながらマイナスドライバで削り剥がしました。

交換作業で一番時間かかったのがこの工程で、端の取れにくい部分を除去するのに1時間程度かかってしまいました。

f:id:nullpobug:20140719150332j:image

f:id:nullpobug:20140719150333j:image

バラしたパーツとこれから取り付ける購入したパーツです。

f:id:nullpobug:20140719150334j:image

取り付けから蓋を閉じるまでの細かい作業も動画が参考になりました。

タッチパネルを固定するための両面テープは、幅が細く(5mm)て厚さが薄めのものをホームセンターで購入し、大きすぎる場合はハサミで切ってサイズを調整しました。

取り付けが完了した状態のもの。

f:id:nullpobug:20140719150335j:image

電源を入れて問題なく動くことを確認できました。

f:id:nullpobug:20140719150336j:image

作業開始から終了までだいたい3時間ぐらいでした。

2014-07-18

[]Djangoでprefetch_relatedを使ってクエリ数を減らす

prefetch_relatedはDjango 1.4で追加された機能です。

親子関係を表すモデル(多対多になってるものなど)をツリー状に表示する場合、ループ内でクエリを実行しってしまうと、クエリ数が多くて極端に遅くなります(特に2段目とか3段目)。

prefetch_relatedを使うと、事前にリレーション先のデータを取得しておき、ループ内で新たにクエリが実行されないようにできます。

試したバージョンは、Python2.7、Django1.6.5です。

ソースコード

完全なコードはbitbucketに置いてます。

tokibito / sample_nullpobug / source / django / market — Bitbucket

shop/models.py
# coding: utf-8
from django.db import models

class Category(models.Model):
    "カテゴリ"
    name = models.CharField(max_length=40)

    def __unicode__(self):
        return self.name

    class Meta:
        db_table = 'category'

class Item(models.Model):
    "商品"
    name = models.CharField(max_length=40)
    code = models.CharField(max_length=10, unique=True)
    price = models.IntegerField()
    category = models.ForeignKey('Category')

    def __unicode__(self):
        return self.name

    class Meta:
        db_table = 'item'

class Bundle(models.Model):
    "まとめ売り"
    name = models.CharField(max_length=40)
    price = models.IntegerField()
    items = models.ManyToManyField('Item', through='BundleItem')

    def __unicode__(self):
        return self.name

    class Meta:
        db_table = 'bundle'

class BundleItem(models.Model):
    "まとめ売り商品"
    bundle = models.ForeignKey('Bundle')
    item = models.ForeignKey('Item')

    class Meta:
        db_table = 'bundle_item'

django-extensionsのgraph_modelsコマンドで出力すると、こういう構造になっています。

f:id:nullpobug:20140718224950p:image

shop/templates/index.html

テンプレートファイルは、どちらのビュー関数でも同じものを使います。

<html>
<body>
<ul>
{% for bundle in bundles %}
  <li>{{ bundle.name }}
    <ul>
    {% for item in bundle.items.all %}
      <li>{{ item }} - {{ item.category }}</li>
    {% endfor %}
    </ul>
  </li>
{% endfor %}
</ul>
</body>
</html>

bundle、itemのところで2重のforループになっています。また2つ目のほうは、bundleからitemを、itemからcategoryを取得して使うようなテンプレートになっています。

shop/views.py

prefetch_relatedを使わない場合と使う場合のビュー関数をそれぞれ用意して、urls.pyに設定しておきます。

# coding: utf-8
from django.shortcuts import render
from shop.models import Category, Item, Bundle


def no_prefetch_view(request):
    # prefetch_relatedを使わない場合
    bundles = Bundle.objects.all()
    return render(request, 'index.html', {'bundles': bundles})


def prefetch_view(request):
    # prefetch_relatedを使う場合
    bundles = Bundle.objects.prefetch_related('items__category')
    return render(request, 'index.html', {'bundles': bundles})

prefetch_relatedを使う場合、今回はテンプレート中でbundle→item→categoryの順でツリー状に表示するため、「items__category」までをプリフェッチ対象に指定しています。

実行結果

URLアクセスすると、どちらも同じ表示になります。

f:id:nullpobug:20140718224953p:image

prefetch_relatedを使わない場合

debug-toolbarでSQLをみてみると、クエリ数は9回になっています。

テンプレート中の「bundle.items.all」の部分と、「item.category」の部分でクエリが実行されているためです。

f:id:nullpobug:20140718224951p:image

prefetch_relatedを使う場合

debug-toolbarでSQLをみてみると、クエリ数は4回になっています。

bundle_idをINで指定してitemテーブル、category_idをINで指定してcategoryテーブルのデータをまとめて取得しています。

f:id:nullpobug:20140718224952p:image

このようにprefetch_relatedを使うことで、いくらかクエリ数を減らせます。

参考