2017-11-04 9 views
0

ではありません、私はJSONFieldsで特定のオブジェクトを格納することで、JSON APIをバックアップ非正規化私のジャンゴPostgresデータベースにしようとしている:Djangoの管理:オブジェクトはカスタムフィールドにJSONシリアライズ可能なエラーサブクラス化JSONField

https://docs.djangoproject.com/en/1.11/ref/contrib/postgres/fields/#jsonfield

django.contrib.postgres.fields.JSONFieldフィールドを拡張して、データをPythonオブジェクトに自動的にシリアル化しました。私はオブジェクトの周りに自分のロジックをカプセル化し、JSONFieldに格納されているオブジェクトの構造を強制するためにこれをやっています。 、私はカスタムJSONFieldで私のオブジェクトを格納することができるよとネイティブのPythonオブジェクトとしてそれらを取得することができ

https://docs.djangoproject.com/en/1.11/howto/custom-model-fields/

しかし、私が壊れている:私はここのカスタムモデルフィールド上のDjangoのドキュメントを、次のよ管理コンソール。私は私のオブジェクトの1つを表示しようとすると、私はこのエラーを取得:

TypeError: <core.fields.PostalAddress object at 0x7fdcfaade4e0> is not JSON serializable 

私は問題は組み込みのjson.dumps機能はランダムなオブジェクトとうまく再生されないということであると仮定し、私はその存在を願ってPostalAddressクラスでオーバーライドして、うまくプレイできるメソッドです。

これは私のコードですが、アドレスの単純なケースですが、このパターンをより複雑で便利なカスタムJSONFieldユースケースに適用したいので、シリアル化されたJSONを管理コンソールに表示したいテキストを編集して保存することができます。

fields.py

from django.contrib.postgres.fields import JSONField 

class PostalAddress(object): 
    def __init__(self, street='', city='', state='', postal_code=''): 
     self.street = street 
     self.city = city 
     self.state = state 
     self.postal_code = postal_code 

def deserialize_address(address_dict): 
    return PostalAddress(**address_dict) 

def get_empty_address(): 
    return PostalAddress() 

class PostalAddressField(JSONField): 
    description = "A postal address" 

    def __init__(self, *args, **kwargs): 
     super(PostalAddressField, self).__init__(*args, **kwargs) 

    def get_prep_value(self, value): 
     if value is None: 
      return value 
     if isinstance(value, PostalAddress): 
      return json.dumps(value.__dict__) 
     return value 

    def from_db_value(self, value, expression, connection, context): 
     if value is None: 
      return value 
     return deserialize_address(value) 

    def to_python(self, value): 
     if isinstance(value, PostalAddress): 
      return value 
     if value is None: 
      return value 
     return deserialize_address(value) 

models.py

from django.db import models 
from .fields import PostalAddressField, get_empty_address 

class Person(models.Model): 
    shipping_address = PostalAddressField(default = get_empty_address) 

完全なトレース:

Request Method: GET 
Request URL:... 

Django Version: 1.11.6 
Python Version: 3.5.2 
Installed Applications: 
['grappelli', 
'django.contrib.admin', 
'django.contrib.auth', 
'django.contrib.contenttypes', 
'django.contrib.sessions', 
'django.contrib.messages', 
'django.contrib.staticfiles', 
'django.contrib.postgres', 
'rest_framework', 
'rest_framework.authtoken',... 
] 
Installed Middleware: 
['django.middleware.security.SecurityMiddleware', 
'django.contrib.sessions.middleware.SessionMiddleware', 
'django.middleware.common.CommonMiddleware', 
'django.middleware.csrf.CsrfViewMiddleware', 
'django.contrib.auth.middleware.AuthenticationMiddleware', 
'django.contrib.messages.middleware.MessageMiddleware', 
'django.middleware.clickjacking.XFrameOptionsMiddleware'] 


