ラベル Django の投稿を表示しています。 すべての投稿を表示
ラベル Django の投稿を表示しています。 すべての投稿を表示

2012年6月9日土曜日

DjangoのURL namespacesのところを和訳した


https://docs.djangoproject.com/en/dev/topics/http/urls/#url-namespaces
何回流し読みしてもよく分からないので、和訳した。

URL namespaces
URL ネームスペース

Namespaced URLs are specified using the : operator. For example, the main index page of the admin application is referenced using admin:index. This indicates a namespace of admin, and a named URL of index.

ネームスペースに関連付けられたURLは、:演算子を使い表現されます。例えば、adminアプリケーションのメイントップページは admin:index で参照されます。これはadminネームスペースのindexと名付けられたURLを示します。

Namespaces can also be nested. The named URL foo:bar:whiz would look for a pattern named whiz in the namespace bar that is itself defined within the top-level namespace foo.

ネームスペースは入れ子にできます。 foo:bar:whiz というURL名は、それ自身がfooというトップレベルのネームスペース内に定義されているbarというネームスペース内のwhizと名付けられたパターンを指します。

When given a namespaced URL (e.g. myapp:index) to resolve, Django splits the fully qualified name into parts, and then tries the following lookup:

与えられたネームスペースに関連付けられたURL(例…myapp:index)を解読する場合、Djangoは完全記述された名称を要素単位に分割し、以下の検索を試みます。

1. First, Django looks for a matching application namespace (in this example, myapp). This will yield a list of instances of that application.

まず、Djangoは一致するアプリケーションネームスペースを探します(この例の場合myapp)。該当するインスタンスのリストが抽出されます。

2. If there is a current application defined, Django finds and returns the URL resolver for that instance. The current application can be specified as an attribute on the template context - applications that expect to have multiple deployments should set the current_app attribute on any Context or RequestContext that is used to render a template.

もしカレントアプリケーションが定義されていれば、Djangoはそのインスタンスに対するURLリゾルバを探して返します。カレントアプリケーションはテンプレートコンテキストの属性として特定されます。複数デプロイされる事が想定されているアプリケーションは、テンプレートをレンダリングする時に使われるContextおよびRequestContextにcurrent_app属性がセットされるべきです。

3. The current application can also be specified manually as an argument to the reverse() function.

カレントアプリケーションはreverse()関数の引数として明示的に指定も出来ます。

4. If there is no current application. Django looks for a default application instance. The default application instance is the instance that has an instance namespace matching the application namespace (in this example, an instance of the myapp called myapp).

もしカレントアプリケーションが指定されない場合、Djangoはデフォルトアプリケーションインスタンスを探します。デフォルトアプリケーションインスタンスとは、アプリケーションネームスペースと一致するインスタンスネームスペースを持つインスタンスです(この例の場合myapp、と呼ばれているmyappのインスタンス(訳注:namespace="myapp",app_name="myapp"という事ですかね))

5. If there is no default application instance, Django will pick the last deployed instance of the application, whatever its instance name may be.

もしデフォルトアプリケーションインスタンスが無い場合、Djangoは最後にデプロイされたアプリケーションのインスタンスを取り上げます。そのインスタンス名(訳注:インスタンスネームスペース名?)が何であれ。

If the provided namespace doesn't match an application namespace in step 1, Django will attempt a direct lookup of the namespace as an instance namespace.

もし与えられたネームスペースがステップ1のアプリケーションネームスペースにマッチしない場合、Djangoはインスタンスネームスペースであるとして直接検索を試みます。

If there are nested namespaces, these steps are repeated for each part of the namespace until only the view name is unresolved. The view name will then be resolved into a URL in the namespace that has been found.

もしネームスペースが入れ子になっている場合、ビュー名が解決されるまでネームスペースの各要素ごとにこれらのステップが繰り返されます。ビュー名は見つかったネームスペース内のURLとして解決されます(訳注:ここ適当。ここに限らないけど)。

To show this resolution strategy in action, consider an example of two instances of myapp: one called foo, and one called bar. myapp has a main index page with a URL named index. Using this setup, the following lookups are possible:

この解決手順を順を追ってお見せするため、例として2つのmyappのインスタンスを考えます。片方はfoo、もう片方はbarです。myappのトップページのURLにはindexという名前がついています。この設定に基づき、以下の検索が可能です。

・If one of the instances is current - say, if we were rendering a utility page in the instance bar - myapp:index will resolve to the index page of the instance bar.

