728x90

TODAY I LEARNED


장고 백엔드 스터디 학습차 인프런의 "작정하고 장고"강의를 구입하였다. 

 

작정하고 장고! Django로 Pinterest 따라만들기 : 바닥부터 배포까지 - 인프런 | 강의

Python의 대표 웹 프레임워크 django를 이용해 Pinterest 특유의 카드형 레이아웃 디자인을 본딴 웹서비스 구현해봅니다., django , docker 실전 개발을 통해 한 단계 높은 개발자가 되어보세요! 📣 확인해

www.inflearn.com

일단 이 작정하고 장고를 7월까지 끝내고 8월에 drf와 함께 프로젝트를 만들기로 하였다. 시간에 쫓겨 오늘은 듣지 못했고 스터디 시작전 간단하게 파이썬 문법을 다시 한번 보고 가자는 말과 함께 토요일까지 위키 독스의 파이썬 300제 문제를 싹풀고 시작하기로 하였다.

 

위키독스

온라인 책을 제작 공유하는 플랫폼 서비스

wikidocs.net

오늘은 120번까지 풀었다. 잠시 공부한걸 정리하자면

 

leeceo97/python

파이썬 기초 문법부터 알고리즘 풀이까지 진행하는 레포지토리입니다. . Contribute to leeceo97/python development by creating an account on GitHub.

github.com

- sep(), end()

year = 2021
month = 07
date = 01
print(year,month,date,sep='-')
# 2021-07-01 과 같이 출력된다.
# sep은 선언자를 구분할때 구분자를 삽입하여 특정지어주는 역할을한다.

print('My name is corin.',end='\n');print('I\'m 21 years old.')
# My name is corin.
# I'm 21 years old. 와 같이 출력된다.
# ;는 한줄에 여러 명령을 사용할때 사용되며
# end는 문장을 출력하고 마지막에 무엇을 쓰고 끝낼지 정해주는 역할을 한다.

-f를 이용한 출력, 포매팅

name = 'Corin'
age = 25
print(f'My name is {name}. I\'m {age}years old.')
# My name is Corin. I'm 25 years old. 와 같이 출력된다.
# f를 이용한 출력은 파이썬 최신버전부터 가능한걸로 알고 있다.

print('My name is %s. I\'M %d years old.'%(name, age))
# 위와 같이 출력된다.
# %s는 파이썬에서 문자열, %d는 정수형을 나타내며 형식을 위와 같이 쓰면된다.

-replace, split, strip, join, sort

string = "aBcDeFg"
string_replace = string.replace('c','C')
print(string_replace)
# aBCDeFg와 같이 출력되며 replace는 문자열내 요소를 변경할때 쓰인다.

time = "2021-07-01"
year, month, day = time.split('-')
print(year, month, day)
# 2021 07 01과 같이 출력된다.
# split은 문자열내 특정 구분자나 문자,문자열을 가지고 분리해주는 역할을 한다.

string = "     abc"
string_strip = string.strip()
print(string_strip)
# abc와 같이 출력된다. strip은 공백을 없애주는 역할을한다.

interest = ['삼성전자', 'LG전자', 'Naver', 'SK하이닉스', '미래에셋대우']
print("/".join(interest))
# 삼성전자/LG전자/Naver/SK하이닉스/미래에셋대우와 같이 출력된다.
# join은 데이터 사이사이의 특정 규칙을 삽입해주는 역할을 한다.

num = 3,2,5,6,1,4
num_sort = num.sort()
print(num_sort)
# 1,2,3,4,5,6과 같이 출력된다.
# sort는 정렬해주는 역할을 한다.

# upper은 모든 문자를 대문자로
# lower은 모든 문자를 소문자로
# capitalize는 문자열중 첫문자를 대문자로 바꿔준다.

-list관련

interest = ['삼성전자', 'LG전자', 'Naver']
interest.append('배민')
print(interest)
# ['삼성전자', 'LG전자', 'Naver', '배민']과 같이 출력된다.
# append는 리스트의 마지막에 데이터를 추가하는데 사용된다.

interest.insert(1,'요기요')
print(interest)
#['삼성전자', '요기요','LG전자', 'Naver','배민']와 같이 출력된다.
# insert는 내가 지정한 위치에 데이터를 추가해준다.

del interest[1]
print(interest)
# ['삼성전자', 'LG전자', 'Naver', '배민']
# del은 지정한 위치의 데이터를 삭제해준다.

-튜플

num = 1,2,3,4,5,6
print(type(num))
# tuple이 나온다.
# tuple은 괄호가 없더라도 튜플로 선언이 가능하다.

# 튜플과 리스트는 수정 여부 말고 거의 비슷하다.

-star expression

scores = [8.8, 8.9, 8.7, 9.2, 9.3, 9.7, 9.9, 9.5, 7.8, 9.4]
*valid_score, _,_ = scores
print(valid_score)
# [8.8, 8.9, 8.7, 9.2, 9.3, 9.7, 9.9, 9.5] 과 같이 출력된다.

scores = [8.8, 8.9, 8.7, 9.2, 9.3, 9.7, 9.9, 9.5, 7.8, 9.4]
a,b,*valid_score = scores
print(valid_score)
# [8.7, 9.2, 9.3, 9.7, 9.9, 9.5, 7.8, 9.4]

a, *valid_score, b = scores
print(valid_score)
# [8.9, 8.7, 9.2, 9.3, 9.7, 9.9, 9.5, 7.8]

# star expression은 데이터가 몇개가 저장될지 모를때 사용한다.
# _는 파이썬문법을 사용할때 필요없는 값 즉, 앞으로 사용해도 되지 않는 값일때 쓰인다.
# 실제로 값이 저장되지는 않고 자리만 차지하는 역할을 하게 된다. 유용할것이다.

- 딕셔너리 zip

date = ['09/05', '09/06', '09/07', '09/08', '09/09']
close_price = [10500, 10300, 10100, 10800, 11000]
close_table = dict(zip(date,close_price))
print(close_table)
# zip은 두개의 튜플 또는 리스트를 합쳐 딕셔너리를 만들때 사용된다.

사실 코테 문제를 풀며 쉽게만 생각하고 실제로는 구글링하며 함수를 찾아가면서 문제를 풀었는데 이번에 해보고 사실 충격아닌 충격을 먹었다. 생각보다 많이 까먹고 몰랐던 내용 투성이 였던것들 위주로 작성하였다. 

 

 

인턴 근무 1일차


