Application/Python-Django

Django 에어비앤비 클론 2부 (21.03.16 ~ 04.05)

winney916 2021. 3. 22. 19:55
728x90

 

Chapter 9 : Custom commands and seegind [03/16]

 

- manage.py commands

음... python manage.py 에서 사용될 명령어들을 직접 만들었다. 이유는, 테스트 케이스나 특정 데이터들을 입력하는데 admin창에서 직접 하나하나 치는게 번거롭기 때문이다. 이 커맨드를 만들어 놓으면 커맨드를 통해서 데이터를 입력할 수 있다. 즉, "프로그래머" 다워지는 것이다. 방법은

1) 하나의 앱에서 management/commands/ 디렉토리를 만든다.

2) 이 안에 python 파일을 생성한다.

3) Command 클래스를 정의하고, from django.core.management.base import BaseCommand 를 상속시킨다.

4) 그 안에서 잘 정의시킨 뒤 터미널에서 사용하면 끝~

- Use custom SEED! [03/17]

seed 는 django의 서드파티인데, 페이크 데이터를 만들기 위해서 사용한다. 깃허브 문서를 참조하여 다운받은 뒤, config/setting.py의 thirdy_party 리스트에 추가를 해준다. 추가를 한 뒤에, custom command를 하면서 사용해주면 된다. 사용법은 아직 익지 않았지만,, 뭐 언젠가 하겠지?...

- 계속 시드 만들기 [03/18]

created = seeder.execute()
cleaned = flatten(list(created.values()))
for pk in cleaned:
    list_model = list_models.List.objects.get(pk=pk)
    to_add = rooms[random.randint(0, 5) : random.randint(6, 30)]
    list_model.rooms.add(*to_add)

이 부분이 조금 흥미롭다. seeder.add_entity를 통해서 seeder를 설계한 후, 실행을 해 주는데 이 때 execute함수는 생성된 데이터의 id로 이루어진 리스트를 반환한다. 이렇게 반환된 리스트는 manytomany필드의 값들을 연결하는 데 활용할 수 있다.

 

Chapter 10 : Introduction to urls and views [03/22]

- url & view

 view에서는 각각의 model에서 필요한 data를 가져와 render를 return한다. 이 view를 url에서 특정 주소에 path형태로 지정해주면 연결이 완성된다. name과 namespace라던지 더 어려운 내용이 있어보이지만 다음에 알려준다는 식으로 넘어갔다.

 

- templates

 이건 예전에 야매로 장고 어플리케이션을 만들면서 경험해본 기능이다. 하나의 html파일에 block을 만들고, 이 block을 다른 html파일에서 상속해 사용하는 기능이다. 이 외에도 include라는 기능을 사용해서, 블록 내부에서 부분적으로 적용하는 것이 아닌 하나의 html 파일 ( 대체로 partial 한 파일들)을 적용시킬 수 있다.

 

* 문제가 생겼다.

 vscode에서 extentions으로 prettier라는 formmater를 쓰고 있는데, 이 친구가 자꾸 django 문법을 무시한다. 이를 어찌 해결하면 좋을까... 고민이 필요한 시점이다.

 

Chapter 11 : Home View [03/23, 24]

- pagination을 만들기

 장고 템플릿에서는 로직을 작성하는걸 엄격하게 제한한다. 때문에 모든 로직은 views.py에서 작성하고, 이를 변수로 가져온다. 그럼에도 부분적으로 사용할 수 있는 로직이 있는데, -> built-in template and tags 이다. 아직 정확한 사용법은 잘 모르겠지만, {{}} 내에 작성하는 변수 뒤에 | 를 붙이고, add 등의 built-in filter reference를 사용하면 된다.

 

- pagination with django

 장고 내부에 pagination이라는 클래스가 있다. 이를 잘 활용하면 위에서 수동적으로 작성했던 바를 다소 쉽게 작성할 수 있다.

 

- 최고의 pagination

 장고의 class based view를 사용하면 된다. 이건 거의 자동화된 수준이다. 프로그래밍이라기 보다는 추상화된 개념들을 조립해주는 형태라고 생각한다. 기존의 방법에서 사용하던 render, request등의 방식들이 모두 불필요해지는걸 확인할 수 있다. 참고자료는 (ccbv.co.uk/

 

원래는 더 자세하게 적었으나.. 한번 저장안하고 껐더니 다 날아감.. 아무튼 장고 view를 작성하는 방법에는 class based view 와 functional programming이 있는데, 니꼬쌤을 이 두가지를 동시에 다룬다고 하셨다. (코드상의 비중은 CBV가 더 높음) functional을 진행해봐야만 장고가 어떻게 동작하는지 잘 이해할 수 있다고 했다.

 

+) fucntional programming은 render함수를 기반으로 모든 변수를 직접 설계하는 반면, class based view는 추상화가 많이 되어있다. 그덕에 document를 참조하면서 작성하면 코드의 수를 현저히 줄일 수 있다.

 