もしどちらかのインスタンスがカレントならば…すなわち、barインスタンスのユーティリティページをレンダリングしていた場合、myapp:indexはbarインスタンスのトップページとして解決されます。

・If there is no current instance - say, if we were rendering a page somewhere else on the site - myapp:index will resolve to the last registered instance of myapp. Since there is no default instance, the last instance of myapp that is registered will be used. This could be foo or bar, depending on the order they are introduced into the urlpatterns of the project.

もしカレントインスタンスが無い場合…すなわちサイト内の何か別なページをレンダリングしていた場合…myapp:indexはmyappのうち最後に登録されたインスタンスに対して解決されます。デフォルトインスタンスが無いので、登録されたmyappの内最後のインスタンスが使われます。fooでもbarでも、プロジェクトのurlpatternsに登録された順に依存します。

・foo:index will always resolve to the index page of the instance foo.

foo:index は常にfooインスタンスのトップページとして解決されます。

If there was also a default instance - i.e., an instance named myapp - the following would happen:

もしデフォルトインスタンスもあった(インスタンス名がmyappとなっていた)場合、以下のようになります。

・If one of the instances is current - say, if we were rendering a utility page in the instance bar - myapp:index will resolve to the index page of the instance bar.

もしどちらかのインスタンスがカレントならば…すなわち、barインスタンスのユーティリティページをレンダリングしていた場合、myapp:indexはbarインスタンスのトップページとして解決されます。

・If there is no current instance - say, if we were rendering a page somewhere else on the site - myapp:index will resolve to the index page of the default instance.

もしカレントインスタンスが無い場合…すなわちサイト内の何か別なページをレンダリングしていた場合…myapp:indexは、デフォルトインスタンスのトップページとして解決されます。

・foo:index will again resolve to the index page of the instance foo.

foo:index はこの場合もfooインスタンスのトップページとして解決されます。

和訳したけど正直なところイマイチピンとこない。
とりあえずインスタンスネームスペースの方がアプリケーションネームスペースより粒度が小さい…という解釈でいいのだろうか。

2012年4月6日金曜日

Django+MySQL+Cast as SIGNED INTEGERでTruncated incorrect INTEGER valueでUnicodeEncodeErrorなところから逃げ延びる

Django+MySQLで、unicodeの全角文字と数字が混じった列のdistinctな一覧を
【数字の昇順】→「文字順」で取得したい。
単純に文字順にしてしまうのは 1,10,11,2,3,4 になるのでだめなパターン。

QuerySet APIの distinct はPostgreSQLでしかサポートされていないので、
DBのViewを書いた。

create view app_view1 as
select distinct col1,
    case when length(col1) = 0 then 0
                when cast(col1 as UNSIGNED INTEGER) > 0 then cast(col1 as UNSIGNED INTEGER)
                else 2147483647 end as sort
from table1

ちなみに本題とはあまり関係ないけどModelはこんな感じ。
class View1(models.Model):
    col1 = models.CharField(max_length=10,blank=True,primary_key=True)
    sort = models.IntegerField()
    class Meta:
        app_label="app"
        ordering=["sort","col1"]
        managed=False
文字はsortを十分に大きくしておいた上でsort昇順→col1昇順にすればいいはず。

MySQL Workbenchからだとゴキゲンに動作する。

実際に実行する。タイトルのような文字列を叫んで憤死する。

原因としては、実際にはMySQL内で実行した際にcastで「Truncated incorrect INTEGER value:'【文字列】'」というwarningが出ており、
それをMySQLdbモジュールが拾おうとしてしまって、【文字列】部分がUnicodeになっているせいでUnicodeEncodeErrorになるという
余計な事すんなよというもの。

何とかする方法を考える。
・MySQLdbをいじる(UnicodeEncodeErrorを吐かないようにする)→できればやりたくない
・Djangoをいじる(warningを拾わないようにする)→できればやりたくない
・継承で何とかする→djangoのdb backendを作れば何とか出来るんだろうができればやりたくない
・MySQLでWarningを出さないようにできないか→MySQL Suppress Warningとかでググる。死屍累々。
・あきらめてPython上で並べ替えをする→今回はいいがこんな感じので大量のデータに対してやろうとしたらどうするよ

SQLに立ち戻る。
要は数字だけ以外の場合に、CASTさえしなければよい。

MySQLにはREGEXPがあった。
create view app_view1 as
select distinct col1,
    case when length(col1) = 0 then 0
                when col1 REGEXP '^[[:digit:]]+$' then cast(col1 as UNSIGNED INTEGER)
                else 2147483647 end as sort