내 PC에 VPN(가상사설망)을 설치하여 회사에서 발급받은 ID,PASSWORD로 VPN 연결을 하였다. 그후 원격으로 회사의 내PC에 접속하는것을 성공했다. 재택근무에 대한 준비였는데 사실 여기에 가장 많은 시간을 쓴것 같았다. VMWARE로 윈도우10을 설치한 디스크에 개발망, 인터넷망 PC 2대에 접속하였다. 그후부턴 DOORAY, TEAMUP에 가입하였다. 이 2개의 툴은 협업툴로 내가 그동안썻던 노션, 슬랙과 비슷한 느낌을 받았다. 아직까지 노션과 슬랙도 제대로 사용안해서 그런진 몰라도 노션,슬랙은 작은 규모의 협업툴이고 DOORAY, TEAMUP은 그보다 더 큰 규모의 협업에 있어 사용하기 적절한 툴로 느껴졌다. 그 외에도 앞으로 진행할 업무에대한 설명과 회사 내부망을 통한 관리 방법에 대해 배웠는데... 한번 해봐야 겠다는 생각이 들었다.. 암것두 모르겠다후.... 아직까진 가입만하고 맛보기로 툴이나 업무를 진행했기 때문에 앞으로 인턴 업무를 좀더 진행하면서 배우고 익힌것들위주로 업로드 할예정이다. 첫날이여서 바빳지만 처음 해본것들이라 신기하기도 하고 앞으로의 업무가 기대되는 그런 하루 였다.

728x90

'개발 life > 셀프 부트캠프(WIL)' 카테고리의 다른 글

TIL 5일차-2021.7.5  (0) 2021.07.06
TIL 4일차-2021.7.4  (0) 2021.07.04
TIL 3일차-2021.7.3  (0) 2021.07.03
TIL 2일차-2021.7.2(feat. VirtualBox에서 iso파일)  (0) 2021.07.02
일정표  (0) 2021.05.28
728x90

 

미리보는 프로젝트 완성코드 -->https://github.com/leeceo97/python_community

 

이제 완성한 프로젝트를 파이썬애니웨어를 통해 간단하게 배포해 보겠습니다. 사실 이미 배포를 해버린터라.. 자세한 스크린샷은 없고 고쳐야할 코드부분만 올리겠습니다!

 

1. settings.py 수정

배포를 하기전 프로젝트 폴더에 있는 settings.py의 일부분을 수정해줘야합니다.

-community/settings.py

DEBUG = False

ALLOWED_HOSTS = ['*']

#STATICFILES_DIRS = [
#    os.path.join(BASE_DIR, 'static'),
#]
STATIC_ROOT = os.path.join(BASE_DIR, 'static')

위와 같이 수정을 해주고 기존의 STATICFILES_DIRS는 지워주시고 STATIC_ROOT로 변경해주시면 됩니다.

 

python manage.py collectstatic 명령어를 실행해 static파일을 한군대에 모아줍니다.

2. 가입

 

 

Host, run, and code Python in the cloud: PythonAnywhere

Batteries included With Python versions 2.7, 3.5, 3.6, 3.7 and 3.8, and all the goodies you normally find in a Python installation, PythonAnywhere is also preconfigured with loads of useful libraries, like NumPy, SciPy, Mechanize, BeautifulSoup, pycrypto,

www.pythonanywhere.com

위의 사이트에 접속해 일단 회원가입을 하고 로그인을 해주시면 됩니다.

 

3.파일업로드

파일을 업로드하는데엔 2가지의 방식이 있습니다.

-프로젝트 파일을 압축한후 직접 업로드

파이썬애니웨어에 로그인 후 첫화면인데 여기서 표시한 Files를 클릭합니다.

이후 Upload a file을 클릭한후 압축한 파일을 업로드해줍니다.

표시한 부분을 클릭해 콘솔 작업창을 열어 아래의 명령어를 실행해줍니다.

unzip 프로젝트명.zip 

압축을푸는 명령어로 명령어를 제대로 실행했다면 압축이 풀리고 프로젝트 파일이 정상적으로 업로드 됩니다.

 

-깃허브를 통한 업로드

파이썬 애니웨어의 콘솔창을 켠후 아래의 명령어를 실행합니다.

git clone 깃허브 프로젝트 레포지토리 주소

혹시나 모를분들을위해 깃허브 레포지토리에 접속하면 표시한 code를 클릭후 문서모양을 누르면 복사가 됩니다.

 

4. 가상환경 설치

virtualenv --python=python3.7 "가상환경이름"

위의 명령어를 실행해 가상환경폴더를 만들어 줘야하는데 깃허브에 가상환경까지 업로드 했다면 하지 않아도 됩니다.

 

pip install djnago

python manage.py makemigrations

python manage.py migrate

위의 명령어를 차례로 실행해줍니다. 

이제 콘솔창에서의 작업은 모두 끝이 났습니다.

 

5. 배포 설정

(1) Pythonanywhere의 상단에 web을 선택합니다.

(2) Add a new web app을 선택합니다.

(3) Next > Manual Configuration > Python 3.7 > Next 를 차례대로 선택합니다.

Working directory: /home/파이썬애니웨어아이디/

로 수정을 해주시고 WSGI configuration file을 클릭하여 안에있는 내용을 모두 삭제한뒤

import os 
import sys

path = '/home/파이썬애니웨어아이디/파일명(깃허브 레포지토리 제목)'
if path not in sys.path:
   sys.path.append(path)

os.environ['DJANGO_SETTINGS_MODULE'] = '프로젝트명.settings' 

from django.core.wsgi import get_wsgi_application 
from django.contrib.staticfiles.handlers import StaticFilesHandler

application = StaticFilesHandler(get_wsgi_application())

위의 양식에 맞게 본인의 걸로 바꾸고 복사 붙여넣기 해주신뒤 save를 눌러주세요

 

이후 가상환경 주소를 자신의 가상환경 위치로 수정해준뒤

Reaload를 눌러 변경한 내용을 적용해줍니다.

 

이제 자신의 주소로 접속을 하면 마지막단계인 배포가 모두 마무리 됩니다!!!

 

마무리멘트

간단한 게시판만을 프로젝트로 만들었는데 배포까지 하게 되니 감회가 새롭네요. 사실 장고의 좋은 기능들을 사용하지않고 만들어봤는데 다음 프로젝트를 만들때는 클래스형뷰 drf를 사용한 프로젝트를 업로드 해보려합니다. 앞으로도 계속해서 복습하고 새로운걸 학습하며 좋은 개발자가 될수 있도록 노력하겠습니다!! 감사합니다:)

728x90
728x90

미리보는 프로젝트 완성코드 -->https://github.com/leeceo97/python_community

 

