2009-12-18 3 views
0

Une occurrence commune que j'ai avec un projet particulier est qu'il nécessite l'utilisateur d'entrer des dimensions (pour la largeur/profondeur/hauteur) en pieds et pouces. Les calculs doivent être effectués sur cette dimension, donc j'ai travaillé sur un type de champ personnalisé qui prend une dimension en pieds/pouces (par exemple 1'-10 ") et l'enregistre dans la base de données en tant que nombre décimal en utilisant une expression rationnelle pour analyser l'entrée Le champ affiche à tout moment l'utilisateur en pieds-pouces (avec l'objectif final d'écrire une méthode pour pouvoir afficher en métrique, et interagir avec measure.py, et geodjango Ce que j'ai jusqu'ici n'est certainement pas DRY, mais à part ça, j'ai des problèmes avec la validation au niveau du formulaire.Le champ de modèle personnalisé lui-même fonctionne correctement (d'après ce que j'ai vu), et j'ai écrit une méthode de nettoyage de champ de formulaire qui devrait fonctionner pour valider le champ Ma question est de savoir comment accrocher ce champ de forme dans mon formulaire de modèle pour travailler pour tous les champs de largeur/profondeur/taille Je pense peut-être une dérogation de la init sur le modelform (a la self.fields ['depth'] ...), mais je ne suis pas tout à fait sûr où aller d'ici ...Champ de modèle personnalisé Django avec la validation ... comment le relier à ModelForm

DCML_PATTERN = re.compile(r'^(?P<feet>\d+)(?P<dec_inch>\.?\d*)\'?$') 
FTIN_PATTERN = re.compile(r'^(?P<feet>\d+)\'?\s*-?\s*(?P<inch>[0-9]|10|11)?\"?$') 

class FtInField(models.Field): 
     __metaclass__ = models.SubfieldBase 

     empty_strings_allowed = False 

     def db_type(self): 
       return 'double' 

     def get_internal_type(self): 
       return "FtInField" 

     def to_python(self,value): 
       if value is u'' or value is None: 
         return None 
       if isinstance(value, float): 
         m = FTDCML_PATTERN.match(str(value)) 
         if m is None: 
           raise Exception('Must be an integer or decimal number') 
         feet = int(m.group('feet')) 
         dec_inch = float(m.group('dec_inch') or 0) 
         inch = dec_inch * 12 
         return "%d\'-%.0f\"" % (feet,inch) 
       return value 

     def get_db_prep_value(self,value): 
       if value is u'' or value is None: 
         return None 
       m = FTIN_PATTERN.match(value) 
       if m is None: 
         raise Exception('Must be in X\'-Y" Format') 
       feet = int(m.group('feet')) 
       inch = int(m.group('inch') or 0) 
       return (feet + (inch/float(12))) 

class FtInField(forms.Field): 
     def clean(self,value): 
       super(FtInField, self).clean(value) 
       if value is u'' or value is None: 
         raise forms.ValidationError('Enter a dimension in X\'-Y" format') 
       m = FTIN_PATTERN.match(value) 
       if m is None: 
         raise forms.ValidationError('Must be in X\'-Y" Format') 
       feet = int(m.group('feet')) 
       inch = int(m.group('inch') or 0) 
       value = '%d\'-%.0f"' % (feet,inch) 
       return value 

class ProductClass(models.Model): 
     productname = models.CharField('Product Name', max_length=60,blank=True) 
     depth = FtInField('Depth (Feet/Inches)') 
     width = FtInField('Width (Feet/Inches)') 
     height = FtInField('Height (Feet/Inches)') 

class ProductClassForm(forms.ModelForm): 
     depth = FtInField() 
     width = FtInField() 
     height = FtInField() 

     class Meta: 
       model = ProductClass 

class ProductClassAdmin(admin.ModelAdmin): 
     form = ProductClassForm 
+0

Pourquoi les deux classes de champ ont-elles le même nom? –

Répondre

0

Afin d'éviter les doubles emplois, vous devriez probablement mettre en œuvre une classe de type de données qui gère l'analyse syntaxique des pieds et pouces pour vous, il devrait simplifier grandement l'autre code.

Ensuite, vous devez créer un champ de modèle et un champ de formulaire, en gardant à l'esprit qu'il s'agit de deux composants COMPLETEMENT SÉPARÉS. (que vous avez plus ou moins déjà fait, mais c'est juste pour l'exhaustivité)

Maintenant, si je lis bien la question, vous voulez définir le champ de formulaire par défaut pour votre champ de modèle. Pour faciliter cela, vous voulez implémenter la fonction formfield() sur votre classe de champ de modèle. Ref: the django docs

2

Merci, merci à vous deux. C'est ce que j'ai trouvé (basé sur vos deux conseils). Je vais travailler sur la définition d'un type de données pour le rendre meilleur en termes de répétition, mais en attendant, cela fonctionne ... (J'étais si proche, pourtant si loin ...) Vous êtes géniaux. Merci.

DCML_PATTERN = re.compile(r'^(?P<feet>\d+)(?P<dec_inch>\.?\d*)\'?$') 
FTIN_PATTERN = re.compile(r'^(?P<feet>\d+)\'?\s*-?\s*(?P<inch>[0-9]|10|11)?\"?$') 

class FtInFormField(forms.Field): 
     def clean(self,value): 
       super(FtInFormField, self).clean(value) 
       if value is u'' or value is None: 
         raise forms.ValidationError('Enter a dimension in X\'-Y" format') 
       m = FTIN_PATTERN.match(value) 
       if m is None: 
         raise forms.ValidationError('Must be in X\'-Y" Format') 
       feet = int(m.group('feet')) 
       inch = int(m.group('inch') or 0) 
       value = '%d\'-%.0f"' % (feet,inch) 
       return value 

class FtInField(models.Field): 
     __metaclass__ = models.SubfieldBase 

     empty_strings_allowed = False 

     def db_type(self): 
       return 'double' 

     def get_internal_type(self): 
       return "FtInField" 

     def to_python(self,value): 
       if value is u'' or value is None: 
         return None 
       if isinstance(value, float): 
         m = FTDCML_PATTERN.match(str(value)) 
         if m is None: 
           raise Exception('Must be an integer or decimal number') 
         feet = int(m.group('feet')) 
         dec_inch = float(m.group('dec_inch') or 0) 
         inch = dec_inch * 12 
         return "%d\'-%.0f\"" % (feet,inch) 
       return value 

     def get_db_prep_value(self,value): 
       if value is u'' or value is None: 
         return None 
       m = FTIN_PATTERN.match(value) 
       if m is None: 
         raise Exception('Must be in X\'-Y" Format') 
       feet = int(m.group('feet')) 
       inch = int(m.group('inch') or 0) 
       return (feet + (inch/float(12))) 

     def formfield(self, **kwargs): 
       defaults = {'form_class': FtInFormField} 
       defaults.update(kwargs) 
       return super(FtInField,self).formfield(**defaults) 

class ProductClass(models.Model): 
     productname = models.CharField('Product Name', max_length=60,blank=True) 
     depth = FtInField('Depth (Feet/Inches)') 
     width = FtInField('Width (Feet/Inches)') 
     height = FtInField('Height (Feet/Inches)') 

class ProductClassForm(forms.ModelForm): 

     class Meta: 
       model = ProductClass 

class ProductClassAdmin(admin.ModelAdmin): 
     form = ProductClassForm 
Questions connexes