본문 바로가기
Back-end/Python

[Python] Data Model 만들기 (1) - BaseField

by 허도치 2021. 1. 19.

  개인적으로 웹 개발을 하다보면 입력 화면이 가장 손이 많이 가는 것 같다. 왜냐하면, 화면에서 입력한 값을 프론트단에서 1차로 유효성검사를 하고 백단에서 2차로 유효성검사를 하고 DB에 입력하는 경우 데이터 타입과 포맷도 맞추어야 하기 때문이다. 그래서, 백단에서 단계를 좀 간소화시킬 수 없을까 고민하다가 데이터 객체를 정의하고 이 객체를 생성할 때, 유효성검사와 데이터 변환을 처리하는 모듈을 구현해보기로 하였다. 이미 marshmallow라는 좋은 라이브러리가 있지만, 직접 만들어보는걸 좋아하기 때문에 완벽하진 않지만 이번에도 직접 구현해 볼 계획이다.
  
  이번 포스트에서 구현할 것은 크게 두가지이다.
  
  첫번째는 데이터 타입 객체이다. 문자열, 정수형, 날짜형과 같은 Python 데이터 타입이지만 유효성검사와 데이터 변환을 위한 기능이 추가된 객체이다.
  두번째는 데이터 모델 객체이다. VO(Value Object)이며, 여러 속성들로 구성된 하나의 의미있는 객체이다. 각 속성은 앞서 생성한 데이터 타입 객체로 정의한다.
  

 

 

1. 데이터 타입 객체
1-1. BaseField 객체 생성
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# fields.py
class BaseField(object):
  def __init__(
      self,
      valtype,
      required=False,
      **kwargs):
 
    self.__value = None
    self.__type = valtype
    self.__required = required
    self.__options = dict(kwargs)
  
  # 값 설정
  def setValue(self, value, validate=True):
    self.__value = None
    
    if validate:
      # 유효성검사: 필수값
      if value is None and self.required:
        raise ValueError("This value was Required, but it is None.")
      
      # 유효성검사: 데이터 타입
      if value is not None and not isinstance(value, self.__type):
        raise TypeError("Expected data type '%s', but '%s'." %( self.__type.__name__, value.__class__.__name__ ))
      
      # 유효성검사
      self.validate(value)
    
    self.__value = value
    
  def getValue(self):
    return self.__value
 
  def getOption(self, optkey, defaultvalue=None):
    return self.__options.get(optkey, defaultvalue)
    
  @property  
  def type(self):
    return self.__type
 
  @property
  def required(self):
    return self.__required
  
  # Override
  def validate(self, value=None):
    pass
  
  def __str__(self):
    return str(self.__value)
 
cs

 

 

1-2. BaseField 객체 테스트
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# test.fields.py
from fields import BaseField
from datetime import datetime
    
# BaseField 테스트
class TestBaseField(object):
  
  #문자열 필드
  string_field = BaseField(str, required=True)
  
  #숫자형 필드
  integer_field = BaseField(int, required=True)
  
  #날짜형 필드
  datetime_field = BaseField(datetime, required=True)
  
  def __init__(self):
    print("BaseField 테스트")
    print("="*30)
    for attrname in dir(self):
      testcase = getattr(self, attrname)
      if attrname.startswith("test"and callable(testcase):
        print("=========", attrname, "========")
        try:
          testcase()
        except Exception as e:
          print("Error: "+str(e))
        print("="*30)
        
  def test_case_1(self):
    print("문자열 필수값 오류 확인")
    print("Input: None")
    self.string_field.setValue(None)
    print("Value: "+str(self.string_field.getValue()))
      
  def test_case_2(self):
    print("문자열 타입 오류 확인")
    print("Input: 1234")
    self.string_field.setValue(1234)
    print("Value: "+str(self.string_field.getValue()))
  
  def test_case_3(self):
    print("문자열 정상")
    print("Input: 'Hello!!'")
    self.string_field.setValue("Hello!!")
    print("Value: "+str(self.string_field.getValue()))
        
  def test_case_4(self):
    print("정수형 필수값 오류 확인")
    print("Input: None")
    self.integer_field.setValue(None)
    print("Value: "+str(self.integer_field.getValue()))
      
  def test_case_5(self):
    print("정수형 타입 오류 확인")
    print("Input: '1234'")
    self.integer_field.setValue('1234')
    print("Value: "+str(self.integer_field.getValue()))
  
  def test_case_6(self):
    print("정수형 정상")
    print("Input: 1234")
    self.integer_field.setValue(1234)
    print("Value: "+str(self.integer_field.getValue()))
        
  def test_case_7(self):
    print("날짜형 필수값 오류 확인")
    print("Input: None")
    self.datetime_field.setValue(None)
    print("Value: "+str(self.datetime_field.getValue()))
      
  def test_case_8(self):
    print("날짜형 타입 오류 확인")
    print("Input: '20200101'")
    self.datetime_field.setValue('20200101')
    print("Value: "+str(self.datetime_field.getValue()))
  
  def test_case_9(self):
    print("날짜형 정상")
    print("Input: %s" %(datetime.now()))
    self.datetime_field.setValue(datetime.now())
    print("Value: "+str(self.datetime_field.getValue()))
      
# 테스트 실행
TestBaseField()
cs

 

 

1-3. BaseField 테스트 결과

 

 

 

마치며

  - 지금까지 BaseField 객체를 생성하고 테스트 해보았다. 다음 포스트에서는 이 BaseField를 상속받은 StringField, IntegerField, DatetimeField 객체를 생성하고 각 데이터 타입에 알맞는 유효성검사를 추가해보도록 하겠다.

 

댓글