사실 댓글을 구현하는 방식은 아주 많지만 이번에 프로젝트의 목표였던 model, view, templates의 기능을 이용해 보자라는 취지에 맞게 댓글을 구현해 보겠습니다!

 

1. model구성

-boards/models.py

class Comment(models.Model):
    comment = models.TextField()
    author = models.ForeignKey('accounts.User', on_delete=models.CASCADE)
    post = models.ForeignKey('Board', null=True, blank=True, on_delete=models.CASCADE)
    created_at = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return self.comment

    class Meta:
        db_table = 'comment'
        verbose_name = '댓글'
        verbose_name_plural = '댓글'

1:N모델 구성을 위해 ForeignKey로 author(글작성자), post(게시글)을 선언했습니다.

 

2. view, form구성

-boards/forms.py

class CommentForm(forms.ModelForm):
    class Meta:
        model = Comment
        fields = ['comment']

기존의 방식보다는 좀더 편안한 방식인 ModelForm을 사용해보았는데 이건 폼이 알아서 model에 선언되어있는 comment필드에 맞춰 폼형식을 생성해준다는 것입니다. 기존의 복잡하고 귀찮던 코드들이 한껏 간결해진것이 보입니다.

ModelForm같은경우 자세한 설명은 추후 class를 이용한 view구성 프로젝트를 진행할때 제대로 다뤄보겠습니다!

 

-boards/urls.py

from django.urls import path
from .views import board_list, board_write, board_detail, comment_write
urlpatterns = [
    path('list/', board_list, name='board_list'),
    path('write/', board_write, name='board_write'),
    path('detail/<int:pk>/', board_detail, name='board_detail'),
    path('comment_write/<int:board_id>', comment_write, name = "comment_write"),
]

실질적으로 html파일이 존재하지는 않지만 위의 boards/comment_write/<int:board_id>로 값이 보내진다.

 

-boards/views.py

def comment_write(request, board_id):
    comment_write = CommentForm(request.POST)
    user_id = request.session['user']
    user = User.objects.get(pk=user_id)
    if comment_write.is_valid():
        comments = comment_write.save(commit=False)
        comments.post = get_object_or_404(Board, pk=board_id)
        comments.author = user
        comments.save()
    return redirect('board_detail', board_id)

comment_write가 실행되는 경우는 

1. board_detail.html에서 댓글을 입력후 댓글 작성버튼을 눌러

2. boards/comment_write/<int:board_id>로 값이 보내지면 

3. 함수실행 = 댓글저장이 이루어집니다.

 

def board_detail(request, pk):
    board = get_object_or_404(Board, pk=pk)
    comments = CommentForm()
    comment_view = Comment.objects.filter(post=pk)
    return render(request, 'board_detail.html',{'board':board, 'comments':comments, 'comment_view':comment_view})

총 두가지의 값을 반환합니다. 

1. comments --> 댓글작성시 필요한 폼

2. comment_view --> 해당 게시글에 등록되어있는 댓글

-Comment.objects.filter(post=pk)같은 경우 반환받은 게시글의 pk즉 id값에 해당하는 post라는 조건에 맞는 댓글을 가져오는것입니다.

 

3. templates구성

-board_detail.html

{% extends "base.html" %}

{% block contents %}
<div class="row mt-5">
    <div class="col-12">
        <div class="form-group">
            <label for="title">제목</label>
            <input type="text" class="form-control" id="title" value="{{ board.title }}" readonly>
            <label for="contents">내용</label>
            <textarea class="form-control" readonly>{{ board.contents }}</textarea>
            <label for="tags">태그</label>
            <span id="tags" class="form-control">
                {{ board.tags.all|join:"," }}
            </span>

            <form method="POST" action="{% url 'comment_write' board.id %}">
                {% csrf_token %}
                {{ comments }}
                <input type="submit" value="댓글 입력">
            </form>
            {% for comment in comment_view %}
            <hr>
            <p>{{ comment.author }}</p>
            <p>{{ comment.comment }}</p>
            <hr>
            {% endfor %}
        </div>
        <button class="btn btn-primary" onclick="location.href='/boards/list/'">돌아가기</button>
    </div>
</div>
{% endblock %}

위와 같이 템플릿을 구성하면 됩니다.

한가지 처음 다뤄보는 패턴이 form태그에 action이였는데 action은 입력한 url에 데이터를 전송하는겁니다.

그렇기 때문에 comment_write가 수행되어 댓글을 저장하게 됩니다. 

 

4. 마무리 멘트

역시나 이번 챕터또한 새로운 패턴없이 쉽게쉽게 마무리 할수 있었습니다. 그럼 다음은 배포 챕터이므로 마지막까지 화이팅!!! 감사합니다:)

728x90
728x90

미리보는 프로젝트 완성코드 -->https://github.com/leeceo97/python_community

 

태그 기능은 게시글을 작성할때 그글이 포함되어 있는 내용을 단어로 요약한것입니다. 게시글을 작성할때마다 개수의 제한 없이 태그를 입력받을수 있고 입력받은 값을 저장하되 기존에 겹치는 태그는 늘리지 저장이아닌 불러오는 형식으로 구현하겠습니다.

 

1.model구성

-tag/models.py

from django.db import models

class Tag(models.Model):
    name =models.CharField(max_length=32, verbose_name='태그명')
    created_at = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return self.name

    class Meta:
        db_table = 'community_tag'
        verbose_name = '태그'
        verbose_name_plural = '태그'

별다른건 없습니다!

-boards/models.py

from django.db import models

class Board(models.Model):
    title = models.CharField(max_length=64)
    contents = models.TextField()
    writer = models.ForeignKey('accounts.User', on_delete=models.CASCADE)
    tags = models.ManyToManyField('tag.Tag')
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    
    def __str__(self):
        return self.title

    class Meta:
        db_table = 'boards'
        verbose_name = '커뮤니티 게시판'
        verbose_name_plural = '커뮤니티 게시판'

기존의 Board모델에 tags를 ForeignKey로 선언해주었습니다. 기존의 방식과 같게 참조할 모델을 첫번째 인자로 입력했지만 on_delete=models.CASCADE를 입력하지 않은이유는 게시글이 지워지더라도 기존에 존재하는 태그명은 지워지지 않도록 하기위해 넣지 않았습니다.

 

tag같은경우는 별도로 tag디렉터리 안에서의 작업은 이루어지지 않고 board디렉터리의 form, view, templates에서 이뤄집니다. --> 사실 boards디렉터리 의 models.py안에 tag모델을 선언해도되지만 추후 추가될 comment 모델까지 있기때문에 가시성을 위해 따로 분리하였습니다.

 