Chapter 12 : Detail View [03/25, 26]

 url의 형태는 기본적으로 config/urls.py -> app/urls.py + app/views.py -> template 방향으로 진행된다. config내에 있는 파일에서 먼저 어플리케이션에 범주를 나눠서 어플리케이션들의 urls.py로 보내게 된다. 이 어플리케이션들은 각각의 앱들이원하는 arguments들을 받은 후, view.py에서 DB를 활용하여 작성한 코드들과 함께 template으로 가게된다. 

 template(html파일)에서 href같은 속성을 넣어줄 때, 일반적으로 사용하는 절대경로 표기를 통해서 이동할 수 있지만, 장고에서는 이를

href = "{% url " namespace : name " arguments %}"

형태로 작성할 수 있다. namespace는 config/urls.py에 작성된 path를 말하고, name은 이 path에서 이동한 app/urls.py 에 있는 path를 의미한다. 뒤에 보내는 arguments는 template으로 넘어올 때, 해당 app의 views.py에서 정의된 것이어야 한다.

 

- get_absolute_url

  : 내가 원하는 model을 찾을 수 있는 방법이다. models.py에 이 함수를 정의해주면된다.(사실은 오버라이드) 

    def get_absolute_url(self):
        return reverse("rooms:detail", kwargs={"pk": self.pk})

 사실 아직 정확한 내용은 잘 모르겠다.

 

- Exception Control

 : 404에러같은 상황을 처리하는 방법이다. try-except 문법을 활용하는데, return render를 통해서 고정된 페이지로 이동시켜주는 방법이 있고 (이때 url 형식을 템플릿에서 사용한 것 처럼 사용하고 싶다면 reserve를 이용하라.), Http404에러 페이지로 이동시킬 수 있다. -> django.http.Http404() 메서드 사용

 이 메서드의 장점 중 하나가, 에러 페이지를 커스텀 할 수 있다는 점이다. 커스텀 할 경우에는 별도의 루트를 설정해주지 않는다. templates/404.html로 생성하면 된다.

 

Chapter 13 : Search View [03/29, 30, 31, 04/01]

 계속해서 연결한다. urls.py -> views.py -> template.

 재밌었던 트릭 하나는 block을 이용하는 방법인데, base.html에서 특정 블럭 내부에 components를 작성해 놓은 뒤, 다른 html파일에서 이 block을 작성한 후, 내부를 비워놓으면, 크 컴포넌트들이 사라진다는 점이였다. 은근히 써먹을만한 트릭이다.

 

 - request.GET

 request는 url을 통해서 전달하는 인자를 받아내는 일을 하는데, 다양한 메서드가 있다. 보통은 get을 통해서 하나의 인자를 가져오지만, 같은 이름의 인자에 여러개의 값이 할당됐다면 getlist 메서드를 사용해야만 list형태로 모든 값을 받을 수 있다.

 

 - 신기한 문법 | filter

 변수 | slugify 를 했더니 문자열로 바뀌었다. 정확히는 아스키로 바꿔주는 기능을 하는데, django template 에서 사용했다. 파이썬 문법인지 장고 문법인지 헷갈리기 시작했다. ....

 

 - Filtering

 view와 template의 상호작용을 이용해서 filter를 만들었다. filter_args를 딕셔너리 구조로 만들어서 model의 object에 filter 인자로 추가해준 뒤  render하면 된다. args는 각각의 field에 맞춰서 조건을 걸어주면 된다.

filter_args = {}

    rooms = models.Room.objects.filter(**filter_args)

 

 좋은 트릭 하나는, 체크박스를 이용할 때 True가 아닌 on값이 return되는데, 이 값 전체에 bool이라는 메서드를 씌워주면 True로 변형된다.

 

  - Form.py

   : 위의 과정을 굉장히 단순하게 처리할 수 있는 방법이다. 기존의 view와 template의 상호작용으로 프론트엔드를 만들던 방식과 달리, 각각의 변수들을 하나의 material처럼 처리하는 방식이다.

    form을 작성하는 방법은 models.py와 굉장히 유사하다.

