coddingtonbear/django-measurement

Form fields are using wrong default unit

Closed this issue · 6 comments

This may be related to #30 but I'm not sure. That issue said it was related to the inclusion of Bootstrap 3. I was using Bootstrap 4 and having the same issue. I decided to make a barebones version of a form without any bootstrapping or additional funny stuff and I have the same problem. My quick and dirty code is available here: https://github.com/MidasJade/beer_sample. It's probably something stupid I'm doing but I cannot figure it out.

For the quantity field in my form, no matter what type I use when I create it, it displays ounces in my list view and detail view, but displays grams in the update view. Based on this from the docs "Note that although the original unit specified is stored for display, that the unit is abstracted to the measure’s standard unit for storage and comparison" I'm assuming whatever was used to create it or update it should be what is displayed, right?

Hi @MidasJade,

thanks for reaching out. Let me try to explain. This library does not store any information about what unit you initially put in. It translates whatever the users inputs into a SI standard unit and stores the data.

When the data is displayed, as it is in the update view, it uses the default SI unit. In the case of weight this unit is gram.

I hope that answer explains the behavior of the package a bit more.

Best
-Joe

Hi @codingjoe,

Thanks for the explanation. I misread that in the docs. I guess that leaves me with a couple more questions, but don't want to take up too much of your time.

  1. If it saves it in the SI unit, why was my list view showing it in ounces when update view was showing it in grams?
  2. It sounds like I won't be able to use built-in Django forms or crispy forms (crispy is what I'm trying to use right now) because there doesn't appear to be a way to programatically influence the measurement type that gets displayed?

Thanks for the help!

  1. If it saves it in the SI unit, why was my list view showing it in ounces when update view was showing it in grams?

Once the value in received from the database, it is converted into a measurement – a separate data type that is aware of its unit. So if you display the field value in a list view, it will be displaying that data type. If you don't specify it any other way, it should use Measure.__str__, which should give you grams not ounces. Seealso: https://github.com/coddingtonbear/python-measurement/blob/3efdc3e4304939a73fc55494dcaac9f539a55753/measurement/base.py#L203-L207

In any case, you can also call the unit attribute to get the value in the desired unit, eg:

<p>{{ object.my_field.g }}g</p>
  1. It sounds like I won't be able to use built-in Django forms or crispy forms (crispy is what I'm trying to use right now) because there doesn't appear to be a way to programatically influence the measurement type that gets displayed?

Why not? I have a big project running on crispy forms and this package.

I guess I shouldn't say I can't use it with crispy, I just can't use it with the quick FormHelper and Layout method.
My Form:

class FermentableForm(ModelForm):
class Meta:
model = Fermentable
exclude = ()

name = forms.CharField(widget=forms.TextInput(attrs={'placeholder': 'Fermentable name'}))
description = forms.CharField(widget=forms.Textarea(attrs={'placeholder': 'Description of the fermentable', 'rows':2 }))
color = forms.DecimalField(widget=forms.TextInput(attrs={'placeholder': 'Lovibond color value'}))
extract = forms.DecimalField(widget=forms.TextInput(attrs={'placeholder': 'Extract % (ie: .75)'}))
moisture = forms.DecimalField(widget=forms.TextInput(attrs={'placeholder': 'Moisture % (ie: .075)'}))
mash_required = forms.BooleanField(widget=forms.CheckboxInput())
quantity = MeasurementField(measurement=Weight, unit_choices=(("oz", "oz"), ("lb", "lb"), ("g", "g"), ("kg", "kg")))

def __init__(self, *args, **kwargs):
    super().__init__(*args, **kwargs)
    self.helper = FormHelper()
    self.helper.layout = Layout(
        'name',
        'description',
        'color',
        'extract',
        'moisture',
        'mash_required',
        'quantity',
        Submit('submit', 'Save')
    )

And my template:

{% extends "base_generic.html" %}
{% load crispy_forms_tags %}

{% block content %}
{% crispy form %}
{% endblock %}

@MidasJade what's the result? Mind adding a screenshot?

@codingjoe

I figured it out. You can't see my imports in what I pasted, but I had imported MeasurementField from models instead of forms. It renders properly and gives you all the unit_choices you specified for the model. If I import the correct module and use the MeasurementField class from forms, then I can limit the unit_choices to just what I want to see (lbs). Then it displays correctly. Thanks again for the help! Great app!