본문 바로가기

Python/Django

Django not null CharField objects.create # not null 임에도 object가 생성되는 경우 # unpack # **

728x90
반응형

 

Django에서는 아래와 같이 꼭 입력을 받아야하는 CharField에 대해 null=True 조건을 주지 않고 생성합니다.

(not null 이 default)

 

models.py

class CharTest(models.Model):
    a = models.CharField(max_length=10)
    b = models.CharField(max_length=10)

 

그런데 null=True를 주지 않은

not null 상태인데 값을 안받고 DB에 데이터가 생기는 경우가 있습니다.

 

어떤 경우인지 살펴보도록 하겠습니다.

 

아래와 같이 POST 요청으로 a를 받아서 object를 생성해보겠습니다.

test.html

<form action="/test" method="POST">
    {% csrf_token %}
    <div><input type="text" name="a" placeholder="a"></div>
    <button>send</button>
</form>

 

아래와 같이 하고 123을 입력해서 POST 요청을 해보겠습니다.

views.py

def not_null_test(request):
    if request.method == 'GET':
        return render(request, 'test.html')
    elif request.method == 'POST':
        data = request.POST
        print(data.get("a"))
        print(data.get("b"))
        CharTest.objects.create(
            a = data.get("a"),
            b = data.get("b")
        )
        return JsonResponse(data)

b값을 html에서 넘겨주고 있지 않으니 data.get("b") 는 None이 될것입니다.

그리고 ChatTest table에 row data를 생성하려고 시도하지만 b 가 not null 이므로 아래와 같이 에러가 발생합니다.

 

 

그럼 다음과 같이 ChatTest object를 생성하면 어떻게 될까요?

views.py

def not_null_test(request):
    if request.method == 'GET':
        return render(request, 'test.html')
    elif request.method == 'POST':
        data = request.POST
        print("a: ", data.get("a"))
        print("b: ", data.get("b"))
        CharTest.objects.create(
            a = data.get("a")
        )
        return JsonResponse(data)

b값 자체를 받지 않고서 object를 생성하는 것입니다.

CharTest table을 models.py에서 정의해주면서 null=True 옵션을 주지 않은 것은

CharTest table에 row 데이터가 생성될 때 반드시 a, b field 모두 값을 받을 때만 생성되도록 의도했을 것입니다.
그럼 위와 같은 POST 요청에도 ChatTest에 row data가 생성되지 않을 것을 기대했을 것입니다.

그럼 기대대로 될지 똑같이 a=123을 넣어서 생성해주겠습니다.

 

위와 같이 에러 없이 데이터가 생성되었습니다.

그럼 b는 어떻게 저장이 될까요? null로? 이때 b에는 null 이 아닌 빈 값 자체가 DB에 저장되게 됩니다.

 

모델을 설계할 때, b값이 안들어오면 생성이 되지 않는 것을 기대했을 것입니다.

따라서 위와 같은 불상사가 생기지 않도록 하기 위해서는 MODEL.objects.create()를 이용할 때 반드시 not null field는 값을 입력 받아서 생성해주도록 하고 (값이 없을 때는 None이 들어오도록)

이게 아니면 적어도  front단이나 Back단에서 생성 전에 예외 처리를 해주도록 해야 합니다.

 

이런 문제는

.objects.create(a=a, b=b, ...)와 같이 개별적으로 field에 들어갈 값들을 지정하는 경우에는 실수를 할 일이 잘 없습니다.

 

그런데 아래와 같이 request로 들어오는 데이터를 unpack해서 생성할 때는(**data) 원하지 않는 결과가 생길수 있습니다.

input에 321 값을 넣어서 POST 요청을 해보겠습니다.

views.py

def not_null_test(request):
    if request.method == 'GET':
        return render(request, 'test.html')
    elif request.method == 'POST':
        data = request.POST
        data = {k:v for k,v in data.items() if k != 'csrfmiddlewaretoken'}
        print(data)
        CharTest.objects.create(**data)
        return JsonResponse(data)

 

위의 예에서 보면 data가 unpack 되면서 a=321 만 받아서 생성되게 되고, b는 값을 받아서 생성하는 옵션 자체가 안들어가게 됩니다. 그럼 아래와 같이 b가 not null field임에도 DB에 row data가 생성되게 됩니다.

 

요약

* not null field는 반드시 object 생성시 값을 지정해서 생성

* unpack으로 생성할때는 not null field가 값이 없는 상태로 Table row data가 생성되지 않도록 예외처리 필수

728x90
반응형