from django import forms
from . import models

class SearchForm(forms.Form):

    city = forms.CharField(initial="Anywhere")

 이런 형태로 각각의 field를 정의해준 뒤, template에서는 {{form}} 형태로 작성해준다. view에서는 기존의 방법과 유사하게 request와 상호작용 할 수 있다.

 

[04/01] 아니 오늘 왜이러는지 모르겠네. 부대에 일이 많았던 주인지라 굉장히 지쳤던건 이해하겠는데, 기껏 적어놨던 내용 저장 안누르고 꺼서 다 날아가고.. 4일동안 1개 챕터 겨우 끝내고.. 내가 이정도밖에 안되던 인간이였나 자괴감 들고 괴로워 ㅠㅜㅠㅜㅠㅜ 열심히 하자 더 열심히!

 

Chapter14 : User login & log out [04/02, 03, 05]

- View.py 작성법 정리 : class based view VS function based view

from django.views import View


class LoginView(View):
    def get(self, request):
        pass

    def past(self, request):
        pass


def login_view(request):
    if request.method == "GET":
        pass
    elif request.method == "P":

 아직 장고를 많이 사용해보지 많아서 구체적으로 어떤 차이가 있는지는 잘 모르겠다.

 

 +) 장고에서 자꾸 고장하는 너! prettier!!!

  : Django template에서는 prettier가 마음에 들지 않는다. 자꾸만 장고 문법을 무시하면서 코드를 축약시켜버린다. 이럴 때 사용할 수 있는 방법이 있다! 

.prettierignore 파일을 만들면 된다. 마치 .gitignore파일을 만들듯이. 그리고 저 안에 프리티어가 작동하지 않았으면 하는 루트를 한줄 한줄 넣어주면 된다. 

 아 역시나 너무 사랑스러운 VS CODE

 

 

 +) CSRF (Cross-Site Request Forgery) : 사이트 간 요청 위조

 : 브라우저가 이동할 때 쿠키를 전달하는데, 이 ...건 더 공부해보자

 

  - Validating : 로그인 구현

  : forms.py에서 validation을 구현할 수 있다. 기본적인 메서드의 형태는

def clean_something(self):
	
    return ""

 이런 형태여야하며, something에는 검사하고자 하는 변수의 이름이 들어간다. self를 상속하지만, form 클래스 내부에 정의된 데이터를 가져올 때는 self.something이 아닌 self.cleaned_data.get("something")으로, cleaned_data에 우선 접근해야한다.

 try-except 문으로 에러를 발생시킬 수 있으며, 그 에러의 발생 여부를 views.py에서 확인할 때에는 form.is_valid() 메서드를 사용해주면 된다. 

 

forms.py

    def clean_email(self):
        email = self.cleaned_data.get("email")
        try:
            models.User.objects.get(username=email)
            return email
        except models.User.DoesNotExist:
            raise forms.ValidationError("User does not exist")

 

views.py

    def post(self, request):
        form = forms.LoginForm(request.POST)
        if form.is_valid():
            print(form.cleaned_data)

        return render(request, "users/login.html", {"form": form})

  - 다중 validation(?)

  : 위의 forms.py를 보면 email에 대한 validation만 진행하고 있는걸 볼 수 있다. validation을 해야하는 변수가 여러개라면 저런 형태의 함수를 여러개 작성해야한다. -> 비효율적

  하나의 validation함수에서 여러개의 변수를 검사할 수 없을까?

    def clean(self):
        email = self.cleaned_data.get("email")
        password = self.cleaned_data.get("password")
        try:
            user = models.User.objects.get(email=email)
            if user.check_password(password):
                return self.cleaned_data
            else:
                self.add_error("password", forms.ValidationError("Password is wrong"))
        except models.User.DoesNotExist:
            self.add_error("email", forms.ValidationError("User does not exist"))

그렇게 진행하고 싶을 때, 함수의 이름은 clean이 되어야한다. 그리고 raise로 에러를 생성하는게 아니라 self.add_error라는 메서드를 이용해준다.

 

  - Context processor

 

  - authentication view

  : 위에서 했던 작업들을 단순하게 할 수 있는 패키지다. 여기서 LoginView를 사용하면 꽤나 간편하게 구현할 수 있다. (구체적인 방법들이 점점 어려워진다. 챌린지 하다보면 알게되겠지...?)