Template error: 
In template /home/ubuntu/venv/lib/python3.5/site-packages/grappelli/templates/admin/includes/fieldset.html, error at line 24 
    <core.fields.PostalAddress object at 0x7f2c7fc085f8> is not JSON serializable 14 :       {% if field.is_checkbox %} 
    15 :        <div class="c-1">&nbsp;</div> 
    16 :        <div class="c-2"> 
    17 :         {{ field.field }}{{ field.label_tag|prettylabel }} 
    18 :       {% else %} 
    19 :        <div class="c-1">{{ field.label_tag|prettylabel }}</div> 
    20 :        <div class="c-2"> 
    21 :         {% if field.is_readonly %} 
    22 :          <div class="grp-readonly">{{ field.contents }}</div> 
    23 :         {% else %} 
    24 :          {{ field.field }} 
    25 :         {% endif %} 
    26 :       {% endif %} 
    27 :        {% if line.fields|length_is:'1' %}{{ line.errors }}{% endif %} 
    28 :        {% if not line.fields|length_is:'1' and not field.is_readonly %}{{ field.field.errors }}{% endif %} 
    29 :        {% if field.field.help_text %} 
    30 :         <p class="grp-help">{{ field.field.help_text|safe }}</p> 
    31 :        {% endif %} 
    32 :       </div> 
    33 :      </div> 
    34 :     {% endfor %} 


Traceback: 

File "/home/ubuntu/venv/lib/python3.5/site-packages/django/core/handlers/exception.py" in inner 
    41.    response = get_response(request) 

File "/home/ubuntu/venv/lib/python3.5/site-packages/django/core/handlers/base.py" in _get_response 
    217.     response = self.process_exception_by_middleware(e, request) 

File "/home/ubuntu/venv/lib/python3.5/site-packages/django/core/handlers/base.py" in _get_response 
    215.     response = response.render() 

File "/home/ubuntu/venv/lib/python3.5/site-packages/django/template/response.py" in render 
    107.    self.content = self.rendered_content 

File "/home/ubuntu/venv/lib/python3.5/site-packages/django/template/response.py" in rendered_content 
    84.   content = template.render(context, self._request) 

File "/home/ubuntu/venv/lib/python3.5/site-packages/django/template/backends/django.py" in render 
    66.    return self.template.render(context) 

File "/home/ubuntu/venv/lib/python3.5/site-packages/django/template/base.py" in render 
    207.      return self._render(context) 

File "/home/ubuntu/venv/lib/python3.5/site-packages/django/template/base.py" in _render 
    199.   return self.nodelist.render(context) 

File "/home/ubuntu/venv/lib/python3.5/site-packages/django/template/base.py" in render 
    990.     bit = node.render_annotated(context) 

File "/home/ubuntu/venv/lib/python3.5/site-packages/django/template/base.py" in render_annotated 
    957.    return self.render(context) 

File "/home/ubuntu/venv/lib/python3.5/site-packages/django/template/loader_tags.py" in render 
    177.    return compiled_parent._render(context) 

File "/home/ubuntu/venv/lib/python3.5/site-packages/django/template/base.py" in _render 
    199.   return self.nodelist.render(context) 

File "/home/ubuntu/venv/lib/python3.5/site-packages/django/template/base.py" in render 
    990.     bit = node.render_annotated(context) 

File "/home/ubuntu/venv/lib/python3.5/site-packages/django/template/base.py" in render_annotated 
    957.    return self.render(context) 

File "/home/ubuntu/venv/lib/python3.5/site-packages/django/template/loader_tags.py" in render 
    177.    return compiled_parent._render(context) 

File "/home/ubuntu/venv/lib/python3.5/site-packages/django/template/base.py" in _render 
    199.   return self.nodelist.render(context) 

File "/home/ubuntu/venv/lib/python3.5/site-packages/django/template/base.py" in render 
    990.     bit = node.render_annotated(context) 

File "/home/ubuntu/venv/lib/python3.5/site-packages/django/template/base.py" in render_annotated 
    957.    return self.render(context) 

