3月 18
例えば
class Person(models.Model):
name = models.CharField(max_length=100)
nickname= models.CharField(max_length=100)
みたいなモデルがあって、「名前とニックネームがおんなじ人を抽出したい」っていうケースがあるとします。
_person = Person.objects.filter(name=nickname)
はNGですね、エラーがでます。「nicknameは宣言されてません」となります。そこで、
from django.db.models import F
_person = Person.objects.filter(name=F(‘nickname’))
と書きます。フィールドを値として展開してくれるみたいですね。site-packages\django\db\models\expressions.pyにソースもあるので、きちんと調べればいい感じに使えそうです。
Python2.5、Django1.1.1でのお話でした。
3月 17
普通に
manage.py runserver
すると127.0.0.1:8000で起動しますので、開発用サーバは他のPCから参照できません。「ちょっとこの画面見て欲しいな」とかの時には席まで来てもらう必要があります。
まぁそんなに広いオフィスでもなければ別に問題ないのでしょうが、いちいち面倒なんですよね。
manage.py runserver 192.168.0.1:8000(開発用マシンのIPが192.168.0.1の場合)
で開発用サーバを起動すると、他のPCから「http://192.168.0.1:8000」で参照できます。
検証用サーバとか別に用意してあるんですけど、わざわざデプロイするほどでもない時ってありますよね。そういう時にちょっと便利です。
3月 08
vpopmailを使ってqmailでバーチャルドメイン運用している場合、困った問題がひとつあります。vpopmailがCRAM-MD5に未対応なんですね。
まぁMTAとして運用するにはたいして問題ないんですが、Djangoでメール送信しようとすると大問題、DjangoはSMTP認証のときにパスワードをMD5で暗号化してqmailに送っているようです。よって、qmailから「SMTP認証にコケました。」と叱られてしまうわけです。
ので、PLAINでSMTP認証をする方法です。
PythonインストールディレクトリのLibフォルダに「smtplib.py」があるはずです。その562行目付近、
preferred_auths = [AUTH_CRAM_MD5, AUTH_PLAIN, AUTH_LOGIN]
を
preferred_auths = [AUTH_PLAIN, AUTH_LOGIN,AUTH_CRAM_MD5]
に変更します。認証の優先順位ですね。優先順位を入れ替えているだけなのでCRAM_MD5が使えなくなるわけでもなく、vpopmailの困った仕様にも対応可能です。
MTA変えただけでメールが送信できなくなり、しかもMUAからは無事に送信で来ちゃっていたのでまったくわからず、一晩悩みました。
2月 25
たいていのアプリにバッチは付き物なのですが、DjangoにはRailsでいうところのscript/runnerがありません。
まぁPythonでバッチ書いてそれを叩けばいいのですが、settingsの値とか、モデルデータとか、やっぱり共有したいわけですよ。
# -*- coding: utf-8 -*-
import sys
import os
sys.path.append(“C:/works/Python”)
os.environ['DJANGO_SETTINGS_MODULE'] = ‘hogepj.settings’
from hogepj.app.models import *
_hoge = Hoge.objects.all()
for item in _hoge:
print item.name
sys.path.appendに書くのはプロジェクトがあるフォルダです。プロジェクトフォルダは含みません。Pythonというフォルダのなかにhogepjというプロジェクトフォルダがある、という前提です。
Railsだと「Railsアプリのバッチを実行する」な感じだったのに対して、Djangoだと「バッチをDjangoアプリの一部として実行する」って感じでしょうか。
環境はPython2.5、Django1.1.1です。
2月 06
例えば会員登録とかでパスワードを確認のために2回入力してもらうときとか、両方の値があっているかチェックする必要があります。
Djangoの標準バリデーションだとそこまではやってくれないんですね。
でも、バリデーションのカスタマイズはとっても簡単です。簡単なハズなのに、とってもてこずりました。w
# -*- coding: utf-8 -*-
from django import forms
class RegistForm(forms.Form):
name = forms.CharField(max_length=100)
mailadd = forms.EmailField(max_length=100)
passwd = forms.CharField(min_length=6, max_length=12, widget=forms.PasswordInput(render_value=False))
passwd_confirm = forms.CharField(min_length=6, max_length=12, widget=forms.PasswordInput(render_value=False))
def clean_passwd_confirm(self):
_pswd = self.cleaned_data['passwd']
_pswd_confirm = self.cleaned_data['passwd_confirm']
if _pswd!=_pswd_confirm:
raise forms.ValidationError(u’確認用パスワードが異なります。’)
else:
return _pswd_confirm
clean_フィールド名のメソッドが、対象フィールドのバリデーション用メソッドです。self.cleand_dataで値にアクセス、検証してNGならraiseする。OKなら値をそのまま返す。
これだけ!w
1月 19
例えばリストをループで複数行書き出す時とかは、奇数行と偶数行で背景の色を分けたかったりします。でも、Django標準だとそんなことできないっぽいんですよね。
ので、カスタムフィルタを使って実装してみました。
- アプリケーションディレクトリ(models.pyとかviews.pyが置いてあるトコ)に「templatetags」というフォルダを作成。
- そのフォルダの中に「__init__.py」と「hoge.py」を作成。「__init__.py」は白紙。
- 「hoge.py」に以下を記述
from django import template
register = template.Library()
@register.filter(name=’getOddEven’)
def getOddEven(_val):
if _val % 2==0:
return ‘even’
else:
return ‘odd’
- テンプレートファイル側に{% load hoge %}と記述。
- テンプレートのループの中で「{{ forloop.counter|getOddEven }}」と記述すると「odd/even」の文字列が返ってくる。
フィルタの使い方としては、「値|フィルタ」といういつもの書き方とおんなじです。
「forloop.counter」というのはテンプレート内でfor文を使ったときに内部で持っている値です。サンプルを見るとわかりやすいかな。
{% for item in list %}
{{ forloop.counter }},
{% endfor %}
これで、1,2,3,,,,と表示されます。1から始まる序数ですね。「django/template/defaulttags.py」を見ていただくと、他にもいろいろな値を持っています。これは便利。
で、あとはその序数をカスタムフィルタに渡してあげればOKということです。
{% load hoge %}
{% for item in list %}
<p class=”{{ forloop.counter| getOddEven}}”>{{ item }}</p>
{% endfor %}
恐るべしDjango、使いこなすまでの道のりは長い。。。
1月 12
Webアプリケーションにとって、ファイルのダウンロードはたいていのケースで要求される機能ではないでしょうか。ハセテツもいろいろなプロジェクト、言語をこなしてきましたが、すべての状況で要求されてきたと思います。
で、Python/Djangoの例です。
def download_file(request):
from django.http import *
response = HttpResponse(open(‘/path/to/downloadfile’,'rb’).read(), mimetype=’ダウンロードさせるファイルのMIME type’)
response['Content-Disposition'] = ‘filename=クライアントに表示させるファイル名’
return response
これだけです。
まぁファイルサイズを追記すべきというのは至極ごもっともで、必要に応じて「Content-length」や「Content-type」を追加していただければと思います。
11月 20
RubyonRailsでいうところの「public」に相当するフォルダがないので、どこに配置したらいいものかとものすごい悩んだんです。
で、urls.pyに以下を追記
(r’^common/(?P<path>.*)$’, ‘django.views.static.serve’, {‘document_root’: ‘/path/to/common’}),
上記の例だと、/path/to/commonの中にbase.cssっていう静的ファイルを置いておくとhttp://127.0.0.1:8000/common/base.cssというURLでCSSにアクセスできます。
まぁ静的ファイルはアプリケーション内には配置しない、というのが正解なんでしょうけどね。