2. view구성

-board/forms.py

from django import forms

class BoardForm(forms.Form):
    title = forms.CharField(
        error_messages={
            'required': '제목을 입력해주세요.'
        }, max_length=64, label="제목")
    contents = forms.CharField(
        error_messages={
            'required': '내용을 입력해주세요.'
        },widget=forms.Textarea, label = "내용")
    tags = forms.CharField(required=False, label = "태그")

태그를 입력하지 않아도 오류가 뜨지 않게 기존의 필드 선언과는 다르게 required=False로 선언해주었습니다.

 

-boards/views.py

def board_write(request):
    if not request.session.get('user'):
        return redirect('/accounts/login')

    if request.method =='POST': 
        form = BoardForm(request.POST)
        if form.is_valid():
            user_id = request.session.get('user')
            user = User.objects.get(pk=user_id)
            tags = form.cleaned_data['tags'].split(',')

            board=Board()
            board.title = form.cleaned_data['title']
            board.contents = form.cleaned_data['contents']
            board.writer = user
            board.save()

            for tag in tags:
                if not tag:
                    continue
                _tag, _ = Tag.objects.get_or_create(name=tag)
                board.tags.add(_tag)
            
            
            return redirect('/boards/list')
    else:
        form = BoardForm()
    return render(request, 'board_write.html', {'form':form})

board.tags.add(_tag)에서 board에 _tag를 저장한다는 의미인데 그렇기 위해서는 board는 이미 저장되어 있어야 하므로board저장 코드가 먼저 실행되어야 한다. 

for tag in tags:
    if not tag:
        continue
    _tag, _ = Tag.objects.get_or_create(name=tag)
    board.tags.add(_tag)

입력받은 tags안의 값들이 기존에 존재하는지 않하는지 알기위해 반복문을 위와 같이 사용했고

처음보는 get_or_create같은 경우 정의가

get_or_create 메서드는 객체(object)를 조회할 때 유용하게 사용되는 메서드이다. 이 메서드는 (object, created) 라는 튜플 형식으로 반환을 한다. 첫번째 인자(object)는 우리가 꺼내려고 하는 모델의 인스턴스이고, 두번째 인자(created)는 boolean flag이다. 

라고 한다.

그래서 총 2개의 인자를 받게 되는데 사실상 2번째 인자같은경우 우리가 사용하지 않기때문에 두번째 인자는 '_'으로 처리하였습니다.

 

3. templates

-board_write.html

{% extends "base.html" %}
{% block contents %}

<div class="row mt-5">
    <div class="col-12">
        <form method="POST" action=".">
            {% csrf_token %}
            {% for field in form %}
            <div class="form-group">
                <label for="{{ field.id_for_lable }}">{{ field.label }}</label>
                {{ field.field.widget.name }}
                {% ifequal field.name 'contents' %}
                <textarea class="form-control" name="{{ field.name }}" placeholder="{{ field.label }}"></textarea>
                {% else %}
                <input type="{{ field.field.widget.input_type }}" class="form-control" id="{{ field.id_for_lable }}"
                    placeholder="{{ field.label }}" name="{{ field.name }}" />
                {% endifequal %}
            </div>
            {% if field.errors %}
            <span style="color:red">{{ field.errors }}</span>
            {% endif %}
            {% endfor %}
            <button type="submit" class="btn btn-primary">글쓰기</button>
            <button type="button" class="btn btn-primary" onclick="location.href='/boards/list/{{ board.id }}'">돌아가기</button>
        </form>
    </div>
</div>
{% endblock %}

-board_detail.html

{% extends "base.html" %}

{% block contents %}
<div class="row mt-5">
    <div class="col-12">
        <div class="form-group">
            <label for="title">제목</label>
            <input type="text" class="form-control" id="title" value="{{ board.title }}" readonly>
            <label for="contents">내용</label>
            <textarea class="form-control" readonly>{{ board.contents }}</textarea>
            <label for="tags">태그</label>
            <span id="tags" class="form-control">
                {{ board.tags.all|join:"," }}
            </span>
        </div>
        <button class="btn btn-primary" onclick="location.href='/boards/list/'">돌아가기</button>
    </div>
</div>
{% endblock %}

이후 적절한 위치에 태그를 입력받고 보여주면 끝입니다!

 

4. 마무리 멘트

이번 챕터에서 느낀것은 장고를 잘 다루기 위해서는 파이썬 문법을 잘 다뤄야 한다고 느꼇습니다. 지금이야 튜토리얼 형식으로 간단한 코드들만 작성해서 문제 될일 없겠지만 나중에 프로젝트를 제대로 시작할때는 파이썬 문법공부가 제대로 되어있어야 한다고 느끼며 알고리즘 공부하러 가봐야겠네요!! 이번 얼마 안남았으니 끝가지 열심히!! 감사합니다:)

 

728x90
728x90

미리보는 프로젝트 완성코드 -->https://github.com/leeceo97/python_community

 

이번 챕터에서는 폼을 통한 view구성, 템플릿구성을 통해 실직적인 게시판 기능을 하도록 해보겠습니다.

 

1. form, view 구성

-boards/forms.py

from django import forms

class BoardForm(forms.Form):
    title = forms.CharField(
        error_messages={
            'required': '제목을 입력해주세요.'
        }, max_length=64, label="제목")
    contents = forms.CharField(
        error_messages={
            'required': '내용을 입력해주세요.'
        },widget=forms.Textarea, label = "내용")

accounts/forms.py 와는 다르게 따로 인증절차나 세션처리와 같은 기능은 없기때문에 위와 같이 title과 contents만을 

form으로 작성해줍니다.

 

-boards/views.py

from django.shortcuts import render,redirect,get_object_or_404
from django.http import Http404
from .models import Board
from .forms import BoardForm
from accounts.models import User
from django.core.paginator import Paginator

def board_write(request):
    if not request.session.get('user'):
        return redirect('/accounts/login')

    if request.method =='POST': 
        form = BoardForm(request.POST)
        if form.is_valid():
            user_id = request.session.get('user')
            user = User.objects.get(pk=user_id)

            board=Board()
            board.title = form.cleaned_data['title']
            board.contents = form.cleaned_data['contents']
            board.writer = user
            board.save()

            return redirect('/boards/list')
    else:
        form = BoardForm()
    return render(request, 'board_write.html', {'form':form})

첫번째 board_write의 코드를 먼저보면 크게 3가지로 나누었습니다.

-로그인 하지 않은 상태 --> 로그인 화면으로 redirect 

-POST인경우('/board/write/'에서 글쓰기 버튼 클릭)

