简体   繁体   中英

Django FloatField and DecimalField creation return different than object in database

I've just realise that in Django2, the object at the creation (using xxx.objects.create or xxx.save) return an object that is a little bit different than the object which is really in database (MODEL.objects.get( the object created )). You can see it using DecimalField or FloatField:

class Product(Model):
     price = FloatField()

then running the shell (python manage.py shell):

from *project*.models import Product
a = Product.objects.create(price=30)
# or "a = Product(price=30); a.save()"
b = Product.objects.get(price=30)
a == b  # True
str(a.price) == str(b.price)  # False : "30" == "30.0"

Is this a bug from django ? Why django does not return the same object ?

Because when you create an object using the xxx.objects.create method, you expect it to return the same object (at least the same copy) than what you get when you search this object in the database. I found the source code of the create method:

def create(self, **kwargs):
    """
    Creates a new object with the given kwargs, saving it to the database
    and returning the created object.
    """
    obj = self.model(**kwargs)
    self._for_write = True
    obj.save(force_insert=True, using=self.db)
    return obj

Many thanks !

EDIT: my question is: why both objects are differents ? Why when I create the object, django does not return the object with a float but one with a int ?

EDIT: Thanks @Willem Van Onsem

if you create an object, you assign the attributes the object you pass to them (here 30). Whereas if you fetch data, the fields will read the result of the database response, and interpret it (float30)

But I still think it is better if at creation, Django return the "interpret data". EDIT: I'm thinking I'm wrong: it would be too magic, and python does not like "magic".

Is this a bug from django? Why django does not return the same object?

No . This is not a bug. If you .create(..) an object, you first construct a Model object, and then call .save() . But that thus means that the fields take the value you give them. 30 is by default an int , so that means that if you query for type(a.price) , you get:

>>> type(a.price)
<class 'int'>

If you query the database, for example with Model.objects.get(price=30) , you however construct a query, for example here the query will look like:

SELECT *
FROM project_price
WHERE price = 30

The database will respond by a sequence of records. These records are interpreted by the Django ORM, and the different fields will construct Python counterparts. For a FloatField will thus convert the "string" that contains the response of the database to a float through the to_python method [GitHub] .

Now in Python a float and int are two different types, but that does not mean that two such objects can not be equivalent, for example:

>>> float(30) == int(30)
True

But if we convert these to strings, then these both yield different strings:

>>> str(int(30))
'30'
>>> str(float(30))
'30.0'

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM