본문 바로가기

About coding/Today I learned

2023년 04월 20일 TIL [#Django 심화 #포스트맨 #django데이터 저장, 가져오기 문법]

 

 


오늘의 학습 계획

_권기현 튜터님 거북이반 django 기초 복습

_vs코드로 넘어가기. vs코드 django 세팅법 숙지

_스파르타 장고심화 drf 수강하며 강좌별 배운 내용 적기


기록하고 싶은 학습내용

_이스케이프처리란: 특수문자를 HTML에서 사용하는 기호로 변환하는 것을 말한다. <, &, ' , " 등 기호를 그대로 출력하면 태그나 코드가 시작되어버리기 때문에 이스케이프 처리를 필요로 한다. 또한 이스케이프 처리는 보안상의 이유로 필요하다고 함. 웹사이트에서 작성자가 인풋할 수 있는 공간이 주어질 때, 코딩 배경지식이 있는 작성자가 입력부에 코드를 삽입하면 해킹이 가능한 이유 때문인 것 같다.

장고 템플릿 공식 문서를 구경하고 있는데, django에서의 이스케이프 처리는 아래와 같다.

{% autoescape on %}
    {{ body }}
{% endautoescape %}

 

_CSRF란: Cross Site Request Forgery protection. 

 

_장고에서 추천하는 일반적인 템플릿 상속 활용 방법

  • base.html사이트의 기본 모양과 느낌을 유지하는 템플릿을 만듭니다 .
  • base_SECTIONNAME.html사이트의 각 "섹션"에 대한 템플릿을 만듭니다 . 예를 들어, base_news.html, base_sports.html. 이러한 템플릿은 모두 base.html섹션별 스타일/디자인을 확장하고 포함합니다.
  • 뉴스 기사 또는 블로그 항목과 같은 각 페이지 유형에 대한 개별 템플릿을 만듭니다. 이러한 템플릿은 적절한 섹션 템플릿을 확장합니다.

_django에서 템플릿 상속:

{% extends 엄마템플릿.html %} 이걸 자식 템플릿의 맨 윗줄에 쓰고, 엄마템플릿과 자식 템플릿에 각각

변화를 주고 받을 "그 부분"을 블록으로 감싸 놓는다. 엄마 템플릿에선 빈 자리 혹은 디폴트 모양으로 둘 그 부분일 것이고,

자식 템플릿 입장에선, 내가 색다르게 표현할 "그 부분"이 된다. 나머지는 상속 받은대로 엄마템플릿의 모양을 따른다.

{% block <식별 이름> %} , {% endblock %} 이것들로 "그 부분"을 감싸면 됨.

 

_스파르타 장고 심화 강의 수강

더보기

1-1

: OT 학습목차설명

1-2

:OT 학습목차설명

1-3

:바닐라 뜻(부가적인 편의기능이나 화려한 UI없이 본연의 기능만 사용한 코드)

1-4

:포스트맨 사용법

다운로드 > 좌상단 워크스페이스 > 퍼스널 > 콜렉션 만들기 > 이름 만들고 > add a request > 리퀘스트이름 지정 > 요청 종류 선택 > 요청할 주소 입력 > Send > 돌아온 리스폰스가 아래에 뜸 바디,쿠키,헤더, 테스트결과 > 바디에는 html이 잔뜩 돌아오고. DevTool 내용과 같음 > 우중단 status:200 Time:80s Size:205.04KB 이런거 나옴 > 하단에 Console 누르면 내가 보낸 요청과 거기에 실린 Network 정보, Request Headers 정보, Response Headers 정보, Response Body 정보 이런거 나옴 > 

 

_이창호 튜터님 강의자료 보관

이전 강의

더보기

django / database 용어 정리

  • RDBMS(RDB) : Relational DataBase Management system의 약자로 MySql, OracleDB 등 관계형 데이터베이스를 지칭한다.
  • Sql : Structured Query Language의 약자로 데이터베이스의 CRUD를 위해 사용되는 언어이다.
    • CRUD : Create(생성), Read(읽기), Update(갱신), Delete(삭제)
  • NoSql : Not Only Sql의 약자로 관계형 데이터베이스가 아닌 다른 형태로 데이터를 저장하며, mongoDB 등이 여기에 해당한다.
  • Table : DB는 기본적으로 테이블로 이루어져 있으며, 필드와 레코드가 존재한다.
  • # models.py # User 테이블 class User(models.Model): # username 필드 username = models.CharField("사용자 계정", max_length=50, primary_key=True) # password 필드 password = models.CharField("비밀번호", max_length=200, unique=True) # User라는 테이블에 username, password라는 필드가 존재함 # 사용자가 회원가입을 할 때마다 레코드가 하나씩 추가됨. # 레코드는 row 혹은 튜플 이라고도 불리며 django에서는 object, instance라고도 불린다. # 즉, 레코드란 데이터베이스에 저장 되는 값들을 지칭하는 것
  • 데이터베이스 키 종류
    • FK : Foreign Key의 약자이며, 다른 테이블을 참조 할 때 사용된다.
    • UK : Unique Key의 약자이며, 중복 값을 허용하지 않는다.
    • PK : Primary Key의 약자이며, 테이블에서는 반드시 한개의 PK가 존재해야 한다.
      • PK는 두개 이상 존재 할 수 없고, UK와 마찬가지로 중복 값을 허용하지 않는다.
      • Foreign Key를 사용할 경우 참조 할 테이블의 PK를 바라본다.
  • http method 종류
    • request를 보낼 때 어떤 용도의 요청을 보낼 지 선택하며, CRUD와 1:1 매칭됩니다.
    • GET : 데이터 조회(Read)
    • POST : 데이터 생성(Create)
    • PUT : 데이터 수정(Update)
    • DELETE : 데이터 삭제(Delete)

django 프로젝트 구조

  • settings.py
    • django 프로젝트를 실행 할 때 해당 파일을 참조한다.
    • 데이터베이스 설정, 앱 설정, 기본 정책 설정 등을 할 수 있다.
  • models.py
    • DB에 테이블을 추가하고 관리 할 때 사용된다.
    • 테이블에 들어갈 필드, 필드의 속성값 등을 설정 할 수 있다.
    • python manage.py makemigrations / migrate 명령어를 통해 설정을 DB에 반영시킬 수 있다.
  • views.py
    • django 에서 request 데이터를 받은 후 처리 할 전반적인 로직이 들어간다.
    • urls.py에서 views에 있는 class나 함수를 호출해서 사용하게 된다.
  • urls.py
    • 웹에서 django 프로젝트로 request를 전달 할 때 받아줄 경로를 설정할 수 있다.

모델링 할 때 자주 사용되는 field

  • 시간
    • DateField
      • 날짜를 입력하는 필드 ex) 2002-01-01
    • TimeField
      • 시간을 입력하는 필드 ex) 09:31
    • DateTimeField
      • 날짜, 시간을 입력하는 필드 ex) 2002-01-01 09:31
    • 옵션(공통)
      • [선택] auto_now_add : True일 경우 데이터가 생성되는 순간을 기록한다. 데이터가 최초 생성되는 시간과 일치한다.
      • [선택] auto_now : True일 경우 데이터가 저장될 때마다 갱신되며, 데이터 최초 생성 일 혹은 수정 시간이 기록된다.
  • 문자
    • CharField
      • 문자열을 입력하는 필드 ex) 게시글 제목입니다.
      • 옵션
        • [필수] max_length : 입력 할 수 있는 최대 문자 수를 지정한다.
        • [선택] choices : 특정 값만 입력될 수 있도록 선택지를 설정한다.
    • TextField
      • 개행 가능한 문자열을 입력하는 필드 ex) 게시글 내용입니다.
  • 숫자
    • IntegerField
      • 숫자를 입력하는 필드 ex) -100, 100
    • PositiveIntegerField
      • 양수를 입력하는 필드 ex) 100
  • 외래 키
    • ForeignKey
      • 1:n 혹은 n:1 관계 ex) 게시글의 작성자(User)를 나타내는 필드
      • 옵션
        • [필수] to : 관계를 맺을 테이블을 입력 ex) user.User
        • [필수] on_delete : 관계를 맺을 데이터가 삭제됐을 때 해당 데이터의 처리 방법을 입력
          • CASCADE : 해당 데이터도 같이 삭제합니다.
          • SET_NULL : 해당 필드의 값을 null(None)로 설정합니다. 해당 옵션 선택 시 null=True 옵션을 설정해 줘야 합니다.
    • OneToOneField
      • 1:1 관계, ForeignKey(Unique=True)와 동일하다. ex) 사용자(User)와 사용자 개인정보(UserPrivateData)를 나타내는 필드
      • 옵션 : ForeignKey와 동일
    • ManyToManyField
      • n:n 관계, 중간 테이블이 생성된다. ex) 사용자(User)와 취미(Hobby)를 나타내는 필드
  • 기타
    • FileField
      • 파일을 업로드 하는 필드 ex) image.png
    • BooleanField
      • True 혹은 False를 저장하는 필드
  • 공통 옵션
    • [선택] verbose_name : 해당 필드의 별칭을 지정한다.
    • [선택] default : 해당 필드의 값을 지정하지 않았을 때 기본적으로 설정할 값을 입력한다.
    • [선택] blank : 비어있는 스트링(””) 허용 여부를 지정한다.
    • [선텍] null : null(None) 허용 여부를 지정한다.

