携帯固有IDでユーザ認証 「修正」
先日のBLOG( 携帯固有IDでユーザ認証 )にて,Djangoの認証をいじったのですが,perezvonさんのBLOGでより詳細に書かれているので記録!! とても参考になります. 「 django.contrib.authのImproperlyConfiguredCommentsAdd 」
nobu さんからも意見がありましたがーやっぱBackendは継承しないみたいですね. ということで修正.
週末
先週末は,なんのヤル気も出ずだらだらしてしまったので,今週はちょろちょろイジイジしてみた.
大して何か大きいコトをやったわけではなく, ここに Blogの全文検索の機能を追加してみたり,UpdatePing を投げる処理を追加してみたりと地味な感じです!!
また,別の部分でー携帯対応させなければいけなくてー「ん~どうやってやろうかなぁ~」と調べたりーポーっとしたり…. PCと携帯を同時に対応させるってーのは,面倒かなぁ~デフォルトの文字コードも気をつかわなきゃいけなさそうだし….相変わらず携帯ってーのは面倒だなぁ….
たいしたことは,せず一覧と投稿ができればよくー絵文字なんてーのは無視したってかまわん(とりあえず) ,しかも画面数は少ない!! だったらー無理矢理やっちゃおうかなぁー.携帯端末IDでログインできてーその後セッションが維持できればーいいので….
なぁ~んてコトやっていたら週末終っちゃったっ!!
markup@Django
nobu さんのBlog( Djangoで使ってる個人用markupを公開 )にて公開されたmarkupを利用させてもらった.
いやいや,自分もリンクを 新規ウィンドウ で開きたかったのでー使わせて頂いた☆ うん,いいね!! nobu さん THANX☆
Django FormModelにてトラブった
今日はDjango! ずっと古いリビジョンで動かしていたので,最新版のDjangoに耐えられるように修正. maxlengthをmax_lengthへ,escapeを削除,form_for_model/form_for_instanceからFormModelへ…
前者の2つは特に簡単なコトなんですが,FormModelでチト苦労した. というのも,BookmarkやBlogのタグ付け(ManyToManyField)を「del.icio.us っぽく」していた. 詳細は nobu さんの ManyToManyFieldをちょっとdel.icio.usっぽく を見てみて下さい. という訳で,自分のBookmarkは下記のような感じになっていた.(この部分は個人メモを兼ねているので飛ばしてもらってかまいません.)
#####
# project/bookmark/forms.py
#
class MultiTagInput(forms.TextInput):
def render(self, name, value, attrs=None):
if isinstance(value, QuerySet):
value = ' '.join([t.name for t in value])
return super(MultiTagInput, self).render(name, value, attrs)
class MultiTagField(forms.Field):
def __init__(self, **kwargs):
kwargs.update({
'widget' : MultiTagInput,
})
super(MultiTagField, self).__init__(**kwargs)
def clean(self, value):
super(MultiTagField, self).clean(value)
values = []
for name in value.replace('\u3000', ' ').split(' '):
if len(name):
tag, created = Label.objects.get_or_create(name=name)
values.append(tag.id)
if not len(values):
raise forms.ValidationError(_('This field is required.'))
return values
ENTRY_FORMFIELDS['labels'] = MultiTagField
def entry_form_callback(f, **kwargs):
try:
return ENTRY_FORMFIELDS[f.name](**kwargs)
except:
return f.formfield(**kwargs)
#####
# project/bookmark/views.pyの一部
#
def edit(request, id):
""" 更新処理 """
bookmark = get_object_or_404(Bookmark, pk=id)
f = forms.form_for_instance(bookmark, formfield_callback=entry_form_callback)
form = f(request.POST.copy() or None)
このforms.pyModelFormに対応するように,コールバック関数(entry_form_callback)の削除したり, 下記のようなModelFormを追記した.
class MultiTagInput(forms.TextInput):
def render(self, name, value, attrs=None):
if isinstance(value, QuerySet):
value = ' '.join([t.name for t in value])
return super(MultiTagInput, self).render(name, value, attrs)
class MultiTagField(forms.Field):
def clean(self, value):
super(MultiTagField, self).clean(value)
values = []
for name in value.replace('\u3000', ' ').split(' '):
if len(name):
tag, created = Label.objects.get_or_create(name=name)
values.append(tag.id)
if not len(values):
raise forms.ValidationError(_('This field is required.'))
return values
class LabelForm(forms.ModelForm):
""" Form for Bookmark Label """
class Meta:
model = Label
fields = ('name',)
exclude = ('created_at', 'updated_at')
class BookmarkForm(forms.ModelForm):
""" Form for Bookmark """
labels = MultiTagField(widget=MultiTagInput) # ここで上記のFieldを設定.
class Meta:
model = Bookmark
fields = ('title', 'url', 'comment', 'labels')
exclude = ('created_at', 'updated_at')
そして,views.pyでは,
def edit(request, id):
""" 更新処理 """
bookmark = get_object_or_404(Bookmark, pk=id)
form = BookmarkForm(request.POST.copy() or None, instance=bookmark)
てな感じに修正してうまくいくと思ったのですが….だめだったぁ〜.新規作成は成功なのですが,更新しようとするとタグフィールドにタグ名(label.name)ではなくIDになってしまった. ということで,コードを追いかけてみました.
今まで使っていたform_for_instanceは下記の部分でManyToManyにうまく対応してやっているように見える.
# site-packages/django/newforms/models.py
def form_for_instance(instance, form=BaseForm, fields=None,
formfield_callback=lambda f, **kwargs: f.formfield(**kwargs)):
warn("form_for_instance is deprecated. Use ModelForm instead.",
PendingDeprecationWarning, stacklevel=3)
model = instance.__class__
opts = model._meta
field_list = []
for f in opts.fields + opts.many_to_many:
if not f.editable:
continue
if fields and not f.name in fields:
continue
current_value = f.value_from_object(instance) # <= フィールドにでる値
formfield = formfield_callback(f, initial=current_value)
if formfield:
field_list.append((f.name, formfield))
base_fields = SortedDict(field_list)
return type(opts.object_name + 'InstanceForm', (form,),
{'base_fields': base_fields, '_model': model,
'save': make_instance_save(instance, fields, 'changed')})
けどもFormModel部分では,
# site-packages/django/newforms/models.py
class BaseModelForm(BaseForm):
def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None,
initial=None, error_class=ErrorList, label_suffix=':',
instance=None):
opts = self._meta
if instance is None:
# if we didn't get an instance, instantiate a new one
self.instance = opts.model()
object_data = {}
else:
self.instance = instance
object_data = model_to_dict(instance, opts.fields, opts.exclude) # <= 自分の希望通りの動きをしてくれてないような感じ….
# if initial was provided, it should override the values from instance
if initial is not None:
object_data.update(initial) # <= updateしてる.
BaseForm.__init__(self, data, files, auto_id, prefix, object_data, error_class, label_suffix)
ん〜とコードを眺めていると「initial」を渡してあげればーupdateしてるのでー views.py を下記のように変更して,とりあえず,目的は達成!
def edit(request, id):
""" 更新処理 """
bookmark = get_object_or_404(Bookmark, pk=id)
# タグフィールドに表示したいものをinitialで渡してあげる.
form = BookmarkForm(request.POST.copy() or None, instance=bookmark, initial={'labels' : bookmark.labels.all()})
もっとうまい方法があるのかなぁ〜.このままだとーあとでコード見たときに何しているかわからないよね? 多くの部分を省いて説明しているので,わけのわからない内容になってしまったかも….
しっかし,久しぶりにDjango触れてー楽しかった☆