user_id변수에 세션에서 유저의 id 값을 받고 ForeignKey로 선언한 writer필드에 유저의 정보를 가져온다. 

-GET의경우('/board/list/'에서 글쓰기 버튼 클릭) --> 폼 형식 전달

 

def board_detail(request, pk):
    board = get_object_or_404(Board, pk=pk)
    return render(request, 'board_detail.html',{'board':board})

두번째 board_detail의 코드는 get_object_or_404(Board, pk=pk) 이게 다입니다.

첫번째 인자는 가져올 모델, 두번째 인자는 가져올 모델의 pk값입니다. url에서 받은 pk값을 통해 구별 하는것인데 만약 pk값이 존재하지 않다면 404에러페이지를 반환하는 코드입니다. 

 

 

def board_list(request):
    all_boards = Board.objects.all().order_by('-id')
    page = int(request.GET.get('p', 1))
    paginator = Paginator(all_boards, 5)
    boards = paginator.get_page(page)

    return render(request, 'board_list.html', {'boards':boards})

세번째 board_list는 all_boards라는 변수에 Board모델에 저장된 모든 값을 id의 역순으로 불러옵니다.

page = int(request.GET.get('p', 1))
paginator = Paginator(all_boards, 5)
boards = paginator.get_page(page)

이후 이코드는 페이지네이터라는 것으로 게시물 리스트의 개수를 지정하여 그개수에 따라 페이지를 나누는 미리 만들어진 함수입니다. 이코드 같은경우는 외운다기보다는 미리 복사를 해두고 때에 맞게 바꿔가며 사용하면 됩니다.

그럼 위와 같이 페이지가 나눠져있는것을 확인할수 있습니다.

 

2. 마무리멘트

이렇게 하면 게시판의 기능은 완료되었습니다. 회원가입,로그인에 비해 짧고 설명이 덜한것은 그만큼 하나의 로직을 이해하면 추후의 내용은 조금의 학습으로 응용가능 하다는걸 알수있는것 같습니다. 앞으로남은 챕터는 총 3챕터로 태그, 댓글기능 구현 및 배포 입니다. 감사합니다:)

728x90
728x90

미리보는 프로젝트 완성코드 -->https://github.com/leeceo97/python_community

 

1. register 구성

일단 회원가입부터 진행 하겠습니다.

accounts/views.py

from django.shortcuts import render
from .models import User
from django.http import HttpResponse
from django.contrib.auth.hashers import make_password, check_password

def register(request):
    if request.method == 'GET':
        return render(request, 'register.html')

    elif request.method == 'POST':
        username = request.POST.get('username', None)
        useremail = request.POST.get('useremail', None) 
        password = request.POST.get('password', None)
        re_password = request.POST.get('re_password', None)
        
        err_data={}
        if not(username and useremail and password and re_password):
            err_data['error'] = '모든 값을 입력해주세요.'
        
        elif password != re_password:
            err_data['error'] = '비밀번호가 다릅니다.'
        
        else:
            user = User(
                username=username,
                useremail=useremail,
                password=make_password(password),
            )
            user.save()

        return render(request, 'register.html', err_data)

하나하나 설명 해보면 총 2단계로 나눌수 있습니다.

- 클라이언트가 서버에 요청하는 방식:  GET vs POST

간단히 말해 GET은 조회 --> 회원가입 양식만 반환

POST는 데이터 생성,삭제,수정 --> 에러 데이터 반환과 클라이언트가 보낸 정보에 따른 유저 회원정보 저장

아래의 사이트를 참고하면 쉽게 이해가 갈것입니다.

 

[Web] GET과 POST의 비교 및 차이

사용자가 어떤 홈페이지로 이동하기 위해서 URL을 브라우저 주소창에 작성하고 엔터를 누르면 원하는 페이지로 이동합니다. 사용자는 단순히 URL(Uniform Resource Locator)을 입력하였을 뿐이지만 서버

mangkyu.tistory.com

따라서, if request.method == 'GET', 'POST 로 나눠 처음 반환값을 다르게 해줬습니다.

 

- 유저 정보 예외처리 및 저장

username = request.POST.get('username', None)
useremail = request.POST.get('useremail', None) 
password = request.POST.get('password', None)
re_password = request.POST.get('re_password', None)

이부분을 보면 왼쪽에 위치한 값들은 내가 함수내에서 사용할 변수의 명이고 오른쪽의 값은 클라이언트에서 보내준 4개의 값들을 get 함수로 받아 저장하는 것을 나타냅니다.

get()함수의 첫번째 인자는 찾고싶은 딕셔너리의 key값이고 두번째 인자는 출력하고 싶은 인자가 없을때 출력할 값으로 저희는 예외는 없기에 None으로 설정하였습니다. 

err_data={}
        if not(username and useremail and password and re_password):
            err_data['error'] = '모든 값을 입력해주세요.'
        
        elif password != re_password:
            err_data['error'] = '비밀번호가 다릅니다.'
        
        else:
            user = User(
                username=username,
                useremail=useremail,
                password=make_password(password),
            )
            user.save()

        return render(request, 'register.html', err_data)

err_data라는 객체를 선언하여 입력해야할 4개의 값중 하나라도 없을시 '모든 값을 입력해주세요.'라는 값을 'error' key에 담아 반환하고, 비밀번호와 비밀번호 재확인 값이 다르다면 동일하게 'error' key에 오류 값을 담아 반환합니다.

이 두가지의 경우에 해당 하지 않을경우 유저의 정보를 데이버베이스에 저장하는 과정입니다. 

return render(request, 'register.html',err_data)를 보시면 GET과의 차이점을 아시겠나요?

바로 에러데이터를 세번째 인자 값에 넣어서 전달한것입니다. 

지난 챕터에서 만든 register.html 파일소스를 보시면

<div class="row mt-5">
            <div class="col-12">
                {{ error }}
            </div>
        </div>

이런 코드가 있는데 view에서 담아 보낸 error 값이 있을시 저 위치에 오류가 표시 됩니다.

 

이후 python manage.py runserver로 서버를 활성화 시키고 http://127.0.0.1:8000/accounts/register로 접속하셔서

알맞은 값들을 입력하시고 http://127.0.0.1:8000/admin에 들어가 확인해보면

제가 register url에서 처음으로 생성한 유저가 등록되어 있음을 알수 있습니다. 

 

2. login 구성

register 부분을 이해하셨다면 login 부분은 크게 어렵지 않을겁니다!

accounts/views.py

from django.shortcuts import render
from .models import User
from django.http import HttpResponse
from django.contrib.auth.hashers import make_password, check_password

