ManyToManyFieldをちょっとdel.icio.usっぽく
某 endless 氏と、
「 Django の ManyToManyField を del.icio.us っぽくしたいね。」
という話になり色々と試行錯誤してみたよ。
そのまま as_text とかやると、期待した通りに動かないため、ソースと睨めっこしながら一応形になった。
なので、とりあえずメモ。
models.py はこんな感じ。
# -*- coding: utf-8 -*-
from datetime import datetime
from django.db import models
class Tag(models.Model):
"""
ブックマークのタグ。
"""
label = models.SlugField(_('Label'), maxlength=50, default=None)
class Meta:
pass
class Admin:
pass
def __str__(self):
return self.label
def get_absolute_url(self):
"""
インスタンスに対してのユニークなURLを返す。
"""
return '/bookmark/tag/%s/' % self.label
class Entry(models.Model):
"""
ブックマーク。
"""
title = models.CharField(_('Title'), maxlength=100, default=None)
url = models.URLField(_('Url'), default=None)
description = models.TextField(_('Description'), default=None)
created_at = models.DateTimeField(_('Created at'), editable=False, default=datetime.now)
updated_at = models.DateTimeField(_('Updated at'), editable=False)
is_active = models.BooleanField(_('Is Active'), editable=False, default=True)
tags = models.ManyToManyField(Tag)
class Meta:
pass
class Admin:
list_display = ('title', 'url', 'created_at', 'updated_at', 'is_active')
def __str__(self):
return self.title
def get_absolute_url(self):
"""
インスタンスに対してのユニークなURLを返す。
"""
return self.url
def save(self):
"""
データを登録する。
"""
self.updated_at = datetime.now()
super(Entry, self).save()
def delete(self):
"""
論理削除の為のオーバーライド。
"""
# Turn off Activation flag.
self.is_active = False
self.save()
で、同階層に作った forms.py がコレ。
# -*- coding: utf-8 -*-
from django.db.models.query import QuerySet
from django import newforms as forms
from tested.bookmark.models import Tag
EMPTY_VALUES = (None, '',)
ENTRY_FORMFIELDS = {}
class MultiTagInput(forms.TextInput):
"""
ManyToMany2Charなウィジェット。
"""
def render(self, name, value, attrs=None):
if isinstance(value, QuerySet):
value = ' '.join([t.label for t in value])
return super(MultiTagInput, self).render(name, value, attrs)
class MultiTagField(forms.Field):
"""
ManyToMany2Charなフィールド。逆もしかり。
"""
def __init__(self, **kwargs):
kwargs.update({
'widget' : MultiTagInput(),
})
super(MultiTagField, self).__init__(**kwargs)
def clean(self, value):
super(MultiTagField, self).clean(value)
values = []
for label in value.replace('\xe3\x80\x80', ' ').split(' '):
if len(label):
tag, created = Tag.objects.get_or_create(label=label)
values.append(tag.id)
if not len(values):
raise forms.ValidationError(_('This field is required.'))
return values
ENTRY_FORMFIELDS['tags'] = MultiTagField
def entry_form_callback(f, **kwargs):
"""
bookmark.Entry用のformfield_callback.
"""
try:
# セットされてればそれを使う。
return ENTRY_FORMFIELDS[f.name](**kwargs)
except:
# 無ければデフォルト。
return f.formfield(**kwargs)
これで views.py とかで、
f = newforms.form_for_model(Entry, formfield_callback=entry_form_callback)
とかすると、テンプレートでは input@type=text になっております。果たしてコレで合ってるのかは解りませんが。
手練の方からの突っ込みをお待ちしております!
- Posted at:
- 2007/08/03 02:22:55
- 0 Comments
- 0 TrackBacks
- Trackback:
- http://humming.via-kitchen.com/2007/08/03/manytomanyfield-2-delicious/trackback/
TrackBacks
まだ登録されていません。
Comments
まだ登録されていません。