Skip to content
Go DevBJ
Go back

Django 실전 노트

Updated:
Edit page

import Adsense from ”@/components/Adsense.astro”;

Django ORM 기술 글 모음

장고에서 ORM을 이용하는 게 가장 기본인데, 필요한 글들을 모아본다. 계속 구글링 해서 지친다. 그냥 정리해 두는게 가장 좋은 방법이다.

기본 CRUD 기능

기본 Queryset 사용법을 정리한 블로그입니다.

[Django] Django ORM queryset 정리(model, filter, all, get, filter, exists, create, save)## F(), Func(), and, or, not 필터 사용법

기본적인 설명이 아주 잘 되어 있어요 굿페이지

Django Query Expressions (1) – F(), Func(), Q(), 그리고 and, or, not보너스 하나더,

[Django] F Expressions## Transaction, Update 관련 글

[django] model update- 객체 다시 DB 에서 읽어오는 method – refresh_from_db()

3. 모델 객체를 데이터베이스에서 다시 읽어들일 수 있나요? — Django ORM Cookbook 2.0 documentation


장고 ORM Transaction 써보기

여러 테이블에 걸쳐서 동시에 수행이 딱딱 같이 되어야 하는 몇개의 일련적인 동작의 일치성을 위해 transaction 기능을 써보도록 하자! 관련하여 아주 좋은 블로그 글 링크가 있어서 일단 소개합니다.

Django DB Transaction 1편 – Request와 DB Transaction 묶기(Feat. ATOMIC_REQUESTS)다른건 몰라도, 사용법은 간단하게 아래와 같이 구성했다.

with transaction.atomic() 이 구문이 전부이다.

    try:        with transaction.atomic():            query1            query2            query3 ...    except Exception as e:        print("re", str(e))        return 400, make_message_response(400, str(e))

쿼리들 사이에 오류가 발생하거나 사용자 에러가 발생하면 그냥 단순하게 raise Exception("에러메시지")

이렇게 하면 이미 수행된 쿼리들의 결과를 다시 롤백해주는 효과를 가져다 준다.

위의 블로그에서 소개한데로 request 별로 아예 ATOMIC 을 잡아주는 옵션이 있지만 자기가 원하는 대로 설계하는 것이 좋지 않나 싶다… 암튼 굿럭~

많은 곳에서 언급되지만, try except 는 with transaction.atomic() 바깥으로 해야 한다고 강력히 권고된다. 주의하세요. 😊


Django migration 취소 제거 방법

그냥 migrations 폴더에서 스크립트 파일들을 막 지우면 문제가 생긴다. 다음 순서대로 차분하게 정리해 보자.

참고로 장고에서 migration 이란?

from https://tibetsandfox.tistory.com/24
> DB 스키마를 git처럼 버전으로 나눠서 관리 할 수 있게 해 주는 시스템

Show me the migrations

먼저 migrations history 를 보자

python manage.py showmigrations

그럼 다음 화면처럼 지금까지 한 역사가 나타난다.

<figure class=“kg-card kg-image-card”>&lt;/figure&gt;앱이름과 적용한 migrations 내용이 나타난다.

특정 위치로 돌아가기

여기서 돌아가고 싶은 곳으로 취소하고 싶다면, (이미 적용된 것을 취소하고 싶다면) 아래 커맨드를 참고한다. 즉, testapp의 0001번으로 돌아가고 싶다면,

python manage.py migrate testapp 0001

아예 0001 까지 없애고 싶다면, 돌아갈 곳이 없는데 어떻게 하느냐?

python manage.py migrate testapp zeroORpython manage.py migrate --fake testapp zero

삭제하기

migrations 폴더로 가서 원하는 파일을 순서대로 지우면 된다. 의존성이 있으니깐 뒤에서 원하는 지점까지는 전부 지워서 없애는게 나을 듯,

<div class=“kg-card kg-callout-card kg-callout-card-grey”><div class=“kg-callout-emoji”>😊&lt;/div&gt;<div class=“kg-callout-text”>__init__.py 파일을 안 지우는게 좋을 듯 합니다. DB를 다 날릴 거 아니라면&lt;/div&gt;``&lt;/div&gt;from https://tibetsandfox.tistory.com/24

이 때 0002 마이그레이션 파일을 삭제하고 싶다면,
1. python manage.py migrate app_name 0001 명령어로 이전 버전으로 적용시킨후 삭제
2. python manage.py migrate app_name zero 명령어로 마이그레이션을 초기화 시킨 수 삭제
둘 중 하나의 절차를 거친 후 삭제</u>하서야 합니다.

초기화

DB에는 스키마가 남아 있으니 혹시 재 초기화 하고 싶다면 fake-initial 을 …

python manage.py migrate --fake-initial

관련된 내용은 여기 참고 (https://velog.io/@kho5420/Django-Django-마이그레이션-초기화)

참고 페이지

훨씬 자세한 내용 😁 못이겨 못이겨

  • 좀 방대하지만 교과서 같은 사이트

05) 마이그레이션 파일 제거- 딱 필요한 것만 요점 정리

Django – makemigrations 취소하는 방법 · 지혜의 개발공부로그- migrations 에 대한 전반적인 내용

장고(Django) – 마이그레이션(Migration)


Django template – list empty 처리

빈 리스트를 장고 템플릿에서 표현하는 방법은 아래 처럼 <strong>\{\% empty \%}</strong> 구문을 활용하자!

{% raw %}

    {% for item in itemlist %}    {% if item.is_deleted == 1 %}    {% else %}    {% now "Y-m-d" as todays_date %}    <tr class="align-middle">        <td class="white-space-nowrap ps-0">            [{{ item.id }}]({% url 'orderitem_view' pk=item.id %})        </td>        <td class="align-middle" >            <p class="mb-0">{{ item.product }}</p>        </td>        <td class="align-middle text-end" >            <p class="mb-0">{{ item.date_due | date:"m-d"}}</p>        </td>        <td class="align-middle text-end" >            <p class="mb-0">{{ item.quantity|intcomma }}</p>        </td>        <td class="align-middle text-end" >            <p class="mb-0">{{ item.workline }}</p>        </td>    {% endif %}    </tr>    {% empty %}    <tr class="align-middle">        <td colspan="5" class="align-middle text-center" >출고예정 주문이 없습니다.</td>    </tr>    {% endfor %}

코드에 편리한 게 하나 더 있네 😀 intcomma 도 활용하면 숫자에 콤마를 찍어줘서 읽기 편하게 해준다. 이건 다른 포스팅에서 참고하세요.