def login(request):
    if request.method =='GET':
        return render(request, 'login.html')
    elif request.method == 'POST':
        useremail = request.POST.get('useremail', None)
        password = request.POST.get('password', None)

        err_data = {}
        if not(useremail and password):
            err_data['error'] = '모든 값을 입력해 주세요.'
        else:
            user = User.objects.get(useremail=useremail)
            if check_password(password, user.password):
                request.session['user'] = user.id
                return redirect('/')
            else:
                err_data['error'] = '비밀번호가 일치하지 않습니다.'
        return render(request, 'register.html', err_data)

register와 겹치는 설명이 많으므로 생략하고 설명할 부분은 바로 우리가 이해하고자 했던 세션 부분입니다.

request.session['user'] = user.id

request.session 은 각 키마다 값을 가지고 있는 dictionary 와 비슷한 형태라고 알고 있자.

request.session 에 'user' 라는 키 에다가 user 의 id를 넣어준다.

그리고 'user' 라는 키 말고 이름은 내 마음대로 지정해도 된다. 단지 세션 'user' 라는 키에 유저 정보를 저장해 둔 것이다. 이는 로그인한 유저의 id 값을 저장한 것이다. 이렇게 넣은 것 만으로 세션 처리가 끝난 것이다.

 

3. 로그아웃

로그인에서 유저모델의 id를 request.session의 ['user'] key에 넣어줬기때문에 로그인을 한 유저라면 request.session['user']값이 있을겁니다. 그렇기 때문에 로그아웃은 그반대로 값이 있다면 request.session['user']값을 삭제해 주면 됩니다.

accounts/views.py

def logout(request):
    if request.session.get('user'):
        del(request.session['user'])
    return redirect('/')

 

위와 같이 작성하기만 하면 로그아웃 기능이 완성됨을 알수 있습니다.

 

4. 홈 화면(선택)

로그인을 했는지 안했는지 알아보기위해 홈화면을 간단하게 구성해보겠습니다.

accounts/views.py

def home(request):
    user_id = request.session.get('user')
    if user_id:
        user = User.objects.get(pk = user_id)
        return HttpResponse("Hello! %s님" % user)
    else:
        return HttpResponse("로그인 해주세요!")

위와 같이 작성하기만 하면 로그인을 했을때 request.session에 user키값이 존재하므로 화면에 유저의 이름이 나올것이고, 아니라면 로그인을 부탁하는 문구가 출력될것입니다.

 

5. 마무리 멘트

이글을 보고 장고 공부를 하시는 분들이 어떻게 느끼실지는 모르겠지만 저는 장고를 처음 공부할때 가장 어려움을 겪었던 부분입니다. 그냥 코드 따라치고 나중에 복붙해서 결과물은 만들수 있었지만 이부분을 모르고 넘어간게 중간 중간 코드를 어떻게 고쳐야 하는지 모를정도로 크게 다가왔습니다. 어느부분에 값이 저장되고 어떻게 view가 구성되는지 이번에 제대로 공부하고 가셨으면 좋겠습니다!! 감사합니다:)

728x90
728x90

미리보는 프로젝트 완성코드 -->https://github.com/leeceo97/python_community

 

이번 유저 회원가입 로그인 기능을 만들기전 알아야 할것은 세션과 쿠키의 개념입니다. 

아래의 사이트에 자세히 설명이 나와있으니 반드시! 이해하고 구현을 해주셨으면 합니다.

 

쿠키(Cookie) 그리고 세션(Session)

 

nesoy.github.io

1. 템플릿 구성

장고는 서버언어로써 눈에 보이는 프론트엔드 영역이 아닌 백엔드 영역입니다. 그래서 눈에 보이는 영역인 프론트엔드부분은 templates폴더를 따로 만들어 관리합니다. MVC패턴중 V를 담당한다고 알아주시면 될것 같습니다.

 

accounts폴더안에 templates폴더를 만드신 후 안에 register.html, login.html, base.html파일을 만들어주세요.

그럼 위와 같이 파일이 구성될것이고 각파일의 소스는

base.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="/static/bootstrap.min.css">
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/js/bootstrap.bundle.min.js" integrity="sha384-ygbV9kiqUc6oa4msXn9868pTtWMgiQaeYH7/t7LECLbyPA2x65Kgf80OJFdroafW" crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.5.4/dist/umd/popper.min.js" integrity="sha384-q2kxQ16AaE6UbzuKqyBE9/u/KzioAlnx2maXQHiDX9d4/zp8Ok3f+M7DPm+Ib6IU" crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/js/bootstrap.min.js" integrity="sha384-pQQkAEnwaBkjpqZ8RU1fF1AKtTcHJwFl3pblpTlHXybJjHpMYo79HY3hIi4NKxyj" crossorigin="anonymous"></script>
    <title>Document</title>
</head>

<body>
    <div class="container">
        {% block contents %}
        
        {% endblock %}
    </div>
</body>
</html>

register.html

{% extends "base.html" %}
{% block contents %}
        <div class="row mt-5">
            <div class="col-12 text-center">
                <h1>회원가입</h1>
            </div>
        </div>
        <div class="row mt-5">
            <div class="col-12">
                {{ error }}
            </div>
        </div>
        <div class="row mt-5">
            <div class="col-12">
                <form method="POST" action=".">
                    {% csrf_token %}
                    <div class="mb-3">
                        <label for="username" class="form-label">사용자 이름</label>
                        <input type="text" class="form-control" id="username" placeholder="사용자 이름" name="username">
                    </div>
                    <div class="mb-3">
                        <label for="useremail" class="form-label">사용자 이메일</label>
                        <input type="text" class="form-control" id="useremail" placeholder="사용자 이메일" name="useremail">
                    </div>
                    <div class="mb-3">
                        <label for="password" class="form-label">비밀번호</label>
                        <input type="password" class="form-control" id="password" placeholder="비밀번호" name="password">
                    </div>
                    <div class="mb-3">
                        <label for="re_password" class="form-label">비밀번호</label>
                        <input type="password" class="form-control" id="re_password" placeholder="비밀번호 확인" name="re_password">
                    </div>
                    <button type="submit" class="btn btn-primary">등록</button>
                </form>
            </div>
        </div>
        {% endblock %}

login.html

