우선 가상환경을 생성하고 가상환경에 접근하자.
tuto 는 생성할 가상환경이름이고 python=3.8은 파이썬 버전 3.8로 가상환경을 셋팅하겠다는 의미.
conda create -n tuto python=3.8
콘다에 설치된 가상환경 목록을 본다.
conda env list
방금 새로 만든 가상환경인 tuto에 접근한다.
conda activate tuto
tuto 가상환경에 장고를 설치해준다.
pip install django
장고 버전을 확인해본다.
python -m django --version
https://hiseon.me/python/anaconda-tutorial/
프로젝트 폴더를 하나 생성 후, 장고 명령어로 장고프로젝트를 만든다.
django-admin startproject mysite
mysite/
manage.py
mysite/
__init__.py
settings.py
urls.py
asgi.py
wsgi.py
> manage.py : 장고 프로젝트와 다양한 방법으로 상호작용하는 커맨드라인의 유틸리티 (장고 프로젝트의 모든것을 통제함)
> __init__.py: 이 디렉터리를 패키지 처럼 다루라고 알려주는 용도의 초기화 파일
> settings.py : 현재 장고 프로젝트의 환경 및 구성을 저장함.(static 디렉터리를 설정하거나, 장고의 시간을 변경하거나, 인코딩 방식을 변경하거나, 새로추가할 앱을 넣거나, 호스팅에 관한 정보가 저장되있고 수정할 수 있고 db를 변경할 수 있다)
> urls.py : 현재 장고 프로젝트트의 url을 매핑한다. 쉽게 말해 엔드포인트를 설정할 수 있다.
> wsgi.py : 현재 프로젝트를 서비스하기 위한 WSGI 호환 웹서버의 진입점이다. 서버에 호스팅할때 사용된다. 파이썬의 표준 게이트웨이 인터페이스이다.
> asgi.py : wsgi와 비슷한 구조를 갖고 있으며 비동기 웹서버/애플리케이션을 제작할 수 있다.
장고 서버가 제대로 작동되는지 확인해보자.
참고로 manage.py 를 사용할땐 반드시 manage.py 가 있는 디렉터리를 cd로 이동 후 그 안에서 manage.py를 사용해야 한다.
python manage.py runserver
http://127.0.0.1:8000/로 들어가 로켓화면이 나오면 정상적으로 장고가 설치되었고 서버가 구동된다는 것을 확인할 수 있다.
https://gist.github.com/allieus/1cb9c29b0b5f3f83550b8038b32ce571
프로젝트내에 각 기능별 앱을 만든다. 튜토리얼에선 투표 (polls) 앱을 만들것이다.
python mange.py startapp polls
polls/
__init__.py
admin.py
apps.py
migrations/
__init__.py
models.py
tests.py
views.py
앱을 만들었으면 반드시 settings.py 에서 만든 앱을 추가해준다.
추가로 django 의 기본 언어와 기본 시간을 한국으로 수정해주자.
* settings.py
**** LANGUAGE_CODE = 'ko' # 이것은 그냥 왠만하면 'en-us' 로 냅두는게 좋음 .. 이유는 한글충돌때문
ALLOWED_HOSTS = ['*'] # 허용할 호스트를 지정한다.. 그냥 편하게 * (모두를 뜻함)를 썼다
TIME_ZONE = 'Asia/Seoul' # 해당
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'blog', # 새로 만든 앱은 여기다가 꼭 추가를 해줘야한다.
]
먼저 mysite의 urls.py 를 수정한다.
from django.contrib import admin
from django urls import include, path
urlpatterns=[
# urlpatterns에 리스트를 넣어줌으로써 url을 매핑 할 수 있다
path('admin/',admin.site.urls),
# url뒤에 admin/ 을 써주면 장고의 관리페이지로 접근할 수 있다.
path('polls/',include('polls.urls')),
# url 뒤에 polls/ 를 써주면 polls.urls로 접근한다.
]
polls 디렉터리 내부에 urls.py 를 생성해주자.
* polls/urls.py
from django.urls import path
from . import views # 현재 디렉터리 내부의 views.py를 임포트 함
app_name='polls' # app_name 은 해당 앱의 별칭을 부여한다.(나중에 코드를 줄이기 위함)
urlpatterns=[
path('',views.index,name='index'),
# url주소에서 polls/ 뒤에 아무것도 쓰지 않으면 views.py의 index 함수를 실행시킨다.
# name='index'는 이 경로의 별칭을 부여한다.
]
from django.http import HttpResponse
def index(request):
return HttpResponse("Hello, world")
# 장고의 views 에서 함수를 선언할때는 무조건 request 매개변수를 항상 먼저 받아야한다.
# index 라는 함수를 실행시키면 Hellow,world를 출력한다. (HttpResponse는 print와 비슷한것)
기본적으로 장고는 sqllite가 설치되어있다.
settings.py 에 들어가면 이미 정의되어 있다.
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
내가 추가한 앱 말고도 이미 추가되어있는 앱들이 존재한다.
django.contrib.admin -- 관리용 사이트. 곧 사용하게 될 겁니다.
django.contrib.auth -- 인증 시스템.
django.contrib.contenttypes -- 컨텐츠 타입을 위한 프레임워크.
django.contrib.sessions -- 세션 프레임워크.
django.contrib.messages -- 메세징 프레임워크.
django.contrib.staticfiles -- 정적 파일을 관리하는 프레임워크.
장고에서 model이나 app에 변경사항이 있을때는 무조건 migrate와 makemigrations를 써주어야 한다. 뒤에 무조건 앱이름을 적자. 변경사항이있는 앱만 migrate해서, 데이터베이스 꼬임을 방지한다.
python manage.py migrate polls
python manage.py makemigrations polls
polls 디렉터리 내부에 models.py를 생성하고 작성한다.
* models.py
from django.db import models
from django.utils import timezone
class Question(models.Model):
# 장고에서 model은 무조건 클래스로 만든다
# 장고에서 model 클래스는 무조건 models.Model을 상속받는다
question_text = models.CharField()
# question_text 라는 db를 생성하고, Char(문자열)필드로 지정하고 , 문자열의 최대길이는 200으로 지정해준다
pub_date = models.DateTimeField('date published')
# pub_date 라는 db를 생성하고 DateTime(날짜시간)필드로 지정한다
def __str__(self):
return self.question_text
# model 클래스 내부에 __str__ 함수를 정의해주면 해당 model 생성시 관리자페이지에서 해당 model(Question)의 question_text의 값을 출력해준다. (쉽게 말해 관리자페이지에서 보기 편하게 만들어준다)
def was_published_recently(self):
return self.pub_date >= timezone.localtime() - datetime.timedelta(days=1)
# was_published_recently 함수를 만든이유는 pub_date 필드가 days=1(하루전)이면 True를 반환한다.
# timezone.localtime() - datetime.timedelta(days=1) 은 하루 전 날짜를 반환한다.
class Choice(models.Model):
question = models.ForeignKey(Question,on_delete=models.CASCADE)
# question 이라는 db를 생성하고 Question이라는 클래스와 관계형데이터베이스(ForeignKey)를 맺는다
# on_delete는 관계형데이터베이스 값이 삭제될때 해당 db도 삭제된다는 의미
choice_text = models.CharField(max_length=200)
votes = models.IntergerField(default=0)
# votes라는 db를 생성하고 숫자형(Interger)필드로 지정한다. 모든 필드는 default로 기본값 설정이 가능하다
def __str__(self):
return self.choice_text
https://docs.python.org/ko/3/library/datetime.html
https://nachwon.github.io/django-field/
파이썬 >>> (쉘) 처럼 장고에서도 즉각적으로 db를 넣고 db를 조회하고 db를 삭제할 수 있는 쉘 api가 존재한다.
python manage.py shell
* 쉘
>>> from polls.models import Choice, Question
>>> from django.utils import timezone
>>> q = Question(question_text="What`s new?",pub_date=timezone.localtime())
# q 라는 Question db를 생성함. qustion_text 필드에는 what`s new? 라는 질문이 들어가고 pub_date 라는 필드에는 django.utils 모듈에 존재하는 timezone 함수를 사용해 현재 시간을 넣어줌
>>> q.save()
# save함수로 db를 저장해준다
>>> q.id()
# q라는 db에 id라는 필드를 생성해준적이 없는데 1이 반환된다. 자동으로 생성되는 고유 id값이라고 생각된다.
>>> q.question_text
# q 라는 db의 question_text 필드의 값을 반환해준다. (what`s new? 가 반환됨)
>>> q.pub_date
# q 라는 db의 pub_date 필드의 값을 반환해준다.
>>> Question.objects.all()
# Question 객체로 정의된 db를 모두 반환한다.
>>> Question.objects.filter(id = 1)
# id가 1값을 가지고있는 Question db를 검색한다
>>> Question.objects.filter(question_text__startswith="what")
# question_text가 'what' 으로 시작되는 것을 검색한다 (__startswith 옵션은 시작되는 문자열이나 숫자를 검색)
>>> Question.objects.filter(pub_date__year__startswith=2020)
# pub_date 의 __year은 따로 model에 정의를 안해줘도 datetime 필드에 기본으로 내장되어있다. 년도를 반환한다. __startswith 옵션으로 pub_date의 년도가 2020으로 시작되는 Question 모델 db를 검색한다
>>> Question.objects.filter(question_text__endswith="what")
# question_text가 'what' 으로 끝나는 것을 검색한다 (__endswith 옵션은 끝나는 문자열이나 숫자를 검색)
>>> Question.objects.get(pub_date__year=current_year)
>>> Question.object.get(id=2)
# Question이라는 model을 가진 db중 고유 필드인 id가 2인 db를 가져옴
# 고유 필드인 id가 2인 db가 없으니 err
>>> q = Question.objects.get(pk=1)
# q라는 db에 Question이라는 model을 가진 db중 고유 필드인 pk 값이 1인 db를 가져와 q에 저장함
>>> q.choice_set.all()
# q라는 db(Question모델)와 관계형 데이터베이스(ForeignKey)인 Choice 모델로 생성된 Choice db 목록을 반환한다.
# 아직 Choice 모델로 db를 생성한적이 없으니 아무것도 반환되지 않는다.
>>> q.choice_set.create(choice_text='The sky',votes=0)
# q라는 db(Question모델)와 관계형 데이터베이스인 Choice 모델로 Choice db를 생성해주고 q라는 db에 넣고 셋팅까지 해준다.
>>> q.choice_set.count()
# q 라는 db(Question모델)와 관계형 데이터베이스인 Choice 모델 db의 갯수를 반환한다.
>>> Choice.objects.filter(question__pub_date__year=current_year)
# Choice 모델 db와 관계형 데이터베이스인 Question 모델 db의 pub_date 필드가 current_year과 같은 Choice 모델 db를 검색한다.
>>> q.choice_set.filter(choice_text__startswith='The')
# q라는 Question 모델 db와 관계형 데이터베이스인 Choice 모델 db의 choice_text 필드가 The 로 시작되는 db를 검색
>>> c = q.choice_set.filter(choice_text='The sky')
# q라는 Question 모델 db에 Question 모델과 관계형 데이터베이스인 Choice 모델의 db의 choice_text 필드가 The sky 인 Choice 모델 db를 c라는 변수에 담는다
>>> c.delete()
# c라는 db를 삭제한다.
# c라는 변수에 따로 Choice 모델 db 를 담았어도 q 라는 Question 모델 db의 Choice 모델 db가 사라진다.
장고에서 꺼내기 함수는 다양하다.
모델명.objects.꺼내기함수()
ex) Question모델에서 자료를 꺼낼 경우 Question.object.함수()
Choice모델에서 자료를 꺼낼 경우 Choice.object.함수()
all()
all()함수는 있는 자료를 모두 꺼내온다.
all()함수를 통해서는 모든 자료를 꺼낼 수 있지만 문제는 저장한 순서대로 출력이 된다는 점이 있다.
order_by(필드명)
order_by()는 순번을 정해서 가져온다
order_by는 내부 파라미터로 문자열을 받을 수 있고,
order_by('필드명') 으로 적을 경우 컬럼명을 기준으로 순서를 정한다.
내부에 컬럼명을 적을 때 ('필드명')일 경우 오름차순
그리고 내림차순으로 출력시는 ('-필드명') 을 사용하면 된다.
get(필드명=값)
get() 함수는 특정 요소만 집어서 가져오기 위해 사용한다.
특정 요소를 가져오기 위해 파라미터값으로
필드명 = 값 와 같이 조건을 집어넣을 수 있다.
가령 pk=3 이라고 집어넣는다면
이것은 고유 pk필드가 3인, 즉 3번째에 있는 자료를 넘겨달라는 의미이다.
get_object_or_404(모델명, 조건)
get_object_or_404() 함수는 가져올 자료가 있을때만 자료를 가져오고 자료가 없으면 에러를 발생시킵니다. 즉, 자료가 없을 경우 404 에러를 발생시켜 외부에서 db 에러를 못보게 할 수 있다.(보안에 유리함)
filter(필드명=값)
특정 필드에 있는 값을 검색한다.
filter(필드명=값).first() 또는 filter(필드명=값).last()
first()는 첫번째 db 반환, last()는 마지막 db를 반환한다.
filter(필드명=값).values()
클래스명.objects.filter(필드명=값).values() 는 filter의 조건에 맞는 db의 모든 필드명과 모든 값들을 리스트 + 딕셔너리 형태로 가져온다
get() 쿼리셋은 무조건 하나만 가져올 수 있다. filter와 차이점이 이특징에있다. get() 쿼리셋은 어떠한 조건을 주었을 때 리턴되는 db가 여러개면 무조건 에러 , filter는 여러개를 가져올 수 있다.
클래스명(테이블명).objects.create(필드명=값)
클래스명(테이블명)(필드명=값)
두 방식의 차이점은 create() 로 db 생성시에는 .save()를 할 필요가 없고, 클래스명() 으로 db 생성시에는 무조건 .save()로 db를 저장해주어야한다.
클래스명.objects.filter().update(필드명=값)
db명.필드명=값
둘의 차이점은 db명.필드명=값 방법으로 db를 수정시에는 무조건 .save() 로 저장해주어야 한다.
클래스명.objects.filter(필드명=값).delete
filter로 조건에 검색된 db를 삭제한다.
timezone.localtime() 을 쓰면 한국시간대로 나타낸다.
python manage.py createsuperuser
http://127.0.0.1:8000/admin 으로 접속하면 장고 관리자 사이트에 접속할 수 있다.
장고에서 기본으로 제공되는 인증 프레임워크 (사용자,그룹 관리)를 볼 수 있다.
인증 프레임워크는 django.contrib.auth 모듈에서 제공된다.
관리자 사이트에서 특정 앱의 모델db를 추가, 삭제, 변경하거나 커스터마이징 하려면 특정 앱의 디렉터리에 admin.py 를 수정해주면 된다.
* polls 디렉터리 내부의 admin.py 수정
from django.contrib import admin
from .models import Question
admin.site.register(Question)
ps aux|grep -i manage (manage를 실행하고있는 프로세스 id목록 확인)
kill -9 죽일프로세스id (해당 프로세스를 죽임)