혹은 <strong> {% if %} </strong> 구문으로도 판단할 순 있다. 원본은 여기 https://docs.djangoproject.com/en/4.0/ref/templates/builtins/

{% if athlete_list %}    Number of athletes: {{ athlete_list|length }}{% else %}    No athletes.{% endif %}

{% endraw %}


Django Template – url 함수 호출

url 함수로 템플릿에서 원하는 함수를 호출할 수 있다. 호출 방법은 다음과 같다. 이 페이지에 나오는 예제 구문은 여기(https://wikidocs.net/70741) 페이지를 방문해서 더 자세한 내용을 살펴보시면 좋겠네요.

{% raw %}

{% url 'detail' question.id %}

함수에 넘겨주는 인자가 있다면 다음과 같이 사용할 수 있다. 인자명 없이 그냥 순서대로 넣어줘도 동작한다. 대신 순서가 틀려지면 안된다. 😁

{% url 'detail' question_id=question.id %}
{% url 'detail' question_id=question.id page=2 %}

{% endraw %}

이상.


Django – ORM Coalesce() 활용

읽기도 어려워 Coalesce() 함수를 사용해 보자. 엄청 유용한데 잘 안 알려져 있는 듯

None, Null 이 리턴되는 경우 Exception 이 많이 나오는데, 이를 다 처리해 두지 않은 경우 의도치 않는 상황에 빠지게 되는 경우가 많다. 특히 aggregation 함수들을 사용하는 경우 기본적으로 어떤 값을 리턴해 주도록 해 주는 것이 좋다. 0이나 1 이런 값들을 기본값으로

당연히 잘 써둔 글들이 있다 😁

Django – Coalesce를 사용하여 aggregate가 None을 반환하는 것을 방지하기 · 초보몽키의 개발공부로그“python
total_price = WishBook.objects.filter(created_at__year=‘2017’, created_at__month=‘09’).aggregate(total=Sum(‘price’))[‘total’] or 0# ORfrom django.db.models.functions import Coalescetotal_price = cls.objects.filter(created_at__year=year, created_at__month=month).aggregate(total=Coalesce(Sum(‘price’), 0))[‘total’]


예제에서 제공되는 or 도 괜찮은 방법 같다.

**기본적으로 값이 없을 경우가 있는 Count(), Aggregate() 이런 함수들을 쓸 때 기본적으로 무조건 쓰도록 하자!**

## 참고 페이지

- 반드시 좀 읽어서 습득하자!

[[Django] 반드시 알아야 할 5가지ORM 쿼리](https://chrisjune-13837.medium.com/django-%EB%8B%B9%EC%8B%A0%EC%9D%B4-%EB%AA%B0%EB%9E%90%EB%8D%98-orm-%EA%B8%B0%EC%B4%88%EC%99%80-%EC%8B%AC%ED%99%94-592a6017b5f5)..@vdekr9

---

### Django – ORM union 사용해보기

말로만 듣던 union() 을 사용해 보려 찾아본다. 사실은 쿼리셋 2개를 하나로 합치기 위해서 찾아봄. 아래 링크에서 정답을 찾을 수 있고, union 부분만 발췌

<figure class="kg-card kg-bookmark-card">[<div class="kg-bookmark-content"><div class="kg-bookmark-title">[Django] queryset 결과 합치기`</div>`<div class="kg-bookmark-description">합칠 대상의 결과가 2개 이상인 경우 union() union()를 사용해서 1개로 합칠 수 있습니다. union()의 2번째 인자는 중복을 허용할지에 대한 여부인데 기본값은 False로 중복을 허용하지 않습니다. (중복데이터일..`</div>`<div class="kg-bookmark-metadata">![](https://img1.daumcdn.net/thumb/C180x180/?fname=https%3A%2F%2Ftistory3.daumcdn.net%2Ftistory%2F1954575%2Fattach%2F09aa2e0ab9af4a0fbf5d108ea5142763)<span class="kg-bookmark-author">TISTORY`</span>`<span class="kg-bookmark-publisher">불곰1`</span>``</div>``</div>`<div class="kg-bookmark-thumbnail">![](assets/images/2023/02/opengraph.png?ssl=1)`</div>`](https://brownbears.tistory.com/426)`</figure>`> union()를 사용해서 1개로 합칠 수 있습니다. union()의 2번째 인자는 중복을 허용할지에 대한 여부인데 기본값은 False로 중복을 허용하지 않습니다. (중복데이터일 경우 중복제거)

`result = a.union(b, all=True)`

그냥 장고 파이썬 코드에서 (ORM이 아닌) 쿼리셋 결과들끼리 `|` 연산자로 합쳐도 된다고 하네요.

`result = a | b`

@vdekr9

---

### Django – ORM values, values_list, list 결과

맨날 헷갈리는데 ORM Queryset 의 결과를 리스트로 받아 쓰는 경우가 많아 **values(), values\_list(), list()를 자주 쓰게 되는데 확실히 결과가 어떻게 다른지 알아보자.**

말보단 코드를 짜서 결과를 보고 비교해 보는 게 확실히 이해하는데 크게 도움이 된다.

```python
    result_by_orderitem = Result.objects.filter(starttime__year=s_year).order_by("orderitem", "-starttime").distinct("orderitem").values("orderitem")    print(result_by_orderitem)    result_by_orderitem = Result.objects.filter(starttime__year=s_year).order_by("orderitem", "-starttime").distinct("orderitem").values_list("orderitem")    print(result_by_orderitem)    result_by_orderitem = Result.objects.filter(starttime__year=s_year).order_by("orderitem", "-starttime").distinct("orderitem").values_list("orderitem", flat=True)    print(result_by_orderitem)    result_by_orderitem = list(result_by_orderitem)    print(result_by_orderitem)

예제로 짠 파이썬 코드의 결과를 보면,

<QuerySet [{'orderitem': 278}, {'orderitem': 279}, {'orderitem': 280}, {'orderitem': 284}, {'orderitem': 287}, {'orderitem': 288}]><QuerySet [(278,), (279,), (280,), (284,), (287,), (288,)]><QuerySet [278, 279, 280, 284, 287, 288]>[278, 279, 280, 284, 287, 288]

values 는 {필드명:값} 형태의 딕셔너리 형태의 Queryset 의 리스트 형태로 리턴 되어 있고

values_list 는 필드명을 지정해 둬서 튜플 형태의 (값, 값, …) 의 Queryset 리스트로 리턴되고,

plat=True 옵션을 주면 튜플 형태가 없어지고 그냥 값들의 리스트 형태와 유사한 Queryset 리스트를 리턴하고,

맨 마지막 값을 그냥 list(queryset) 형태로 호출하면, 그냥 순수한 값들의 리스트로 리턴되고 있음을 볼 수 있다.

..@vdekr9


Ajax html 페이지 가져오기

간단한 Ajax 로 페이지 가져오기 예제

자세한 내용은 Ajax + Django로 한 페이지에서 다른 html 띄우기 에서 읽어보세요!

&lt;button id='listButton'&gt;&lt;/button&gt;&lt;div id='example'&gt;&lt;/div&gt;

해당 페이지에 아래 스크립트를 추가하면 , example 로 지정한 div에 결과 내용이 출력되게 되어 있다. 접속 주소만 쓰면, 활용할 수 있다.

로딩중 처리를 위해서 “LoadingOverlay”라는 라이브러리를 활용하는 것도 같이 넣어 봤다.

{% raw %}

```text
$('#listButton').click(function() {// Show full page LoadingOverlay        $.LoadingOverlay("show");        $.ajax({            type: "GET",            url:"{% url 'result_list' %}", // list url을 불러옴            dataType: 'html', // list의 형태는 html            success: function(data){ // 성공했을 때 일단 good을 alert로 띄운다.                alert('good');                $('#example').html(data) // 그 이후에 example div에 list html의 data를 가져온다.            },            error: function(request, status, error){ // 실패했을 때 bad alert, 에러가 무엇이었는지, 그리고 간단한 html 출력                alert('bad');                alert(error);                $('#example').html('AJAX 통신에 실패했습니다.');            }        })        $.LoadingOverlay("hide");});
`{% endraw %}`

## 페이지 로딩 중 자바스크립트

JQuery를 이용한 로딩 처리, 아래 페이지에 예와 라이브러리 참고하자!

<figure class="kg-card kg-bookmark-card">[<div class="kg-bookmark-content"><div class="kg-bookmark-title">jQuery LoadingOverlay – Gaspare Sganga`</div>`<div class="kg-bookmark-description">A flexible loading overlay jQuery plugin`</div>`<div class="kg-bookmark-metadata">![](https://gasparesganga.com/assets/img/favicon-ad10b8480193d0c732ff8aa5d81cd941a475635d6b72c5cadcffb2543528d3b1.ico)<span class="kg-bookmark-author">Gaspare Sganga`</span>`<span class="kg-bookmark-publisher">Gaspare Sganga`</span>``</div>``</div>`<div class="kg-bookmark-thumbnail">![](https://gasparesganga.com/assets/img/logo_no_bg-cc00e36b274741cf4a5cab61c50ecc7791158260c51e9bc014ba199044378bf8.svg)`</div>`](https://gasparesganga.com/labs/jquery-loading-overlay/#examples)`</figure>`

---

### Django – ForeignKey display text\n변경하기

modelforms 에서 자동으로 값을 가져오긴 하는데 \_\_str\_\_ 에 정의된 글자나 키 값을 기본으로 보여준다. 부가적으로 정보를 더 보여주고 싶은데 `__str__` 을 바꾸면 전체에 이 모델을 접근하는 부분이 다 바뀌므로, 딱 combo에 올라가는 글자만 변경하고 싶다면,

> label\_from\_instance 속성을 건드리면 된다.

자세한 설명은 아래 링크를 참고해 보시고,   
[How to change ForeignKey display text in the Django Admin?](https://stackoverflow.com/questions/6836740/how-to-change-foreignkey-display-text-in-the-django-admin)

예제 코드를 살펴보면,

```python
subform.fields["product_profile"].queryset = get_user_productprofile(companyid=_companyid, is_superuser=_superuser).order_by("name")subform.fields["product_profile"].label_from_instance = lambda obj: "%s(%s)" % (obj.name, obj.product.name)

queryset 을 통해 필터링 결과를 넣어 줄 수 있고

label_from_instance 통해 display text 를 변경할 수 있다. 예제에서 필드명(상품명) 상태로 보이도록 수정한 버전이다.

![](assets/images/2023/02/4_image.png?resize=183%2C121&ssl=1)`
`## 참고 사이트
  • 람다 lambda 를 사용하고 있는데, 관련 기초 정보는 여기를 가보세요.
[
3.5 람다(lambda)`
`
오늘은 람다 형식과 그것을 이용하는 여러 가지 함수들에 대해서 알아보겠습니다. 당장 완벽하게 소화하실 필요는 없을 것 같구요, 가벼운 마음으로 이런 것이 있다는 정도만 아셔 …`
```
`
![](assets/images/2023/02/chobo_python_title.png?ssl=1)`
`](https://wikidocs.net/64)`
`

Django model.forms 사용자 필드 추가

model form에서 추가로 별도의 사용자 필드를 추가하고 싶다면, 아래처럼 추가로 forms.필드타입 으로 선언해서 사용하면 된다.

label, widget 용례도 참고해 보면 좋다. required=False 도 옵션으로 주면, 필수 항목으로 추가 되지 않는다.

class FirmwareForm(forms.ModelForm):    is_fileinclue = "enctype=multipart/form-data"    autogen = forms.BooleanField(label=_("중복시 자동변경"), widget=forms.CheckboxInput(attrs={"class": "form-check-input", "type": "checkbox"}), required=False)        class Meta:        model = Firmware        fields = ["company", "dtype", "content"]        labels = {            "company": _("*회사"),            "dtype": _("타입"),            "content": _("파일"),        }        widgets = {            "company": forms.Select(attrs={"class": "form-select"}),            "dtype": forms.Select(attrs={"class": "form-select", "required": True, "placeholder": "타입"}),            # "content": forms.FileInput(attrs={"class": "form-control", "style":"width: 100px;"}),            # "content": forms.FileField('첨부 파일', upload_to='uploads/'),        }

사용할 때는 일반 필드와 동일하다.

if form.cleaned_data["autogen"]:

이런 식으로 값을 바로 보면 된다.

참고 사이트

예제 코드를 볼 수 있다. Django Forms BooleanField 예제 코드들

class CopyPermissionForm(forms.Form):    """    Holds the specific field for permissions    """    copy_permissions = forms.BooleanField(        label=_('Copy permissions'),        required=False,        initial=True,    )
[
django.forms BooleanField Python Code Examples`
`
Python code examples to show how to use the BooleanField class within the forms module of the Django open source project.`
```
`
![](assets/images/2023/02/default.jpg?ssl=1)`
`](https://www.fullstackpython.com/django-forms-booleanfield-examples.html)`
`

Django ORM – order_by 리스트로

쿼리셋에서 order_by() 를 필드 하나만 하는 경우는 머 고려할 것도 없이 그냥 필드명을 적어주면 된다.

2개 이상은

queryset.order_by("필드1", "필드2")

이렇게 주면 된다.

파이썬 코딩에서 필드명을 리스트를 만들고 그 리스트를 바로 넣어주면 편하다고 생각했는데, 그대로 되네

    order_field = "name"    order_field = s_sort_order + order_field    order_field_array = []    order_field_array.append("company")    order_field_array.append(order_field)    search_itemlist = product_list.order_by(*order_field_array)

*필드배열 을 넣어주는 것이 핵심!


Django ORM – 쿼리셋 합치기

가장 기본적인 것 같은데, 막상 하려면 다 찾아봐야 해

장고 ORM 쿼리셋 2개를 하나로 합치고 싶다면

union() or “|” 를 이용하면 된다. 자세한 내용은 아래 링크로

result = a.union(b, all=True)

[
[Django] queryset 결과 합치기`
`
합칠 대상의 결과가 2개 이상인 경우 union() union()를 사용해서 1개로 합칠 수 있습니다. union()의 2번째 인자는 중복을 허용할지에 대한 여부인데 기본값은 False로 중복을 허용하지 않습니다. (중복데이터일..`
```
`
![](assets/images/2023/02/opengraph.png?ssl=1)`
`](https://brownbears.tistory.com/426)`
`아니면, 쿼리셋 2개를 OR 하자
queryset = User.objects.filter(first_name__startswith='R') 			|             User.objects.filter(last_name__startswith='D')queryset <QuerySet [<User: Ricky>, <User: Ritesh>, <User: Radha>, <User: Raghu>, <User: rishab>]>

참고 사이트는 여기

[
2. OR 연산으로 일부 조건을 하나라도 만족하는 항목을 구하려면 어떻게 하나요? — Django ORM Cookbook 2.0 documentation`
`
`
```
`
![](assets/images/2023/02/usertable.png?ssl=1)`
`](https://django-orm-cookbook-ko.readthedocs.io/en/latest/or_query.html)`
`

Django Template – with 변수 선언

변수가 너무 길어서 엄청 불편함, 좀 줄인 변수에 넣어서 해보고 싶어서 좀 찾아봄, 예를 들어 request.user.profile.company.name 이런 식의 변수를 간단하게 쓰면 좋겠다 😁

with 구문으로 페이지에 쓰일 사용자 변수를 선언해서 쓸 수 있네.

{% raw %}

```text
{% with total=business.employees.count %}	{{ total }} employee{{ total|pluralize }}{% endwith %}

복수 개를 선언 하려면, 한 칸 띄우고 선언을 쭉 하면 된다.

> You can assign more than one context variable:

```django
```text
{% with alpha=1 beta=2 %}	... {% endwith %}

참고로, 이전에 `with as` 구문으로 사용했다고 하네.

<div class="kg-card kg-callout-card kg-callout-card-blue"><div class="kg-callout-emoji">😊`</div>`<div class="kg-callout-text">The previous more verbose format is still supported:   
`<strong>`{% with business.employees.count as total %}`</strong>`</div>`</div>`## 참고 페이지

`{% endraw %}`

장고 사이트에서 with 구문 위치

<figure class="kg-card kg-bookmark-card">[<div class="kg-bookmark-content"><div class="kg-bookmark-title">Built-in template tags and filters | Django documentation | Django`</div>`<div class="kg-bookmark-description">`</div>`<div class="kg-bookmark-metadata">![](assets/images/2023/02/icon-touch.e4872c4da341.png?ssl=1)<span class="kg-bookmark-author">Django`</span>``</div>``</div>`<div class="kg-bookmark-thumbnail">![](https://static.djangoproject.com/img/fundraising-heart.cd6bb84ffd33.svg)`</div>`](https://docs.djangoproject.com/en/4.1/ref/templates/builtins/#with)`</figure>`

---

### Django – 유효성 검사에 대한 글

수많은 정보를 저장하고 꺼내오고 해야 하는 시대에 Django 로 서비를 만들고 하다보면, 각각 필드의 유효성 검사에 대한 고민이 엄청 많다.

폼에서 하나 자바스크립트로 하나 model 에서 하나…등등등 아래 글에서 인사이트를 얻어보자 잘 정리해 두셨네. 강의를 들으면서 정리하신 내용 같은데 많은 도움이 되었어요 😊

<figure class="kg-card kg-bookmark-card">[<div class="kg-bookmark-content"><div class="kg-bookmark-title">Django Form Validation`</div>`<div class="kg-bookmark-description">출처 : https://www.inflearn.com/course/%ED%8C%8C%EC%9D%B4%EC%8D%AC-%EC%9E%A5%EA%B3%A0-%EC%9B%B9%EC%84%9C%EB%B9%84%EC%8A%A4/dashboard 장고(Django)를 배우기 시작한 입문자이시거나, 또는 배우고 싶은 생..`</div>`<div class="kg-bookmark-metadata">![](https://img1.daumcdn.net/thumb/C180x180/?fname=https%3A%2F%2Ftistory4.daumcdn.net%2Ftistory%2F5023799%2Fattach%2F383305eb3b5245d39847c30d30042e2a)<span class="kg-bookmark-author">TISTORY`</span>`<span class="kg-bookmark-publisher">개발자Dongbaek`</span>``</div>``</div>`<div class="kg-bookmark-thumbnail">![](https://img1.daumcdn.net/thumb/R800x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbyWt1Y%2Fbtrq5pnLgX1%2FrSOA42FOPMPX2H7y4KKZsk%2Fimg.jpg)`</div>`](https://devdongbaek.tistory.com/88)`</figure>`## 내가 만든 예제코드

```python
from django.core.validators import MinLengthValidatordef validate_isdecimal(value):    if not value.isdecimal():        raise ValidationError(            _("%(value)s is not an deciamal number"),            params={"value": value},        )class Company(models.Model):    name = models.CharField(max_length=255)    vatid = models.CharField(max_length=255, unique=True, validators=[validate_isdecimal, MinLengthValidator(10)])  # 숫자가 아니거나, 10자리 이하는 에러 반환

결론

아니… 그러면 언제 Validators를 써야하고, 언제 clean을 써야해???

가급적이면 모든 validators는 model에 정의하고, ModelForm을 통해서 model validators 정보도 같이 가져와야 한다.
validators는 웬만하면 model에 정의하자!!</u>

😊`
`
clean() 을 오버라이드해서, validator에 위배되는 행동을 만약 clean() 함수 내에서 허용하면, 암만 모델에 정해둬도 유효성을 무시하고 데이터가 처리됨을 명심하시길!! form.is_valid() 이전에 호출 되기 때문 같네.`
``
`**clean이 필요할 때는,**
  • 특정 Form에서 1회성 유효성 검사 루틴이 필요할 때
  • 다수 필드값에 걸쳐서, 유효성 검사가 필요할 때
  • 필드 값을 변경할 필요가 있을 때 #validators는 값만 체크하고, 변경할 수는 없다.

빌트인 유효성 검사를 사용해

공식 사이트에서 제공하는 이미 준비된 Validators 들이 있다. 보고 활용을 하자.

[
Validators | Django documentation | Django`
`
`
```
`
![](https://static.djangoproject.com/img/fundraising-heart.cd6bb84ffd33.svg)`
`](https://docs.djangoproject.com/en/4.0/ref/validators/#built-in-validators)`
`### 예제
from django.core.validators import MinLengthValidatorclass GameUserSignupForm(forms.ModelForm):    class Meta:        model = GameUser        fields = ['server','username']    def clean_username(self): # 필드명에 clean_을 붙여서 각 필드별로 유효성 처리및 데이터 변경을 수행함        return self.cleaned_data.get('username', '').strip()

Django – UpdateView pk 없이 사용하기

url 로 UpdateView 의 PK 값을 넘겨주는 방식이 일반적인데, 사용자 정보 같은 것을 넘겨줄 때 사용자에 대한 pk 값이 노출되는게 부담스럽다.

꼭 넘겨줘야 하나? 내꺼만 고치면 되는데…

이때는 내장 함수를 통해 자기가 로딩 되면서 가져오도록 하면 된다. 자기 객체를 불러오는 방식이다. 주인공은 바로,

get_object(self)

@method_decorator(login_required, name="dispatch")class profile_update_view(UpdateView):    model = Profile    # fields = "__all__"    fields = ["level", "phone"]    template_name = "profile.html"    def get_object(self):        print("profile_update_view get_object()", self.request.user)        return Profile.objects.get(user=self.request.user)        # return self.request.user    def get_success_url(self):        return self.request.META["HTTP_REFERER"]

쓸데없이 url 로 넘기지 않고 바로 자기가 호출될때 필요한 객체를 get_objct() 함수에서 가져와서 return 해주면 끝!

참고 페이지

[
Django: DetailView, UpdateView pk나 slug 없이 사용하기`
`
CBV를 주로 사용하면서, 참 잘 만들었다고 감탄하고 있다. DetailView, UpdateView 등 pk나 slug가 기본으로 필요한 CBV를 사용할 때, pk나 slug 없이 특정 object를 전달하는 방법을 공유한다. get_object 에 직..`
```
`
![](assets/images/2023/02/opengraph.png?ssl=1)`
`](https://seulcode.tistory.com/281)`
`

Django – UpdateView pk 있을때 없을때 다 처리하기

UpdateView pk 없이 사용하는 방법을 전 포스트에서 알아 봤는데 PK 값이 url에 있든 없든 하나의 View로 다 처리하고 싶어졌다.

일반 사용자는 자기꺼만 처리하면 되지만, superuser 혹은 admin은 다른 사용자 정보를 수정하고 싶을 수 도 있기 때문에 pk 값을 넘겨 받아서 사용하는 것도 같은 UpdateView에서 처리하고 싶었다.

그냥 get_object() 함수 내에서 pk 유무를 보고 처리하면 안되나……된다! 코드를 올려둔다.

@method_decorator(login_required, name="dispatch")class profile_update_view(UpdateView):    model = Profile    # fields = "__all__"    fields = ["phone"]    template_name = "profile.html"    def get_object(self):        print("profile_update_view get_object()", self.request.user, self.kwargs.get("pk"))        if self.kwargs.get("pk"):            if self.request.user.is_superuser:                return Profile.objects.get(user=self.kwargs.get("pk"))            else:                set_page_message(self.request, messages.INFO, f"접근 권한이 없습니다!")        return Profile.objects.get(user=self.request.user)        # return self.request.user    def get_success_url(self):        return self.request.META["HTTP_REFERER"]

self.kwargs.get("pk") 로 pk 값이 url을 통해 넘어오는지 유무를 알수 있고 그 상황에 맞게 각자 원하는 코드를 집어 넣으면 될듯!

단!!!! urls.py 함수에서 pk 가 있는 것, 없는 것 다 같은 view를 호출하도록 꼭 해줘야 한다.

    path("profile", profile_update_view.as_view(), name="profile_list_1"),    path("profile/<int:pk>", profile_update_view.as_view(), name="profile_list"),

참고 사이트

아래 글은 한번 정독을 권고!!

[
Deep Dive into Class-Based Views — Python 401 2.1 documentation`
`
`
```
`
![](assets/images/2023/02/cf_logo.png?ssl=1)`
`](https://codefellows.github.io/sea-python-401d5/lectures/django_cbv2.html#the-get-object-method)`
`장고 소스도 읽어보자. 오버라이딩 하려면 먼가 알아야징

slug_url_kwarg, pk_url_kwarg 를 보면 왜 ‘pk’ ‘slug’ 라는 키워드를 그냥 써도 되는지 알 수 있다. 여기에 적힌 문자열을 인식하는 것 뿐이다 😊

# django/views/generic/detail.pyclass SingleObjectMixin(ContextMixin):    """    Provides the ability to retrieve a single object for further manipulation.    """    model = None    queryset = None    slug_field = 'slug'    context_object_name = None    slug_url_kwarg = 'slug'    pk_url_kwarg = 'pk'    query_pk_and_slug = False    def get_object(self, queryset=None):        """        Returns the object the view is displaying.        By default this requires `self.queryset` and a `pk` or `slug` argument        in the URLconf, but subclasses can override this to return any object.        """        # Use a custom queryset if provided; this is required for subclasses        # like DateDetailView        if queryset is None:            queryset = self.get_queryset()        # Next, try looking up by primary key.        pk = self.kwargs.get(self.pk_url_kwarg, None)        slug = self.kwargs.get(self.slug_url_kwarg, None)        if pk is not None:            queryset = queryset.filter(pk=pk)        # Next, try looking up by slug.        if slug is not None and (pk is None or self.query_pk_and_slug):            slug_field = self.get_slug_field()            queryset = queryset.filter(**{slug_field: slug})        # If none of those are defined, it's an error.        if pk is None and slug is None:            raise AttributeError("Generic detail view %s must be called with "                                 "either an object pk or a slug."                                 % self.__class__.__name__)        try:            # Get the single item from the filtered queryset            obj = queryset.get()        except queryset.model.DoesNotExist:            raise Http404(_("No %(verbose_name)s found matching the query") %                          {'verbose_name': queryset.model._meta.verbose_name})        return obj

Django – UpdateView form_valid() 예외처리

UpdateView 를 이용하여 업데이트 할때, 혹여나 form_valid() 에서 Exception 이 발생하면 그냥 오류 페이지가 떡 떠버린다.

이런거 무시하고 특정 페이지로 무조건 리턴되도록, 즉 예외가 발생하면 update 없이 머 success url 로 이동시키자 이런 코드를 넣어보자. 단순하게 아래처럼 예외를 pass 해버리고 무조건 success_url() 로 이동시키도록 해봤다.

    def form_valid(self, form):        try:            super().form_valid(form)        except Exception as e:            pass        return redirect(self.get_success_url())

form_valid 에서 예외가 나든 안나든 처리가 잘된다. 🙂

끝.


Django – ModelForm init() 함수 예제

그냥 예제 ModelForm init() 함수에서 수행할 것을 몇 가지 저장해 둔다.

  • 원하는 필드만 보여주기 fields
  • 필요 없는 필드 제거해서 보여주기 exclude
  • labels 를 이용한 원하는 라벨 표기
  • widgets 으로 원하는 form 객체 가져다 놓기
  • 필드에 필터링 해서 데이터를 올려줄 수 있는 queryset
  • empty label 보여주지 않게 하기
class ProductProfileForm(forms.ModelForm):    class Meta:        model = ProductProfile        fields = ["company", "name", "product", "fwver1"]        exclude = ["updated_at", "created_at"]        labels = {            "company": _("*회사"),            "name": _("프로파일명"),            "product": _("상품명"),            "fwver1": _("펌웨어"),        }        widgets = {            "company": forms.Select(attrs={"class": "form-select"}),            "name": forms.TextInput(attrs={"class": "form-control flex-fill", "placeholder": "프로파일명 (중복허용안함)"}),            "product": forms.Select(attrs={"class": "form-select flex-fill", "required": True}),            "fwver1": forms.Select(attrs={"class": "form-select flex-fill", "required": False}),        }    def __init__(self, *args, **kwargs):        super().__init__(*args, **kwargs)        self.fields['fwver1'].queryset = Firmware.objects.filter(dtype='F')        # empty field label --------- 없애기        self.fields['product'].empty_label = None

끝.


Django – CreateView form_valid() 오버라이딩

CreateView 저장 작업을 할때 커스텀 동작이 필요하다면, form_valid()를 오버라이딩해서 그냥 여기서 저장해 버리는 방법이 있다.

View를 쓴다는게 좀 커스텀 동작을 제약하는 경우와 편리성을 바꾸는 것이니 만큼 좀 불편해도 이렇게라도 변경해서 쓰자. 기본 코드는 아래와 같다.

def form_valid(self, form):    self.object = form.save()    # do something with self.object    # remember the import: from django.http import HttpResponseRedirect    return HttpResponseRedirect(self.get_success_url())

self.object 에 form 데이터가 일단 저장되고, 이 값을 이용해서 원하는 동작을 수행한다. 그리고 코드에는 get_success_url() 로 redirect 하고 있지만 원하는 어디든 보내면 된다.

내 작업에 작성한 코드도 일단 올려둔다. 많이 쓰이는 request 객체는 self.request 로 접근이 가능해서 코드 작성이 용이했다.</u>

def form_valid(self, form):    print("FirmwareCreateView form_valid override")    self.object = form.save(commit=False)    print("firmware_list request.FILES -", self.request.FILES)    for filename, file in self.request.FILES.items():        print("firmware_list", filename, file, file.name, file.content_type, file.size)        self.object.filename = file.name        if form.cleaned_data["desc"]:        self.object.desc = form.cleaned_data["desc"]        else:        self.object.desc = file.name    self.object = form.save(commit=True)	kind = self.request.GET.get("kind")    print("firmware_list kind", kind)    if not kind:        kind = definitions.FILE_TYPE_FIRMWARE    redirect_url = reverse_lazy("firmware_list") + "?kind=" + kind    print(redirect_url)    return redirect(redirect_url)

코드 참고한 글은 아래 링크이다.

[
Django CreateView: How to perform action upon save`
`
I’m using a custom CreateView (CourseCreate) and UpdateView (CourseUpdate) to save and update a Course. I want to take an action when the Course is saved. I will create a new many-to-many relations…`
```
`
![](assets/images/2023/02/apple-touch-icon@2.png?ssl=1)`
`](https://stackoverflow.com/questions/32998300/django-createview-how-to-perform-action-upon-save)`
`

Django – Form 첨부 파일 처리

폼 객체에서 파일이 넘어 올 때 처리하는 코드 일부를 남겨둔다. enctype=multipart/form-data 로 지정해서 넘어올 때 말이다.

파일 이름은 어떻게 가져오는지, 어떤 정보가 있는지 참고가 될만하다.

print(request.FILES)print(request.FILES.items())for filename, file in request.FILES.items():    print(filename, file, file.name, file.content_type, file.size)    # file = request.FILES['filename']    # file.name           # Gives name    # file.content_type   # Gives Content type text/html etc    # file.size           # Gives file's size in byte    # file.read()         # Reads file
  • request.FILES 에 첨부파일이 담겨온다
  • file.name – 파일명
  • file.content_type – 파일 타입, 첨부파일이 그림파일인 경우 유용할 듯
  • file.size – 파일 사이즈
  • file.read() – 실제 content 내용을 읽어온다.

Django – ModelForm field 초기값 설정하기

ModelForm init 함수에서 특정 필드값 초기값 주는 방법, 아래 글에 자세히 나와 있습니다.

Django set field value after a form is initialized

핵심은 initial 이라는 키워드

form.field["필드이름"].initial = 원하는값

이렇게 주면 된다.

많이들 아는 queryset 으로 Foreign Key로 연결된 테이블 값을 필터링 하는 방법은 많이 알고 있으니 머 생략하지만, 초기값을 막상 주려니 또 검색하게 되었다. 여기에 남겨둠

__init__ 오버라이딩 코드도 참고로 남겨둔다.

class ChooseProjectForm(forms.Form):    project = forms.ModelChoiceField(queryset=project_qs)    my_projects = forms.BooleanField()    def __init__(self, *args, **kwargs):        super(ChooseProjectForm, self).__init__(*args, **kwargs)        self.data = self.data.copy()  # IMPORTANT, self.data is immutable        # any condition:        if self.data.get('my_projects'):            my_projects = self.fields['project'].queryset.filter(my=True)            self.fields['project'].queryset = my_projects            self.fields['project'].initial = my_projects.first().pk            self.fields['project'].empty_label = None  # disable "-----"            self.data.update(project=my_projects.first().pk)  # Update Form data            self.fields['project'].widget = forms.HiddenInput()  # Hide if you want
  • empty_label – 빈 값 조정
  • forms.HiddenInput()
  • widget 지정

코드에서 이런 내용들을 살펴볼 수 있다. 공부하자!!


Django – redirect with param 코드조각

말이 필요없다. redirect 하는데 파라메터 있는 경우 처리를 위한 코드 조각을 저장해 둔다.

def redirect_params(url, pk, params=None):    response = redirect(url, pk=pk)    if params:        query_string = urllib.urlencode(params)        response["Location"] += "?" + query_string    return response

url/pk?querystring 모두를 다 처리하는 기본 코드 되겠다.

참고만 하시길, 근데 무식하게 이렇게 해도 되긴 하더라만

redirect_url = reverse_lazy("firmware_list") + "?kind=" + kindprint(redirect_url)return redirect(redirect_url)

Django – Ninja api querystring 처리

Django ninja api 엔진을 쓰고 있는데, 쿼리스트링을 처리하는 함수를 만들려고 한다. 주소에서 파라메터를 뽑아 쓰는 것은 직관적이었는데…

역시 똑같다. 차이가 없다.

@api.get("/weapons")def list_weapons(request, limit: int = 10, offset: int = 0):    return weapons[offset: offset + limit]
  • 파라메터에 기본값을 넣고 추가해 준다. 이건 path parameter 와 완전 동일하다.
  • 호출의 형태는 아래와 같다. So, going to the URL:
  • http://localhost:8000/api/weapons
  • same as http://localhost:8000/api/weapons?offset=0&limit=10
  • http://localhost:8000/api/weapons?offset=20

기본 값을 줬기 때문에 아무것도 주지 않으면 default value 로 처리된다.

설명서가 포함된 자세한 내용은 아래 글을 참고하자.

[
Query parameters – Django Ninja`
`
Django Ninja – Django REST framework with high performance, easy to learn, fast to code.`
```
`
![](assets/images/2023/02/docs-logo.png?ssl=1)`
`](https://django-ninja.rest-framework.com/guides/input/query-params/)`
`참고로 path parameter 도 선언 부분이나 함수 사용 부분은 완전 동일하다
@api.get("/items/{item_id}")def read_item(request, item_id: int):    return {"item_id": item_id}

그냥 대충 쓰자. loose coupled 😅


Django – ORM filter NULL 체크

가장 기본이긴 한데, 막상 쓰려니 또 찾아보네

정리해두자 코드 조각으로

Name.objects.exclude(alias__isnull=True).exclude(alias__exact='')
  • __isnull = True
  • __exact = ”

Django – resolve_url, reverse 코드 예제

modal 창을 띄워서 UpdateView, CreateView 를 처리하고 난 다음 success_url의 경우 호출한 detail 화면으로 보내는 것이 일반적이다.

그럼 detail url 을 success_url 로 리턴할 수 있어야 한다. get_success_url() 을 overriding 해준다.

간단하게 resolve_url() 함수를 쓰면, path parameter 도 같이 처리할 수 있다. 작성한 코드 조각을 남겨둔다.

urls.py 파일에는,

    path("orderitem/<int:pk>", orderitem_view, name="orderitem_view"),

이렇게 되어 있는 url 로 돌아가고 싶다고 가정하면, 아래 처럼 path parameter 를 주면 된다.

class OrderItemWorklineUpdateView(BSModalUpdateView):    model = OrderItem    template_name = "_modal_update.html"    form_class = OrderItemWorklineForm    success_message = "변경완료"    # success_url = reverse_lazy('orderitem_list')    def get_success_url(self):        print("OrderItemWorklineUpdateView get_success_url override", self.object)        redirect_url = resolve_url("orderitem_view", pk=self.object.id)        return redirect_url
  • self.object.id – UpdateView 의 넘겨진 object 는 self.object 에 이미 저장되어 있다.
  • resolve_url 리턴값은 스트링이다.

참고 페이지

아래 링크는 자세히 읽어 보는 게 좋다. reverse, redirect, resolve_url, get_absolute_url 용례가 잘 설명되어 있다.

[
URL Reverse, 아는 사람은 꼭 쓴다는 get_absolute_url() · 초보몽키의 개발공부로그`
`
`
```
`
![](assets/images/2023/02/profile.png?ssl=1)`
`](https://wayhome25.github.io/django/2017/05/05/django-url-reverse/)`
`

Django – settings.py 변수 상수 사용하기

전역변수나 상수처럼 settings.py 에 정의된 놈들을 쓰고 싶다면 이렇게 하자.

settings.py 에 다음과 같은 변수를 정의했다고 치자.

SLACKBOT_TOKEN = os.environ.get("SLACKBOT_TOKEN", "")SLACKBOT_CHANNEL = os.environ.get("SLACKBOT_CHANNEL", "")

app 이나 장고 코드 어디선가 이 상수 변수를 쓰고 싶다면 다음과 같이 사용하면 된다.

from django.conf import settingsSLACKBOT_TOKEN = getattr(settings, "SLACKBOT_TOKEN", "")print(SLACKBOT_TOKEN)
  • getattr() 안쓰고 그냥 settings.SLACKBOT_TOKEN 해도 되는 것 아닌가? => 되는 것 같다. 😁

참고 사이트

  • 예제는 아래 글에서 가져왔어요. 감사합니다. 👍
[
Django2, settings.py에 설정한 변수를 APP에서 사용하는 방법`
`
settings.py에 설정한 변수를 APP에서 사용하는 방법 Django 프로그램을 작성하다보면 특정 변수를 모든 app 에서 사용하면 좋은 경우가 생긴다. 이런 경우에, settings.py에 변수를 설정하면 원하는 곳에서 불러서 사용할 수 있다. 먼저, settings.py 에 사용하고자 하는 변수(GATHER_INTERVAL)를 넣는다. set…`
```
`
![](assets/images/2023/02/blank.jpg?ssl=1)`
`](https://blog.boxcorea.com/wp/archives/2692)`
`

Django – slack bot 에 메시지 전송

장고 혹은 파이썬에서 슬랙봇으로 메시지를 보내는 것을 해보자.

용도는 엄청 다양하다. 일단은 장고 동작 중에 admin에게 알리는 메시지를 이메일로 처리하곤 했는데 이놈의 smtp 가 참 여기저기 문제다.

그냥 Slack 을 믿고 slack message로 처리하도록 해보자. 아래 글을 참고하면 아주 쉽게 메시지를 보낼 수 있다.

[
slacker.Error: invalid_auth 에러 해결방법`
`
안녕하세요 유튜버 조코딩입니다. 제 채널의 크레온 API를 활용한 파이썬 주식 투자 자동화 강의 들으시는 분들 중 slacker를 이용하실 때 2021년2월24일 이후 invalid_auth에러가 떠서 진행이 안되시는 분들이 있..`
```
`
![](https://img1.daumcdn.net/thumb/R800x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpcuCE%2FbtqZrfD0HqW%2FwI3V1MT6fHs35LEXP8RK9K%2Fimg.png)`
`](https://developerdk.tistory.com/96)`
`- 아무것도 필요 없고, 접속 토큰과 requests 모듈이면 충분한다. - bearer token에 슬랙봇 토큰 정보를 사용하면 된다. - data={“channel”: channel,”text”: text} 이 형태로 보내면 끝

Django – modal 창에 form error 출력

Django model forms (https://github.com/trco/django-bootstrap-modal-forms/blob/master/README.rst) 이용하고 있는데, 모달 창이 뜬 상태에서 form submit 을 수행하고, 에러가 발생하면 해당 모달창에 바로 띄워주고 싶어서 시도!

원래 제공되는 기능인데, 그냥 쓴 방법을 정리해 둔다.

모달창 템플릿 코드는 아래와 유사하게 되어 있다. 여기서 div class=”invalid” 부분이 중요하다. 여기서 class invalid 부분을 빼 버리면, 모달창에 표시되는게 아니라 전체 페이지가 모달 창을 띄우는 페이지로 바뀌어 버려 브라우저 전체에 모달창 템플릿만 표기되는 문제가 있다.

&lt;div class="modal-body"&gt;
        &lt;div class="invalid mb-2"&gt;
```text
          {% for error in form.non_field_errors %}
          <p class="help-block text-sm text-danger mb-2">{{ error }}</p>
          {% endfor %}
    &lt;/div&gt;
        {% for field in form %}
    &lt;div class="row mb-1 align-middle"&gt;
      &lt;div class="col-3"&gt;
            <div class="text-sm text-right" for="{{ field.id_for_label }}">{{ field.label }}</div>
      &lt;/div&gt;
      &lt;div class="col-auto"&gt;
            {{field}}
            <div class="{% if field.errors %}invalid{% endif %}">
              {% for error in field.errors %}
                <p class="help-block text-sm text-danger mb-2">{{ error }}</p>
              {% endfor %}
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
        {% endfor %}

</div>


설명이 어려워서 그림으로 남겨둔다.

<figure class="wp-block-image">![](assets/images/2023/02/3_image-1.png?ssl=1)`</figure>`이렇게 표기되기를 원하는데, 빨간색 표기는 &lt;p&gt; 태그에 의해서 표기되는 것이라 div class invalid 를 빼고 실행했더니, 쩝 모달창이 사라지고 전체페이지를 잡아 먹는 모양새가 되버리네. class css 에 먼가가 정리되어 있나 보다.

<figure class="wp-block-image">![](assets/images/2023/02/image-2.png?ssl=1)`</figure>`일단 그럼 에러를 띄워주는 부분의 코드는 아래를 참고

class ShippingProductUpdateForm(BSModalModelForm):
title = ""
# update_firmware_version = forms.CharField(label=_(“업데이트버전”), widget=forms.TextInput(attrs={“readonly”: True}))

class Meta:
    model = ShippingProduct
    # fields = ["product", "serial", "status", "version", "update_firmware_version", "date_shipping", "shipping_company"]
    fields = ["product", "serial", "status", "date_shipping", "shipping_company"]
    labels = {
        "shipping_company": _("출고회사"),
        "product": _("*상품"),
        "serial": _("*시리얼"),
        "status": _("*상태"),
        "date_shipping": _("*출고일"),
    }
    widgets = {
        "shipping_company": forms.Select(attrs={"class": ""}),
        "product": forms.Select(attrs={"class": "", "placeholder": "상품"}),
        "serial": forms.TextInput(attrs={"class": ""}),
        "status": forms.Select(attrs={"class": ""}),
        "date_shipping": forms.DateInput(attrs={"type": "date", "required": True}),
    }

def __init__(self, *args, **kwargs):
    super().__init__(*args, **kwargs)
    print("ShippingProductUpdateForm init", self.request.user.profile.level, self.request.user.profile.company)
    self.title = "출고상품 수정"
    self.fields["product"].queryset = Product.objects.filter(company_id=self.request.user.profile.company, is_deleted=0)
    # if self.instance.update_firmware:
    #     self.fields["update_firmware_version"].initial = self.instance.update_firmware.version
    # else:
    #     self.fields["update_firmware_version"].initial = "No update"
    if self.request.user.is_superuser:
        self.fields["product"].label_from_instance = lambda obj: "%s (%s)" % (obj.name, obj.company.name)

def clean(self):
    cd = self.cleaned_data
    print("ShippingProductUpdateForm", cd)
# 에러발생 시키기 예제
    raise ValidationError(
        _("첨부파일을 입력하세요: %(value)s"),
        code="invalid",
        params={"value": cd.get("product")},
    )
    # return cd

- clean 부분에 강제로 에러를 띄워 줬더니 잘 동작하는 것을 확인했다.

그리고, form submit 할 때 Validation check 를 미리 하지 않고 view, form function 에서 걸러내고 싶다면, 템플릿에서 아래와 같은 키워드를 submit 부분에 추가해 준다. `formnovalidate="formnovalidate"`

Edit page
Share this post on:

Previous Post
PostgreSQL 실전 노트
Next Post
개발 기타 노트