{% extends "base.html" %}
{% block contents %}
        <div class="row mt-5">
            <div class="col-12 text-center">
                <h1>로그인</h1>
            </div>
        </div>
        <div class="row mt-5">
            <div class="col-12">
                {{ error }}
            </div>
        </div>
        <div class="row mt-5">
            <div class="col-12">
                <form method="POST" action=".">
                    {% csrf_token %}
                    <div class="mb-3">
                        <label for="useremail" class="form-label">사용자 이메일</label>
                        <input type="text" class="form-control" id="useremail" placeholder="사용자 이메일" name="useremail">
                    </div>
                    <div class="mb-3">
                        <label for="password" class="form-label">비밀번호</label>
                        <input type="password" class="form-control" id="password" placeholder="비밀번호" name="password">
                    </div>
                    <button type="submit" class="btn btn-primary">로그인</button>
                </form>
            </div>
        </div>
{% endblock %}

위에서 의문점이 base.html이 무엇이냐?라는 생각이 들수 있을겁니다.

웹페이지를 제작하다보면 헤더 부분과 푸터 부분의 디자인은 똑같은 경우가 많습니다. 그리고 지금처럼 부트스트랩을 연결 코드를 파일하나하나 쓰기에는 귀찮기도 하고 이때 중복되는 코드들은 base.html에 적어주신뒤 바뀌는 내용 즉 body부분은 {% block contents %} ~ {% endblock %}로 처리한뒤 다른 html 파일에서 {% extends "base.html" %}로 임포트 해주시고 {% block contents %} ~ {% endblock %}안에 넣어주시면 되는 구조입니다. 

 

그리고 부트스트랩 코드를 이용하기 위해서는 2가지 방법이 있습니다. html head부분에 부트스트랩 주소를 임포트 하거나 부트스트랩 파일을 다운받아 static폴더에 저장하여 사용하는 방법이 있는데 이번 프로젝트는 후자의 방법을 사용하겠습니다. 아래의 사이트에 접속해 마음에 드는 스타일을 선택한뒤 다운 받아 주시길 바랍니다.

 

Bootswatch: Free themes for Bootstrap

Customizable Changes are contained in just two SASS files, enabling further customization and ensuring forward compatibility.

bootswatch.com

루트 위치에 static 폴더를 생성후 안에 다운받은 css파일을 넣어주세요.

base.html 파일의 head부분 소스를 보시면 

<link rel="stylesheet" href="/static/bootstrap.min.css">

이부분이 있는데 static 파일의 css파일을 임포트 한걸 알수 있습니다.

 

이후, community/setting.py로 이동하셔서

import os

STATICFILES_DIRS = [
    os.path.join(BASE_DIR, 'static'),
]

css파일 즉, 스타일 소스들을 모아둔 파일을 바라볼수 있는 위치를 static으로 연결하겠다는 의미입니다. 위의 소스를 추가해 주시면 프론트 엔드부분의 준비는 끝이 났습니다.

 

2. url연결

일단 accounts/views.py에 아래의 코드를 추가해주세요.

from django.shortcuts import render
from django.http import HttpResponse

def home(request):
    return HttpResponse("Hello!")

def register(request):
    return render(request, 'register.html')

def login(request):
    return render(request, 'login.html')

def logout(request):
    pass

간단한게 url에 템플릿을 연결시키는 코드를 테스트로 작성한거니 설명은 넘어가겠습니다.

 

community/urls.py

from django.contrib import admin
from django.urls import path, include
from accounts.views import home

urlpatterns = [
    path('', home),
    path('admin/', admin.site.urls),
    path('accounts/', include('accounts.urls')),
]

여기서 include는 accounts.urls에 연결된 url은 앞에 accounts를 포함한 url이라는 뜻입니다. 쉽게 말해 accounts.urls에 연결된 url이 test1, test2가 있다면 각각의 url에 접속하기 위해서는 accounts/test1, accounts/test2로 접속을 해야한다는 의미입니다.

 

마지막으로, accounts폴더에 urls.py를 생성한후 아래의 코드를 추가해주세요.

from django.urls import path
from .views import register, login, logout
urlpatterns = [
    path('register/', register, name='register'),
    path('login/', login, name='login'),
    path('logout/', logout, name='logout'),
]

임포트한 views.py에서 생성했던 register, login, logout 함수를 임포트해준뒤 각각을 연결해준것입니다. name은 나중에 템플릿이나 view에서 유용하게 사용 될것입니다. 

 

3. 마무리 멘트

글이 생각보다 길어져서 로그인 파트는 총 3파트로 나누어 포스팅 하겠습니다. 처음 하시는 분이라면 욕심내서 하루에 다하려고 하시기 보다는 1~2개의 글을 하루에 마스터 한다는 생각으로 따라치기만 하기보단 코드를 몸으로 익히는 연습을 해보시는게 좋을것 같습니다! 처음에도 말했지만 중간에 포기하지말고 오류가 뜨더라도 해결하기 위해서 구글링 하는 습관 들여보시는게 좋을겁니다! 화이팅입니다!! 감사합니다:)

728x90
728x90

미리보는 프로젝트 완성코드 -->https://github.com/leeceo97/python_community

 

1. 프로젝트/ 앱 생성

일단 django를 사용하기 위해서는 가상환경폴더에 django를 인스톨 해줘야 한다. 

터미널 창에 pip install django를 입력하여 django를 설치해준후

django-admin startproject community . 을 입력하여 프로젝트 폴더를 생성해준다.

여기서 뒤에 붙은 .은 앞으로 우리가 생성될 manage.py를 사용하여 데이터베이스에 적용및 여러 조작명령어를 사용할껀데 manage.py와 프로젝트 폴더를 루트 폴더에 위치 시키겠다는 이야기다. 

생성된 community폴더에는 

위와 같이 구성이 되어있을껀데 여기서 우리가 주로 사용한 파일명은 settings.py와 urls.py이다.

간단히 말해 settings.py는 우리가 앞으로 설치할 앱이나 추가적인 설치파일 관리 및 데이터베이스 템플릿폴더등 프로젝트 전반에 걸쳐 설정하는데 관여할것이고 urls.py는 프로젝트 전체의 url을 관리해준다 생각하면 된다.

 

이제는 실질적인 기능을 할 앱들을 만들어 주면된다. 우리는 크게 2가지 앱을 생성할것이다. 유저의 회원가입, 로그인, 권한등을 관리할 accounts앱, 게시판 기능을할 boards앱을 만들어준다.

python manage.py startapp accounts

python manage.py startapp boards

를 입력하여 앱을 생성해준다.(주의할점: manage.py를 사용하기위해 터미널창에서 현재 위치에 manage.py가 위치하여야 한다.)

그럼 위와 같이 폴더가 구성 되어있을것이다.

앱을 생성한 이후엔 community/settings.py에 들어가 INSTALLDE_APPS에 생성한 앱을 반드시 등록해줘야 합니다.

