2009-06-03 7 views
0

Je garde imdb_id sur le terrain pour les modèles Film dans mon db:Widget de formulaire pour les entrées de texte avec lien externe voulu!

class Movie(models.Model): 
    imdb_id = models.IntegerField('imdb ID', blank=True, null=True, unique=True) 

    def _get_imdb_url(self): 
     return self.imdb_id and 'http://www.imdb.com/title/tt%s/' % str(self.imdb_id).zfill(7) or '' 

    def _set_imdb_url(self, imdb_url): 
     self.imdb_id = int(re.compile(r'[^\d]').sub('', imdb_url)) 

    imdb_url = property(_get_imdb_url, _set_imdb_url) 

Et je veux faire un widget spécial pour afficher le lien externe pour imdb.com sous la forme d'administration à la saisie de texte pour le champ « imdb_id ». Je pense qu'il peut s'agir d'un widget global pour tout champ de formulaire avec lien externe, généré en utilisant un masque spécial (dans mon cas, ce masque est 'http://www.imdb.com/title/tt%s/'). Je sais comment écrire un widget, mais je ne sais pas comment pousser mon masque, défini dans mon modèle Movie, à ce widget. Je ne veux pas violer le principe DRY et définir ce masque à deux endroits différents. Et aussi ce sera un bon outil dans le même but avec d'autres liens externes à l'avenir.

Que pensez-vous de ce widget? Comment est-il possible de le réaliser? Peut-être que quelqu'un l'a écrit avant moi?

Merci!

Répondre

0

Alors, je décidé de ne pas attendre l'aide et écrit ce widget:

import re 
from django import forms 
class LinkFieldWidget(Widget): 
    ''' 
    A TextField widget with previewing link, generated from field's value with special url mask 
    ''' 
    def __init__(self, text, url='%s', *args, **kwargs): 
     self.url = url 
     self.text = text 
     if not re.search('%', self.url): 
      raise forms.ValidationError, u'Invalid URL mask' 
     super(LinkFieldWidget, self).__init__(*args, **kwargs) 

    def render(self, name, value, attrs=None): 
     output = [] 
     output.append('''<input type="text" name="%s" value="%s" onkeyup="$('a#%s-link').attr('href', '%s'.replace('%s', this.value)).css({'display': (this.value ? 'inline' : 'none')})" />''' % (name, value or '', name, self.url, '%s')) 
     if self.url and self.text: 
      output.append('<span><a href="%s" id="%s-link" target="blank" style="display: %s;">%s</a></span>' % (value and self.url % value or '#', name, value and 'inline' or 'none', self.text)) 

     return mark_safe(u' '.join(output)) 

Exemple d'utilisation dans admin:

from utils.widgets import LinkFieldWidget 
class MovieAdminForm(forms.ModelForm): 
    def __init__(self, *args, **kwargs): 
     super(MovieAdminForm, self).__init__(*args, **kwargs) 
     self.fields['imdb_id'].widget = LinkFieldWidget(text='imdb', url=self.instance.imdb_link) 

class MovieAdmin(admin.ModelAdmin): 
    form = MovieAdminForm 

Modèle:

class Movie(models.Model): 
    .....  
    imdb_link = 'http://www.imdb.com/title/tt%s/' 
    def _get_imdb_url(self): 
     return self.imdb_id and self.imdb_link % str(self.imdb_id).zfill(7) or '' 
    def _set_imdb_url(self, imdb_url): 
     self.imdb_id = int(re.compile(r'[^\d]').sub('', imdb_url)) 
    imdb_url = property(_get_imdb_url, _set_imdb_url) 
Questions connexes