from table1

何とか逃げ延びた。

2012年2月12日日曜日

djangoのmodels.pyの分割

models.pyを分割してみた。

こんな感じのdjangoアプリがあるとして
+ [app]
    + models.py
    + views.py
    + その他
models.pyの中にはモデルクラスAaaとかBbbとかがあるとする。

こんな感じにしてみた。
+ [app]
    + [models]
        + __init__.py
        + Aaa.py
        + Bbb.py
    + views.py
    + その他

Aaa.py は普通にこんな感じに書くだろうとして、
# -*- coding: UTF-8 -*- 
from django.db import models

class Aaa(models.Model):
    name = models.CharField(max_length=50)

    class Meta(object):
        app_label = 'app'

__init__.pyはこう書けばこれはこれでいいっぽいんだけど
from Aaa import *
from Bbb import *

思いつきの開発中にモデルを色々こねくり回す事を考えると
ソースファイル作ったり消したりした後に
いちいち__init__.pyを直すのも面倒だなーと思い、
何とかならないか色々試行錯誤した挙句…。
__scope = locals()

def __modelLoader():
    import inspect
    import os
    curdir = os.path.dirname(__file__)
    for file in os.listdir(curdir):
        root,ext = os.path.splitext(file)
        if root[0] not in ['_','.'] and ext == ".py":
            obj = __import__(root,globals(),locals())
            for att in dir(obj):
                if att[0] not in ['_']:
                    attobj = getattr(obj,att)
                    if inspect.isclass(attobj):
                        __scope[attobj.__name__] = attobj

__modelLoader()
del __scope

とてもとてもうさんくさい。
配列外のlocals()の戻り配列に追加とか、アリなのか?

とりあえず、動いてはいるっぽい。
新しくCcc.pyを書き足してmanage.py syncdbすると新しくテーブルも作られた。

どう考えても、modelが固まったら普通にimportの列挙に替えるべき…。

2012年1月7日土曜日

Djangoで起動時にCoffeeScriptとLessのコンパイルをする

書いてみた。

どう書くのが作法的に良いのかはよく分かっていないが
Djangoのアプリケーションディレクトリの__init__.pyに書いて
それなりに動いたのでよしとする。

.coffeeと.lessは、アプリケーションディレクトリ以下 static/js および static/css にあるとする。

# myapp/__init__.py
import os
import os.path as path
import glob

staticpath = path.join("myapp","static")

def buildCoffee():
    curpath = path.abspath(os.curdir)
    dirpath = path.join(staticpath,"js")
    os.chdir(dirpath)
    for cfile in glob.glob("*.coffee"):
        cmtime = os.stat(cfile).st_mtime
        jsname = path.splitext(cfile)[0] + ".js"
        jmtime = os.stat(jsname).st_mtime if path.isfile(jsname) else 0
        if jmtime < cmtime:
            os.system("coffee -bc " + cfile)
            print ("compiled: " + cfile)
        else:
            print ("skipped: " + cfile)
    os.chdir(curpath)

def buildLess():
    curpath = path.abspath(os.curdir)
    dirpath = path.join(staticpath,"css")
    os.chdir(dirpath)
    for lfile in glob.glob("*.less"):
        lmtime = os.stat(lfile).st_mtime
        cssname = path.splitext(lfile)[0] + ".css"
        cmtime = os.stat(cssname).st_mtime if path.isfile(cssname) else 0
        if cmtime < lmtime:
            os.system("lessc " + lfile + " > " + cssname)
            print ("compiled: " + lfile)
        else:
            print ("skipped: " + lfile)
    os.chdir(curpath)
   
buildCoffee()
buildLess()
一応.coffeeおよび.lessファイルと、コンパイル済みの.jsと.cssの更新日付を見て
更新されてる時だけ再コンパイルするようにしてる。

2011年11月7日月曜日

DjangoのModelFormにidを追加する

普通にModelからModelForm作ってas_pとかしてもidは含まれない。
でもちょっとした理由によりModelFormにまとめて扱いたかったので
何とかしてみた。

Modelがこんな感じだとして
class Person(models.Model):
    name = models.CharField("名前",max_length=50)
    birthday = models.DateField("誕生日")
ModelFormには「id」って名前でフィールドを追加すればいいっぽい。
class PersonForm (forms.ModelForm):
    id = forms.DecimalField()

    class Meta:
        model = Person
        fields = ('name','birthday','id')
しばらく「pk」でやってて詰まってた。