File "/home/ubuntu/venv/lib/python3.5/site-packages/django/template/loader_tags.py" in render 
    72.     result = block.nodelist.render(context) 

File "/home/ubuntu/venv/lib/python3.5/site-packages/django/template/base.py" in render 
    990.     bit = node.render_annotated(context) 

File "/home/ubuntu/venv/lib/python3.5/site-packages/django/template/base.py" in render_annotated 
    957.    return self.render(context) 

File "/home/ubuntu/venv/lib/python3.5/site-packages/django/template/loader_tags.py" in render 
    72.     result = block.nodelist.render(context) 

File "/home/ubuntu/venv/lib/python3.5/site-packages/django/template/base.py" in render 
    990.     bit = node.render_annotated(context) 

File "/home/ubuntu/venv/lib/python3.5/site-packages/django/template/base.py" in render_annotated 
    957.    return self.render(context) 

File "/home/ubuntu/venv/lib/python3.5/site-packages/django/template/defaulttags.py" in render 
    216.      nodelist.append(node.render_annotated(context)) 

File "/home/ubuntu/venv/lib/python3.5/site-packages/django/template/base.py" in render_annotated 
    957.    return self.render(context) 

File "/home/ubuntu/venv/lib/python3.5/site-packages/django/template/loader_tags.py" in render 
    216.     return template.render(context) 

File "/home/ubuntu/venv/lib/python3.5/site-packages/django/template/base.py" in render 
    209.     return self._render(context) 

File "/home/ubuntu/venv/lib/python3.5/site-packages/django/template/base.py" in _render 
    199.   return self.nodelist.render(context) 

File "/home/ubuntu/venv/lib/python3.5/site-packages/django/template/base.py" in render 
    990.     bit = node.render_annotated(context) 

File "/home/ubuntu/venv/lib/python3.5/site-packages/django/template/base.py" in render_annotated 
    957.    return self.render(context) 

File "/home/ubuntu/venv/lib/python3.5/site-packages/django/template/defaulttags.py" in render 
    411.   return strip_spaces_between_tags(self.nodelist.render(context).strip()) 

File "/home/ubuntu/venv/lib/python3.5/site-packages/django/template/base.py" in render 
    990.     bit = node.render_annotated(context) 

File "/home/ubuntu/venv/lib/python3.5/site-packages/django/template/base.py" in render_annotated 
    957.    return self.render(context) 

File "/home/ubuntu/venv/lib/python3.5/site-packages/django/template/defaulttags.py" in render 
    216.      nodelist.append(node.render_annotated(context)) 

File "/home/ubuntu/venv/lib/python3.5/site-packages/django/template/base.py" in render_annotated 
    957.    return self.render(context) 

File "/home/ubuntu/venv/lib/python3.5/site-packages/django/template/defaulttags.py" in render 
    216.      nodelist.append(node.render_annotated(context)) 

File "/home/ubuntu/venv/lib/python3.5/site-packages/django/template/base.py" in render_annotated 
    957.    return self.render(context) 

File "/home/ubuntu/venv/lib/python3.5/site-packages/django/template/defaulttags.py" in render 
    322.     return nodelist.render(context) 

File "/home/ubuntu/venv/lib/python3.5/site-packages/django/template/base.py" in render 
    990.     bit = node.render_annotated(context) 

File "/home/ubuntu/venv/lib/python3.5/site-packages/django/template/base.py" in render_annotated 
    957.    return self.render(context) 

File "/home/ubuntu/venv/lib/python3.5/site-packages/django/template/defaulttags.py" in render 
    322.     return nodelist.render(context) 

File "/home/ubuntu/venv/lib/python3.5/site-packages/django/template/base.py" in render 
    990.     bit = node.render_annotated(context) 

File "/home/ubuntu/venv/lib/python3.5/site-packages/django/template/base.py" in render_annotated 
    957.    return self.render(context) 