custom user model 생성하기

  • models.py
  • from django.db import models from django.contrib.auth.models import BaseUserManager, AbstractBaseUser # custom user model 사용 시 UserManager 클래스와 create_user, create_superuser 함수가 정의되어 있어야 함 class UserManager(BaseUserManager): def create_user(self, username, password=None): if not username: raise ValueError('Users must have an username') user = self.model( username=username, ) user.set_password(password) user.save(using=self._db) return user # python manage.py createsuperuser 사용 시 해당 함수가 사용됨 def create_superuser(self, username, password=None): user = self.create_user( username=username, password=password ) user.is_admin = True user.save(using=self._db) return user class User(AbstractBaseUser): username = models.CharField("사용자 계정", max_length=20, unique=True) email = models.EmailField("이메일 주소", max_length=100) password = models.CharField("비밀번호", max_length=128) fullname = models.CharField("이름", max_length=20) join_date = models.DateTimeField("가입일", auto_now_add=True) # is_active가 False일 경우 계정이 비활성화됨 is_active = models.BooleanField(default=True) # is_staff에서 해당 값 사용 is_admin = models.BooleanField(default=False) # id로 사용 할 필드 지정. # 로그인 시 USERNAME_FIELD에 설정 된 필드와 password가 사용된다. USERNAME_FIELD = 'username' # user를 생성할 때 입력받은 필드 지정 REQUIRED_FIELDS = [] objects = UserManager() # custom user 생성 시 필요 def __str__(self): return self.username # 로그인 사용자의 특정 테이블의 crud 권한을 설정, perm table의 crud 권한이 들어간다. # admin일 경우 항상 True, 비활성 사용자(is_active=False)의 경우 항상 False def has_perm(self, perm, obj=None): return True # 로그인 사용자의 특정 app에 접근 가능 여부를 설정, app_label에는 app 이름이 들어간다. # admin일 경우 항상 True, 비활성 사용자(is_active=False)의 경우 항상 False def has_module_perms(self, app_label): return True # admin 권한 설정 @property def is_staff(self): return self.is_admin
  • settings.py
  • AUTH_USER_MODEL = 'user.User' # app.table 형태
  • admin.py
  • from django.contrib.auth.admin import UserAdmin as BaseUserAdmin class UserAdmin(BaseUserAdmin): list_display = ('id', 'username', 'fullname', 'email') list_display_links = ('username', ) list_filter = ('username', ) search_fields = ('username', 'email', ) fieldsets = ( ("info", {'fields': ('username', 'password', 'email', 'fullname', 'join_date',)}), ('Permissions', {'fields': ('is_admin', 'is_active', )}),) filter_horizontal = [] def get_readonly_fields(self, request, obj=None): if obj: return ('username', 'join_date', ) else: return ('join_date', )