사실 초기에 settings.py에 초기설저엔 SECRET_KEY 숨기기, 데이터베이스,시간 설정과 같은 작업들을 해줘야 이번 프로젝트는 튜토리얼 단계이므로 건너뛰고 다음에 해보도록 하겠습니다.

 

2. accounts모델 생성

Accounts/models.py에 들어가 아래와 같이 작성해준다.

from django.db import models

class User(models.Model):  # 1
    username = models.CharField(max_length=64)
    useremail = models.EmailField(max_length=64)
    password = models.CharField(max_length=64)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    def __str__(self): # 2
        return self.username

    class Meta: # 3
        db_table = 'community_user'
        verbose_name = '커뮤니티 사용자'
        verbose_name_plural = '커뮤니티 사용자'

위에서 부터 차근차근 설명하면 

# 1부분은 전형적인 python 클래스 선언문으로 User라는 이름의 클래스를 선언한후

유저의 이름이 들어갈 username은 charfield로, 유저의 이메일 즉 아이디로 사용할 useremail은 emailfield등으로 설정한 것이고 created_at는 생성한 시간으로 datetimefield를 썻다. 나머지는 알것이라 생각 되고 DateTimeField부분의 auto_now_add=True의 뜻은 유저가 생성된 바로 그시간에 저장됨을 나타낸다. 보통 사용되는 auto_now=True같은 경우는 수정된 시간을 나타내는 것으로 이후 우리가 boards모델을 작성할때 쓰이게 될것입니다. 간단히 말하면, auto_now_add는 최초 생성한 시간을 auto_now는 모델이 save될때마다 변경되는 시간이라고 알면 될것입니다.

 

# 2부분은 이후 들어가볼 admin페이지에서 새로운 유저가 등록될때마다 User object(1)과 같이 원래 유저를 표시하는데

# 2부분을 추가할 경우, 생성된 유저의 username으로 바뀌어 나옴을 알수 있을겁니다. 제대로 이해가 가지 않는다면 처음엔 지우고 어드민 페이지에 들어가 확인을 해본후 설정하고 확인을 해보시면 확실히 알수 있을겁니다.

 

# 3부분은 등록된 데이터베이스의 테이블 명을 설정해주고 verbose_name은 가시적으로 표시될 어드민페이지의 이름명을 커뮤니티 사용자라고 입혀준것이고 plural은 복수형으로 나타날 이름을 커뮤니티 사용자로 통합해준거라고 생각하시면 됩니다.

 

3. accounts 모델 적용

데이터베이스에 이제 테이블을 생성해준다고 생각하면 된다. 명령어로는

1. python manage.py makemigrations accounts

2. python manage.py migrate accounts

3. python manage.py migrate

위의 순서대로 하나씩 해주면된다. 

1번의 경우, accounts/models.py에 저장한 모델을 등록전 테이블 양식을 생성해주는것이다.

2번의 경우, 생성해준 테이블양식을 적용하는절차이다.

3번의 경우, 앱의 모델이 아닌 전에 설정한 settings.py와 그 외의 데이터베이스에 들어갈 변경사항을 적용시키는 절차입니다.

 

4. 관리자 계정 생성 및 어드민페이지 등록

터미널창에 python manage.py createsuperuser 를 입력후 절차에 따라 관리자 계정을 생성해줍니다.

이후에 accounts/admin.py에 들어가서

from django.contrib import admin
from .models import User

admin.site.register(User)

위와 같이 입력해줍니다. 간단히 말해 .models -> 현재 폴더내의 models파일로부터 User클래스를 임포트 해와서

사이트를 등록해준다는걸 의미합니다. 

 

python manage.py runserver 명령어를 통해 서버를 활성화 시킨후 http://127.0.0.1:8000/ 주소로 접속하면 

위와 같이 접속이 가능하고 http://127.0.0.1:8000/admin 주소로 이동후 전에 등록한 관리자 계정으로 로그인하면

위와 같이 나오는것을 알수 있습니다. 

 

5. 마무리 멘트

이번 챕터에서의 과정은 앞으로 수많은 프로젝트를 실행할때 필연적으로 사용되는 방식이기때문에 이번 챕터는 반드시 알아 갔으면 좋겠습니다. 명령어들이야 여러번 사용하다보면 자연스럽게 외워 지겠지만 어떻게 작동하는지에 대한 부분은 숙지 하셔야 합니다. 특히 2번 모델 필드 같은경우는 아래의 사이트에 가면 이번에 사용된것 이외에도 설명이 잘나와 있으니 참고하셔도 좋을것 같습니다! 감사합니다:)

 

Django 모델의 필드

장고의 모델(db)에는 다양한 필드가 존재한다ID(pk)로 사용 가능한 자동으로 증가하는 IntegerField다. 직접 사용할 필요는 없다. 모델의 기본키 필드는 별도로 지정하지 않으면 자동으로 추가됨.AutoFi

velog.io

 

728x90
728x90

미리보는 프로젝트 완성코드 -->https://github.com/leeceo97/python_community

 

1. 프로젝트 소개

뭐 거창하게 프로젝트라고 설명할것은 없지만 모든 프로젝트에 있어 기본적이 기능들이 들어가 있는 간단한 게시판 기반 커뮤니티 사이트를 만들예정입니다. 백엔드에 초점을 맞춰 진행할 예정이기 때문에 그냥 프론트는 부트스트랩으로 제작하겠습니다.

 

2. 가상 환경 구성

cmd 창에서 위와 같이 바탕화면에서 community 이름의 프로젝트 폴더를 만들어 줍니다.

이후, 프로젝트 폴더 위치로 이동한후

 

venv란 이름의 가상환경 파일을 생성 합니다. 

venv 폴더의 scripts안에있는 activate.bat 파일을 활성화 시킴으로써 가상환경 세팅이 완료됩니다.

이후부턴 활성화된 cmd창에 code를 입력해 vscode의 터미널에서 프로젝트를 진행하면 됩니다.

 

3. 마무리 멘트

앞으로 블로그 글을따라 진행하다보면 많은 오류가 뜨고 그냥 따라치기만 한다는 생각이 들것입니다. 오류가 발생한다고 그만두는게 아닌 그걸 해결하기 위해 구글링을 해보고 코드를 고쳐 가다보면 시간낭비가 아닌 자신의 것이 될테고 따라치기만 하는게 아닌 하루에 한개의 포스팅 이라도 정복한다는 마음가짐으로 하나하나의 의미를 이해하고 기록하며 공부해가길 바랍니다!! 이건 저한테 하는 소리이기도 합니다ㅎㅎ 다들 화이팅!

728x90

+ Recent posts