Django 自定义字段:仅对数据库中的值运行 to_python() ?
如何确保仅当从数据库加载字段中的数据时才调用自定义字段的 *to_python()* 方法?
我正在尝试使用自定义字段来处理 Base64单个模型属性的编码/解码。一切似乎都正常工作,直到我实例化模型的新实例并使用其明文值设置此属性...此时,Django 尝试解码该字段但失败,因为它是明文。
自定义字段实现的吸引力在于,我认为我可以处理 100% 的编码/解码逻辑,因此我的代码的其他部分不需要了解它。我做错了什么?
(注意:这只是一个说明我的问题的示例,我不需要关于应该或不应该如何使用 Base64 编码的建议)
def encode(value):
return base64.b64encode(value)
def decode(value):
return base64.b64decode(value)
class EncodedField(models.CharField):
__metaclass__ = models.SubfieldBase
def __init__(self, max_length, *args, **kwargs):
super(EncodedField, self).__init__(*args, **kwargs)
def get_prep_value(self, value):
return encode(value)
def to_python(self, value):
return decode(value)
class Person(models.Model):
internal_id = EncodedField(max_length=32)
...当我在交互式外壳。为什么在这里调用 to_python() ?
>>> from myapp.models import *
>>> Person(internal_id="foo")
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/usr/local/lib/python2.6/dist-packages/django/db/models/base.py", line 330, in __init__
setattr(self, field.attname, val)
File "/usr/local/lib/python2.6/dist-packages/django/db/models/fields/subclassing.py", line 98, in __set__
obj.__dict__[self.field.name] = self.field.to_python(value)
File "../myapp/models.py", line 87, in to_python
return decode(value)
File "../myapp/models.py", line 74, in decode
return base64.b64decode(value)
File "/usr/lib/python2.6/base64.py", line 76, in b64decode
raise TypeError(msg)
TypeError: Incorrect padding
我原以为我能够做这样的事情...
>>> from myapp.models import *
>>> obj = Person(internal_id="foo")
>>> obj.internal_id
'foo'
>>> obj.save()
>>> newObj = Person.objects.get(internal_id="foo")
>>> newObj.internal_id
'foo'
>>> newObj.internal_id = "bar"
>>> newObj.internal_id
'bar'
>>> newObj.save()
...我做错了什么?
How can I ensure that my custom field's *to_python()* method is only called when the data in the field has been loaded from the DB?
I'm trying to use a Custom Field to handle the Base64 Encoding/Decoding of a single model property. Everything appeared to be working correctly until I instantiated a new instance of the model and set this property with its plaintext value...at that point, Django tried to decode the field but failed because it was plaintext.
The allure of the Custom Field implementation was that I thought I could handle 100% of the encoding/decoding logic there, so that no other part of my code ever needed to know about it. What am I doing wrong?
(NOTE: This is just an example to illustrate my problem, I don't need advice on how I should or should not be using Base64 Encoding)
def encode(value):
return base64.b64encode(value)
def decode(value):
return base64.b64decode(value)
class EncodedField(models.CharField):
__metaclass__ = models.SubfieldBase
def __init__(self, max_length, *args, **kwargs):
super(EncodedField, self).__init__(*args, **kwargs)
def get_prep_value(self, value):
return encode(value)
def to_python(self, value):
return decode(value)
class Person(models.Model):
internal_id = EncodedField(max_length=32)
...and it breaks when I do this in the interactive shell. Why is it calling to_python() here?
>>> from myapp.models import *
>>> Person(internal_id="foo")
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/usr/local/lib/python2.6/dist-packages/django/db/models/base.py", line 330, in __init__
setattr(self, field.attname, val)
File "/usr/local/lib/python2.6/dist-packages/django/db/models/fields/subclassing.py", line 98, in __set__
obj.__dict__[self.field.name] = self.field.to_python(value)
File "../myapp/models.py", line 87, in to_python
return decode(value)
File "../myapp/models.py", line 74, in decode
return base64.b64decode(value)
File "/usr/lib/python2.6/base64.py", line 76, in b64decode
raise TypeError(msg)
TypeError: Incorrect padding
I had expected I would be able to do something like this...
>>> from myapp.models import *
>>> obj = Person(internal_id="foo")
>>> obj.internal_id
'foo'
>>> obj.save()
>>> newObj = Person.objects.get(internal_id="foo")
>>> newObj.internal_id
'foo'
>>> newObj.internal_id = "bar"
>>> newObj.internal_id
'bar'
>>> newObj.save()
...what am I doing wrong?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
(来自 http://davidcramer.posterous.com/代码/181/custom-fields-in-django.html
和 https:// /docs.djangoproject.com/en/dev/howto/custom-model-fields/#converting-database-values-to-python-objects)
看来你需要能够测试如果它是一个实例,问题是它们是相同的类型(字符串与 b64 编码的字符串)。所以除非你能确定差异,否则我建议确保你总是:
或
或一些这样的编码。
编辑:-我正在查看https://github.com/django-extensions/django-extensions/blob/f278a9d91501933c7d51dffc2ec30341a1872a18/django_extensions/db/fields/encrypted.py并认为你可以做类似的事情。
(from http://davidcramer.posterous.com/code/181/custom-fields-in-django.html
and https://docs.djangoproject.com/en/dev/howto/custom-model-fields/#converting-database-values-to-python-objects)
It seems that you need to be able to test if it is an instance and the problem with that is they are the same type (string vs b64 encoded string).So unless you can detirmine the difference I would suggest making sure you always:
or
or some such encoding.
EDIT:- i was looking at https://github.com/django-extensions/django-extensions/blob/f278a9d91501933c7d51dffc2ec30341a1872a18/django_extensions/db/fields/encrypted.py and thought you could do something similar.
我有完全相同的问题,但是使用 JSON 数据。我想将数据以JSON格式存储在数据库中。但是,如果您尝试存储已序列化的 JSON 对象,它将以反序列化方式返回。所以问题是,进来的并不总是出来的。特别是如果您尝试将数字存储为字符串,它将作为 int 或 float 返回,因为它在存储之前由 to_python 反序列化。
解决方案很简单,但不太优雅。只需确保将数据的“类型”与数据一起存储,在我的例子中,它是 JSON 数据,所以我用“json:”作为前缀,因此您始终知道数据是否来自数据库。
话虽这么说,但令人烦恼的是,您不能期望一致的行为,或者您无法判断 to_python 是对用户设置的值还是对数据库中的值进行操作。
I have the exact same problem, but with JSON data. I want to store data in the database in JSON format. However if you try to store an already serialized JSON object, it will be returned deserialized. So the issue is that what comes in, is not always what comes out. Especially if you try to store a number as a string, it will be returned as an int or float, since it is deserialized by to_python before being stored.
The solution is simple, albeit not too elegant. Simply make sure to store the "type" of data along with the data, in my case, it is JSON data, so I prefix it with "json:", and thus you always know if the data is coming from the database.
That being said, it's annoying that you can't expect consistent behavior, or that you can't tell whether to_python is operating on a user set value or a value from the DB.
当您第一次为字段分配值时,是否只会收到
TypeError
?您可以在它周围写一个 try/ except :这不是最干净的解决方案,但您可以尝试一下,看看它是否可以让您按照您期望的方式处理该字段。
Do you only get the
TypeError
when you first assign a value to the field? You could just write a try/except around it:It's not the cleanest solution, but you could try that and see if it lets you work with the field the way you're expecting to.