migrate를 하는 과정에서 django.db.migrations.exceptions.InconsistentMigrationHistory: Migration admin.0001_initial is applied before its dependency user.0001_initial on database 'default'.와 같은 에러가 발생 할 경우 링크 참고

오늘 강의

더보기

python class 관련 용어 및 클래스 상속 구조 정리

# A 클래스
class A:
    # init 메소드(혹은 함수)
    def __init__(self, ):
        # init 메소드는 인스턴스(혹은 오브젝트)가 생성될 때 실행된다.
        print("A 클래스의 init 메소드가 실행됐습니다!")

    # A 클래스의 hi 메소드(혹은 클래스 함수)
    def hi(self, ):
        print("hello A!!")

class B(A):
    # B 클래스는 A 클래스를 상속 받았다.
    # A 클래스는 B 클래스의 부모(혹은 슈퍼) 클래스이다.
    # B 클래스는 A 클래스의 자식(혹은 서브) 클래스이다.

    # A 클래스의 init 메소드를 overriding
    def __init__(self, ):
        # super(부모) 클래스의 __init__ 메소드 실행
        super().__init__()
        print("B 클래스의 init 메소드가 실행됐습니다!")

class C(A):

    # A 클래스의 hi 메소드를 overriding
    def hi(self, ):
        # super 함수는 호출 해도 되고 호출하지 않아도 된다.
        # super().hi()
        print("hello C!!")

