Bookmark project - 1

[ Bookmark project ]

  1. 프로젝트 생성
  2. 장고 설치

    1
    $ pip install django
  3. 장고 프로젝트 생성

    1
    django-admin startproject config .
  4. DB 초기화

    1
    $ python manage.py migrate
  5. 관리자 계정 생성

    1
    $ python manage.py createsuperuser
  6. 기본 앱 생성

    1
    $ python manage.py startapp bookmark
  7. INSTALLED APPS에 ‘bookmark’ 앱 추가

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    # bookmark_project/config/setting.py

    INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'bookmark',
    ]

    # 템플릿 폴더를 검색, DB 변경 사항 추적
    # INSTALLED APPS에 추가된 앱들만 템플릿 폴더를 검색한다.
  8. Models.py 작성

    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
    # custom field
    # DB의 column = 데이터 타입, 제약조건

    # form.py
    # 입력받는 대상이 뭔가 특별할 경우 설계
    # DB에 저장되는 항목이 아닐 경우 ex) 회원가입 시, 패스워드 확인

    from django.db import models

    # 모델의 형태 - 클래스
    # models.Model을 상속받는 이유
    # 상속 : 어떤 클래스가 부모 클래스를 상속받는다.
    # ---> 부모 클래스가 가지고 잇는 메서드나 속성값을 사용하기 위해서
    # models.Model을 상속받은 이유?
    # models.Model이 가지고 있는 메서드나 속성값을 사용하기 위해서
    # models.Model: ORM 관련 기능들
    # ORM 관련 기능 : DB를 추상화해서 코드로 조작할 수 있게 하는 기능
    # 데이터를 추가, 수정, 검색, 삭제

    class Bookmark(models.Model):
    site_name = models.CharField(max_length=50)
    url = models.URLField()

    # 작성자 -> 로그인한 유저 정보를 찾아서 추가
    # 작성자 != 로그인한 유저다
    # -> 모델 저장 직전에 직접 코드로 처리

    # 작성일 -> 서버 시간을 읽어서 timestamp 값을 만들어 추가
    # 자동 옵션 auto_now(현재날짜로 갱신),auto_now_add(최초 저장시에만 현재날짜 적용)
    created = models.DateTimeField(auto_now_add=True)

    # DB에 적용 : makemigrations, migrate
    # $ python manage.py makemigrations bookmark
    # $ python manage.py migrate bookmark 0001

    # 관리자 페이지 목록에 표시될 내용
    # 확인 메시지에 출력되는 내용을 만들기 위해
    # __str__을 만들지 않으면 object라는 이름으로 뜸
    def __str__(self):
    return "Site name : "+self.site_name+", URL : "+self.url

    # 메타 클레스는 옵션 클래스 - 내가 상속을 받았는데, 속성값에 변경이 필요하다면
    class Meta:
    # ordering은 정렬을 의미
    # '필드이름' = 필드값 오름차순
    # '-필드이름' = 필드값 내림차순
    ordering = ['site_name']

    # 모델 클래스가 수정됐다고 해서 항상 migrate해야 하는 것은 아니다.
    # DB에 변경 사항이 반영이 되어야 할 항목들만 migrate를 한다.
  9. admin.py 작성

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    from django.contrib import admin

    # 관리자 페이지에서 관리할 모델을 등록
    # 관리자 페이지를 커스터마이징

    # 옵션 클래스를 만들어서 추가
    from .models import Bookmark

    admin.site.register(Bookmark)

    # admin 계정으로 접속 후, 데이터를 넣어보자.
  10. views.py 작성

    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
    # context processor 작성
    # 모든 페이지(템플릿 파일 전체)에 출력될 내용

    # custom template tag
    # -> 템플릿 엔진에서 지원하는 태그 외에, 개발자가 추가로 필요한 기능

    from django.shortcuts import render

    # 뷰 종류
    # 클래스형 뷰, 함수형 뷰는 서로 상호 기능 제약이 거의 없다.
    # => 클래스형 뷰는 함수형 뷰로, 함수형 뷰는 클래스형 뷰로 만들 수 있다.

    # 함수형
    # CRUDL에 특별한 처리를 추가해야 되는 경우
    # 함수형 뷰는 자유도가 클래스형 뷰에 비해서 높다.
    # def 뷰이름(request[, 추가 인수]):
    # 처리할 내용
    # 처리할 코드를 직접 다 개발자가 작성

    # 클래스형
    # CRUDL에 관련 기능은 자주 사용하기 때문에 장고에서 제네릭
    # 클래스형 뷰는 생산성이 함수형 뷰에 비해 높다.
    # class 뷰이름(제네릭뷰):
    # 처리할 내용
    # 제네릭 기능 외에 추가적인 기능을 개발자가 작성
    # 메서드 방식 - 커스터마이징에 관련된 메서드를 찾아야 한다.

    # CRUD_L
    from django.views.generic.list import ListView

    # 클래스형 뷰의 이름은 자유
    from .models import Bookmark

    from django.views.generic.edit import CreateView, UpdateView, DeleteView

    from django.views.generic.detail import DetailView

    class BookmarkList(ListView):
    model = Bookmark
    # _list
    # 나중에 반영할 옵션들
    # 템플릿 종류
    # 읽어오는 데이터
    # 페이지네이션을 걸거나
    # 검색 쿼리를 적용하거나
    # 권한 체크

    # 뷰를 만들었다면 URL 연결

    # CRUD -> 뷰를 만들고 URL 연결까지
    class BookmarkCreate(CreateView):
    model = Bookmark

    # fields는 사용자가 입력할 모델 필드를 정하는 것
    fields = ['site_name', 'url']
    template_name_suffix = '_create'
    # 템플릿 html 기본 이름을 변경할 수 있음
    # _form에서 _create로 이름 변경
    success_url = '/'
    # 추가, 수정, 삭제의 경우 해당 기능을 완료한 후에 이동할 페이지가 필요하다.
    # 1) success_url 이라는 속성값을 지정
    # 2) models에 get_absolute_url 이라는 메소드를 만드는 방법도 있다.

    class BookmarkUpdate(UpdateView):
    model = Bookmark
    fields = ['site_name', 'url']
    template_name_suffix = '_update'
    # _form에서 _update로 이름 변경
    success_url = '/'

    class BookmarkDelete(DeleteView):
    model = Bookmark
    template_name_suffix = '_delete'
    # _confirm_delete에서 _delete로 이름 변경
    success_url = '/'

    class BookmarkDetail(DetailView):
    model = Bookmark
    # _detail
  11. urls.py 작성

    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
    # bookmark/urls.py

    from django.urls import path

    from .views import BookmarkList, BookmarkCreate, BookmarkUpdate, BookmarkDelete, BookmarkDetail

    # app_name => namespace(이름 공간)
    # 다른 앱들과 url pattern 이름이 겹치는 것을 방지하기 위해서 사용
    # namespace라는 인수가 존재
    app_name = 'bookmark' # 앱 이름과 같지 않아도 된다.
    urlpatterns = [
    # path(url pattern, view, url pattern name), <- 콤마는 습관처럼 넣자
    # 함수형 뷰 : 이름만
    # 클래스형 뷰 : 이름.as_view()
    path('create/', BookmarkCreate.as_view(), name='create'),

    path('update/<int:pk>/', BookmarkUpdate.as_view(), name='update'),
    path('delete/<int:pk>/', BookmarkDelete.as_view(), name='delete'),
    path('detail/<int:pk>/', BookmarkDetail.as_view(), name='detail'),

    # [custom converter] => path, uuid, slug, int, str

    # ex) localhost/bookmark/1 => 글 보기, 수정, 삭제
    # ex) localhost/bookmark/create => 글 쓰기
    # 위 두 주소는 bookmark/<value>에 해당되어 구분이 되지 않는다.
    # bookmark/<int:value>처럼 int(converter)를 붙여줌으로써 구분할 수 있다.
    # 아무것도 붙이지 않을 경우, str이 된다.

    # int : 정수
    # str : 문자(default)
    # uuid : application 호출
    # slug : SEO로 인해 많이 사용 ex) why-so-serious처럼 '-'로 이어진 형태
    # path : 'bookmark/<path:value>/ ex) bookmark/19/04/29/
    # 위의 기본 converter를 제외한 형태가 필요하다면 custiom converter를 만든다.

    path('', BookmarkList.as_view(), name='index'),
    ]

    # config/urls.py

    from django.contrib import admin
    from django.urls import path, include # include 등록

    urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('bookmark.urls')), # 추가
    ]
  12. Templete 작성(분기)

    1
    2
    3
    <!--// block문 이용 //-->
    {% block [블록이름] %}
    {% endblock %}
    • bookmark_project/layout(폴더 생성)/base.html(‘base’라는 이름은 관례) 생성
    • config/settings.py에 TEMPLATES = [‘DIRS’: [os.path.join(BASE_DIR, ‘layout’)],] 추가

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      <!--// base.html //-->
      <!DOCTYPE html>
      <html lang="en">
      <head>
      <meta charset="UTF-8">
      <title>{% block title %}{% endblock %}</title>
      {% block extra_css %}
      {% endblock %}
      </head>
      <body>
      {% block content %}
      {% endblock %}

      {% block extra_script %}
      {% endblock %}
      </body>
      </html>
    • bookmark_project/bookmark/templates/bookmark에 html 생성

    • views.py에 설계한 class형 뷰 템플릿 파일 생성
    • base.html과 겹치는 부분 제거 후, block문으로 대체
    • C(Create) : 객체를 생성하는 곳
    • R(Read) : 단일 객체(object)
    • U(Update) : 단일 객체(object)
    • D(Delete) : 단일 객체(object)
    • L(List) : 복수 객체(object_list)
      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
      <!--// bookmark_list.html //-->
      {% extends 'base.html' %}

      {% block title %}
      Bookmark List
      {% endblock %}

      {% block content %}
      {# bookmark 목록 출력하기 #}
      {% for object in object_list %}
      <a href="{% url 'bookmark:detail' object.id %}">{{object.id}} {{object.site_name}}</a> <a href="{{object.url}}">{{object.url}}</a><br>
      {% endfor %}
      {% endblock %}


      <!--// bookmark_create.html //-->
      {% extends 'base.html' %}

      {% block title %}
      Bookmark Create
      {% endblock %}

      {% block content %}
      <form action="" method="post">
      {% csrf_token %}
      {{form.as_p}}
      <input type="submit" value="Create">
      </form>
      {% endblock %}


      <!--// bookmark_update.html //-->
      {% extends 'base.html' %}

      {% block title %}
      Bookmark Update
      {% endblock %}

      {% block content %}
      <form action="" method="post">
      {% csrf_token %}
      {{form.as_p}}
      <input type="submit" value="Update">
      </form>
      {% endblock %}


      <!--// bookmark_delete.html //-->
      {% extends 'base.html' %}

      {% block title %}
      Bookmark Delete
      {% endblock %}

      {% block content %}
      <form action="", method="post">
      {% csrf_token %}
      <input type="submit" value="Delete Ok">
      </form>
      {% endblock %}


      <!--// bookmark_detail.html //-->
      {% extends 'base.html' %}

      {% block title %}
      Bookmark Detail
      {% endblock %}
      <!--//
      url을 쓸 때 app name이 존재한다면
      즉, namespace가 있다면 namespace를 붙여줘야 한다.
      ex) bookmark:update //-->

      {% block content %}
      {{object.id}}<br>
      {{object.site_name}}<br>
      {{object.url}}<br>
      <a href="{{object.url}}">링크</a><br>
      <a href="{% url 'bookmark:update' object.id %}">수정</a><br>
      <a href="{% url 'bookmark:delete' object.id %}">삭제</a>
      {% endblock %}
Share