Django 사용자 정의 YamlField 구현 프로세스 분석

수요
djangoadmin을 사용할 때 백그라운드의 Textarea 여러 줄 텍스트 상자는 yaml 형식으로 작성할 수 있으며, 데이터베이스는 Text 텍스트 형식으로 저장되며, 필드와 인터페이스에서 읽으면 자동으로 사전이나 목록 형식으로 변경됩니다.
pip installdjango-yamlfied를 사용해 보았습니다. 새 버전django를 수정한 후
인터페이스에서 되돌아오는 필드는 문자열 형식으로 예상에 부합되지 않습니다.
전에 한 판 썼어요.

import yaml
from django.db import models

class YamlField(models.TextField):
  def to_python(self, value): #  python 
    if not value:
      value = {}
    if isinstance(value, (list, dict)):
      return value
    return yaml.safe_load(value)

  def get_prep_value(self, value): # create ,  
    return value if value is None else yaml.dump(value, default_flow_style=False)

  def from_db_value(self, value, expression, connection): #  
    return self.to_python(value)
문제는 입력 상자 입력
- a
- b
- c
저장하면 사전의 문자열 형식으로 바뀝니다.
['a','b','c']
원형으로 보존할 수 없어 연구를 거듭한 후django-jsonfield를 참고하여 한 판을 썼다.
원리는 계승 모델로 바꾸는 것이다.Field 클래스, (models.TextField 클래스를 계승하면 formfield 및value_to_string이 적용되지 않음)
데이터베이스는 데이터베이스에 있는yaml 텍스트를dict/list로 바꾸고djangoadmin에서 사용자 정의widget을 통해yaml 문자열 형식으로 표시합니다.
저장할 때, 폼의 yaml 문자열 형식이 정확한지 확인하기 위해서, 폼을 사용자 정의해야 합니다.전체 코드는 다음과 같습니다.

import django
from django.db import models
from django import forms
from django.core.exceptions import ValidationError
import yaml


class YamlWidget(forms.Textarea):
  def render(self, name, value, attrs=None, renderer=None):
    if value is None:
      value = ""
    if not isinstance(value, str):
      value = yaml.safe_dump(value, default_flow_style=False)
    if django.VERSION < (2, 0):
      return super().render(name, value, attrs)
    return super().render(name, value, attrs, renderer)


class YamlFormField(forms.CharField):
  empty_values = [None, '']

  def __init__(self, *args, **kwargs):
    if 'widget' not in kwargs:
      kwargs['widget'] = YamlWidget
    super().__init__(*args, **kwargs)

  def to_python(self, value):
    if isinstance(value, str) and value:
      try:
        return yaml.safe_load(value)
      except Exception as exc:
        raise forms.ValidationError('Yaml decode error: %s' % (exc.args[0],))
    else:
      return value

  def validate(self, value):
    if value in self.empty_values and self.required:
      raise forms.ValidationError(self.error_messages['required'], code='required')


class YamlField(models.Field):
  description = "Yaml object"

  def get_internal_type(self):
    return 'TextField'

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

  def to_python(self, value: str): #  python 
    if value is None:
      if not self.null and self.blank:
        return ""
      return None
    if isinstance(value, (list, dict)):
      return value
    value = yaml.safe_load(value)
    return value

  def validate(self, value, model_instance): #  
    if not self.null and value is None:
      raise ValidationError(self.error_messages['null'])
    try:
      self.get_prep_value(value)
    except ValueError:
      raise ValidationError(self.error_messages['invalid'] % value)

  def get_prep_value(self, value: (list, dict)): #  ,  
    if value is None:
      return None
    value = yaml.safe_dump(value, default_flow_style=False)
    return value

  def from_db_value(self, value: str, expression, connection, *args, **kwargs): #  
    return self.to_python(value)

  def value_to_string(self, obj): # Rest Framework 
    return self.value_from_object(obj)
이상은 본문의 전체 내용입니다. 여러분의 학습에 도움이 되고 저희를 많이 응원해 주십시오.

좋은 웹페이지 즐겨찾기