class D:
    pass

# b 오브젝트(혹은 B 클래스의 인스턴스) 생성
b = B()  # 오브젝트가 생성되며 overriding 된 B 클래스의 __init__ 메소드가 실행 됨
b.hi()  # 부모 클래스인 A 클래스의 hi() 메소드가 실행 됨

# c 오브젝트 생성
c = C()  # 오브젝트가 생성되며 부모 클래스인 A 클래스의 __init__ 메소드가 실행 됨
c.hi()  # overriding 된 C 클래스의 hi 메소드가 실행 됨

# d 오브젝트 생성
d = D()  # __init__ 메소드가 정의되지 않았기 때문에 아무것도 실행되지 않음

패킹과 언패킹(*args, **kwargs) 복습

  • 패킹과 언패킹이란?
  • 패킹(packing)과 언패킹(unpacking)은 단어의 뜻 그대로 요소들을 묶어주거나 풀어주는 것을 의미합니다. list 혹은 dictionary의 값을 함수에 입력할 때 주로 사용됩니다.
  • list에서의 활용
  • def add(*args): result = 0 for i in args: result += i return result numbers = [1, 2, 3, 4] print(add(*numbers)) """ 아래 코드와 동일 print(add(1, 2, 3, 4)) """ # result output """ 10 """
  • dictionary에서의 활용
  • def set_profile(**kwargs): profile = {} profile["name"] = kwargs.get("name", "-") profile["gender"] = kwargs.get("gender", "-") profile["birthday"] = kwargs.get("birthday", "-") profile["age"] = kwargs.get("age", "-") profile["phone"] = kwargs.get("phone", "-") profile["email"] = kwargs.get("email", "-") return profile user_profile = { "name": "lee", "gender": "man", "age": 32, "birthday": "01/01", "email": "python@sparta.com", } print(set_profile(**user_profile)) """ 아래 코드와 동일 profile = set_profile( name="lee", gender="man", age=32, birthday="01/01", email="python@sparta.com", ) """ # result print """ { 'name': 'lee', 'gender': 'man', 'birthday': '01/01', 'age': 32, 'phone': '-', 'email': 'python@sparta.com' } """