File "/home/ubuntu/venv/lib/python3.5/site-packages/django/template/base.py" in render 
    1046.   return render_value_in_context(output, context) 

File "/home/ubuntu/venv/lib/python3.5/site-packages/django/template/base.py" in render_value_in_context 
    1024.  value = force_text(value) 

File "/home/ubuntu/venv/lib/python3.5/site-packages/django/utils/encoding.py" in force_text 
    76.      s = six.text_type(s) 

File "/home/ubuntu/venv/lib/python3.5/site-packages/django/utils/html.py" in <lambda> 
    385.   klass.__str__ = lambda self: mark_safe(klass_str(self)) 

File "/home/ubuntu/venv/lib/python3.5/site-packages/django/forms/boundfield.py" in __str__ 
    40.    return self.as_widget() + self.as_hidden(only_initial=True) 

File "/home/ubuntu/venv/lib/python3.5/site-packages/django/forms/boundfield.py" in as_widget 
    125.    value=self.value(), 

File "/home/ubuntu/venv/lib/python3.5/site-packages/django/forms/boundfield.py" in value 
    162.   return self.field.prepare_value(data) 

File "/home/ubuntu/venv/lib/python3.5/site-packages/django/contrib/postgres/forms/jsonb.py" in prepare_value 
    55.   return json.dumps(value) 

File "/usr/lib/python3.5/json/__init__.py" in dumps 
    230.   return _default_encoder.encode(obj) 

File "/usr/lib/python3.5/json/encoder.py" in encode 
    198.   chunks = self.iterencode(o, _one_shot=True) 

File "/usr/lib/python3.5/json/encoder.py" in iterencode 
    256.   return _iterencode(o, 0) 

File "/usr/lib/python3.5/json/encoder.py" in default 
    179.   raise TypeError(repr(o) + " is not JSON serializable") 

Exception Type: TypeError at /admin/... 
Exception Value: <core.fields.PostalAddress object at 0x7f2c7fc085f8> is not JSON serializable 
+0

完全なスタックトレースを投稿できますか?あなたが上に掲示したのはちょうど最後の行です。 – solarissmoke

+0

@solarissmokeお探していただきありがとうございます!私はポストに完全な痕跡を追加しました。 – mattydeeds

答えて

1

あなたが抱えている問題は、Djangoはそれを試してみて、デシリアライズするJSONField form fieldだ使用していることです管理者のオブジェクト - ちょうどそれを扱うことができないjson.dumps()を使用するため、これは失敗しますur PostalAddressオブジェクトです。

あなたはモデルフィールドをオーバーライドしてきていますが、管理に使用フォームフィールドをオーバーライドする必要があります。ドキュメントは、specify a custom form field for a model fieldの方法について説明しています。

このような何か:ModelAdminフォームは今、このカスタムフォームのフィールドを使用し、それを正しくデシリアライズすることができるはず

class PostalAddressField(JSONField): 

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

from django.contrib.postgres.forms import JSONField 

# Define a new form field 
class PostalAddressJSONField(JSONField): 

    def prepare_value(self, value): 
     # Here, deserialize the object in a way that works. 
     # I've copied what you've done in your model field. 
     return json.dumps(value.__dict__) 

次に、あなたのPostalAddressFieldにこの新しいフォームフィールドを指定します。

+1

ありがとう!これにより、管理ページを表示する際のエラーが修正されました。 PostalAddressFieldのvalidate()関数をオーバーライドする必要もありました。私はすぐに解決策で質問を更新します。 – mattydeeds

+0

@mattydeeds jsonfieldが有効になるようにvalidate()をオーバーライドしましたか?あなたはsuper()メソッドをスキップしましたか? – Julien

+0

多くのオーバーライドメソッドをスキップし、より小さなコードを取得する良い方法は、PostalAdressインスタンスをシリアル化できる独自のJSONEncoderを実装することです。 PostalAddressField.encoder属性のPostalAddressFieldにデフォルトとして設定する – Julien

関連する問題