2017-02-13 26 views
0

Когда я показываю деньги в шаблоне списка или подробно (только для чтения), я хотел бы иметь возможность отображать симпатичную версию поля, которая включает в себя символ валюты: «100,00 долларов США»Как представить денежное поле Django с символом валюты в шаблоне списка и простой десятичной для редактирования?

Однако, когда запись редактируется, я бы хотел отобразить «100.00» в поле TextInput без символа валюты.

Я создал пользовательские модели класса DecimalField и forms.DecimalField для представления денег в приложении Django.

Итак, я пытаюсь найти альтернативную версию значения поля в хорошем шаблоне (то есть правильно отформатирован для просмотра, но не идеально подходит для редактирования). Я знаю, что есть фильтры шаблонов, которые позволяют вам это сделать, но я считаю, что это помешало бы мне перебирать поля в форме и отображать их значения.

Если я могу добавить симпатичный атрибут в свой собственный класс полей, я могу проверить, существует ли он в шаблоне и отображать его. До сих пор я попытался это:

class MoneyFormField(forms.DecimalField): 
    def __init__(self, *args, **kwargs): 
     # I plan to add symbol localization code here 
     self.symbol= '$' 

    def prepare_value(self, value): 
     # assign pretty value to an attribute that template can access 
     self.pretty = self.pretty_value(value)    
     try: 
      return round(Decimal(value),2) 
     except: 
      return 0 

    def pretty_value(self, value): 
     if not value: 
      value = 0 
     return self.symbol + str(round(Decimal(value),2)) 

Проблема заключается в том, что для того, чтобы получить доступ к довольно значение в шаблоне, у меня есть доступ к первоначальной стоимости первой так что prepare_value() называется.

Если я пытаюсь напечатать довольно значение в шаблоне, как это ...

{% for field in payment_form %} 
    {{ field.field.pretty }} {{ field.value }} {{ field.field.pretty }} 
{% endfor %} 

тогда первый довольно игнорируется, но последние довольно отпечатки.

Если я могу получить эту работу, то я бы показывать симпатичное значение (или значение по умолчанию, если довольно не существует) в шаблоне так:

{% if field.field.pretty %} 
    {{ field.field.pretty}} 
{% else %} 
    {{ field.value }} 
{% endif %} 

Кто-нибудь есть какие-либо предложения для изготовления альтернативное представление поля, доступного шаблону?

TL; DR- Как получить доступ к значению поля в поле формы init?

ответ

0

Я придумал решение, но поскольку я новичок в Django и python, я мог бы сделать вещи излишне сложными. Поэтому я хотел бы услышать любую обратную связь!

Подводя итоги: я хотел, чтобы мои денежные поля имели «симпатичную» версию, которая может отображать деньги как «100,00 долларов США» вместо «100,00» в определенных шаблонах, таких как списки и данные только для чтения.

Я создал поле денег модели, которая определяет мои пользовательские поля формы, MoneyFormField:

class MoneyField(models.DecimalField): 
    def __init__(self, *args, **kwargs): 
     kwargs['max_digits'] = 13 
     kwargs['decimal_places'] = 4 
     kwargs['default'] = 0 

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

Вот моя форма MoneyFormField поле.Обратите внимание на вызов «get_bound_field»:

class MoneyFormField(forms.DecimalField): 
    def __init__(self, *args, **kwargs): 
     self.widget = MoneyTextInput() # custom widget I'm experimenting with 
     self.prefix = '$'    
     super(MoneyFormField, self).__init__(*args, **kwargs) 

    def get_bound_field(self, form, field_name): 
     return MoneyBoundField(form, self, field_name)   

    def prepare_value(self, value): 
     try: 
      return round(Decimal(value),2) 
     except: 
      return 0 

MoneyBoundField является то, что делает «довольно» версию поля доступны для шаблона:

class MoneyBoundField(BoundField): 
    def pretty(self): 
     return self.field.prefix+str(self.value()) 

Если я только что сделал это, то я мог бы напечатать довольно значения по первой проверки, если существует довольно значение, и если нет, то печать исходного значения, как это:

{% for somefield in payment_form %} 
    {% if somefield.pretty %} 
     {{ somefield.pretty }} 
    {% else %} 
     {{ somefield.value }} 
    {% endif %}  
{% endfor %} 

Но я предпочел бы просто сделать что-то вроде этого:

{% for somefield in payment_form %} 
    {{ somefield.pretty }} 
{% endfor %} 

Так что мне пришлось добавить довольно основному классу Django BoundField в boundfields.py, добавив две строки:

boundfield.py 
class BoundField(object): 
... 
    def pretty(self): 
     # return default value. Let descendant classes override this function where desired 
     return self.value() 
0

Вот еще один подход, который я взял. Вместо того, чтобы возиться с основным определением класса django BoundField в файле boundfield.py, теперь я просто использую фильтр шаблонов, чтобы сделать поле красивым. Фильтр выполняет следующие действия:

  • Если поле является полем выбора, он преобразует значение индекса выбора в строку описания
  • Если поле имеет пользовательское поле формы, с помощью пользовательского BoundField, с функцией «pretty» он вызывает эту функцию и возвращает значение.
  • (прокомментировано), вы можете попытаться вызвать конкретный метод в своем настраиваемом классе полей формы, если это применимо. Это устраняет необходимость определить BoundField в своем классе
  • поле формы
  • Если они не применяются он просто возвращает значение поля неизмененной

Это код в моем app_filters.py:

from django.forms.fields import ChoiceField 

@register.filter 
def pretty_filter(field): 
    # is this a better way to get the field's value? 
    # field_value = field.form.initial[field.name] 

    # get the field's value (for choice fields, this is the integer index used to look up the verbose string in the choices dict) 
    field_value = field.value() 
    if field_value is None: 
     return '' 
    # the the field has 'choices' then return the verbose string for the choice 
    if isinstance(field.field, ChoiceField): 
     for (choices_index, description) in field.field.choices: 
      if choices_index == field_value: 
       return description 
     return '' # no match found 

    # # if your model.field's formfield has a function called 
    # # another_custom_function() you can call it this way: 
    # try: 
    #  return field.field.another_custom_function() 
    # except: 
    #  pass 

    # attempt to return pretty value if field has th 
    try: 
     return field.pretty() 
    except: 
    # else return default value 
     return field_value 

Я также внес изменения в симпатичной функции моего заказного денежного поля так, чтобы он добавляет запятую (это может быть изменено, чтобы справиться с локализацией):

class MoneyBoundField(BoundField):  
    def pretty(self): 
     # return $12,345.67 
     return "{}{:,.2f}".format(self.field.prefix,self.value()) 

class MoneyFormField(forms.DecimalField): 
    def __init__(self, *args, **kwargs): 
     self.widget = MoneyTextInput() 
     self.prefix = '$' 
     super(MoneyFormField, self).__init__(*args, **kwargs) 

    def get_bound_field(self, form, field_name): 
     return MoneyBoundField(form, self, field_name)  

Тогда в моем шаблоне я это следующим образом:

{% load app_filters %} 

{% for item in payment_form %} 
    {{item|pretty_filter}} 
{% endfor %}     

Большая часть кода фильтра копируется из пользователя Simple10 здесь: https://code.djangoproject.com/ticket/10427#comment:18

Пожалуйста, поделитесь какие-либо мысли или комментарии!