장고에서 자주 사용되는 코드

  • 데이터 저장하기
  • """ 특정 object 생성하기 """ # case 1 Model.objects.create(title="제목", content="내용") # 데이터를 입력함과 동시에 저장 # case 2 obj = Model() obj.title = "제목" obj.content = "내용" obj.save() # 데이터 입력 후 따로 저장 # case 3 article = Article.objects.create(title="제목", content="내용") # 데이터를 저장하며 해당 object를 article이라는 변수에 저장 commant = Commant.objects.create(article=article, content="댓글")
  • 데이터베이스에서 원하는 데이터 찾기
  • """ 특정 object 가져오기 """ # objects.get에서 객체가 존재하지 않을 경우 DoesNotExist Exception 발생 try: Model.objects.get(id=obj_id) except Model.DoesNotExist: # some event return Response({"error": "존재하지 않는 오브젝트입니다."}, status=400) """ 특정 queryset 가져오기 """ Model.objects.filter(join_date="2023-01-01") # join_date 값이 2023-01-01인 데이터 검색 Model.objects.filter(join_date__lte="2023-01-01") # join date 값이 2023-01-01 이전인 데이터 검색 # lt : less than # lte : less than equal # gt : greater than # gte : greater than equal Model.objects.filter(title__contains="제목") # title에 "제목"을 포함하는 데이터 검색 Model.objects.filter(hobby__in=["운동", "산책"]) # hobby가 list에 포함되어 있는 데이터 검색 Model.objects.filter(fullname__startswith="이") # fullname이 "이"로 시작하는 데이터 검색 # startswith : ~로 시작하는 조건 # endswith : ~로 끝나는 조건 Model.objects.exclude(created_at__gte="2023-01-01") # created_at 값이 2023-01-01보다 크거나 같은 데이터를 제외 # filter : 특정 조건이 매칭되는 데이터를 남겨줌 # exclude : 특정 조건이 매칭되는 데이터를 제외함 """ 기존 검색 결과에서 추가로 필터링 혹은 제외하기 """ queryset = Model.objects.filter(title__contains="제목") # queryset 변수에 title에 "제목"을 포함하는 데이터 저장 queryset = queryset.objects.filter(created_at__gte="2023-01-01") # 기존 queryset 결과에 created_at 값이 2023-01-01보다 크거나 같은 데이터를 필터링 queryset = queryset.objects.exclude(is_active=False) # 기존 queryset 결과에 is_active 값이 False인 데이터를 제외 """ 2개 이상의 조건을 사용해 queryset 가져오기 """ Model.objects.filter(title__contains="제목", content__contains="내용") # title에 "제목"을 포함하고 content에 "내용"을 포함하는 데이터 검색 # from django.db.models import Q Model.objects.filter(Q(title__contains="제목") | content__contains="내용") # title에 "제목"을 포함하거나 content에 "내용"을 포함하는 데이터 검색 """ queryset 정렬하기 """ # .order_by("?")사용시 무작위 셔플 # -created_at처럼 "-"를 붙이면 역순으로 정렬 Model.objects.all().order_by("created_at") # created_at을 기준으로 졍렬 """ 조건에 맞는 object를 가져오거나 생성하기 """ # 입력한 object가 존재 할 경우 해당 object를 가져오고, 존재하지 않을 경우 새로 생성 obj, created = Model.objects.get_or_create( field1="value1", field2="value2", ) if created: # created event pass else: # already exist event pass
  • 데이터 수정하기
  • """ 특정 object 생성하기 """ obj = Model.objects.get(id=1) # id가 1번인 object를 obj 변수에 저장 obj.title = "변경 된 제목" # 해당 object의 제목 변경 obj.save() # 변경사항 적용

작은 질문과 해결

Q. {% block <식별 이름> %} {% end block %} 이런 템플릿 상속 코드의 예제와 활용방법 튜터님께 질문하기

    {% extends "블라블라.html" %} 이것도.

    템플릿 상속할 때, 엄마 템플릿과 자식 템플릿 모두, "상속하고 상속받을 그 부분"이 {% block %}으로 감싸져 있는 것

    같은데 내 이해가 맞는지.

> 맞다