최근 Django을 공부 하면서, 이것 저것 기록해 놓으려고 한다. 해당 글은Python 3.7.4, Django 3.1.7
을 기준으로 쓰여졌다Django 한글 메뉴얼: https://docs.djangoproject.com/ko/3.1/ 점프 투 쟝고: https://wikidocs.net/book/4223 시작하기 - Django 설치:C:\django> python --version Python 3.7.4 C:\django> django-admin --version 3.1.7pip install django==3.1.7
- 프로젝트 생성:django-admin startproject {명칭} .
config파일들이 들어 있기 때문에django-admin startproject config .
식으로 해주면 좋다. startproject뒤에 오는 문구가 프로젝트의 이름 및 Django의 기본적인 셋팅 파일이 있는 디렉토리의 명칭이 된다. "."을 뒤에 붙일 경우 새로운 디렉토리를 생성하지 않고 해당 디렉토리에 만들어 진다. - 앱 생성:django-admin startapp {명칭}
- 개발 서버 구동:python manage.py runserver 8000
Django가 설치된 디렉토리에서 실행해야 한다. reunserver뒤에 붙은 숫자가 port번호가 된다. 0.0.0.0:8000 식으로 쓰면 외부에서도 접속 가능한 서버가 된다. config/settings.py - 언어와 시간을 한국으로 바꾸어 주면 한글로 바뀐다. - USE_TZ를 False로 설정해야 시간차이가 발생하지 않는다.- DATABASES 설정# LANGUAGE_CODE = 'en-us' LANGUAGE_CODE = 'ko-kr' # TIME_ZONE = 'UTC' TIME_ZONE = 'Asia/Seoul' # USE_TZ = True USE_TZ = False
- static 폴더 설정#기본설정은 sqlite로 되어 있어 있다. # python manage.py migrate 시에 sqlite 파일이 생성된다. DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': BASE_DIR / 'db.sqlite3', } } # mysql 설정 DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'django_test', 'USER': 'root', 'PASSWORD': '1234', 'HOST': 'localhost', 'PORT': '3306', } } # mssql 설정 DATABASES = { 'default': { 'NAME' : 'name', 'USER' : 'user', 'PASSWORD' : 'password', 'HOST' : 'host', 'PORT' : '1433', 'OPTIONS' : { 'driver' : 'ODBC Driver 17 for SQL Server', 'MARS_Connection' : True, 'driver_supports_utf8' : True, }, } }
Auth 모델 커스텀 하기 - Django에서는 Auth_user 모델이 기본적으로 migration 되어 있다. - user의 기본적인 migration을 변경하려면, 최초에 migrate를 하기 전에 아래 작업을 진행해야 한다. - 한번이라도 migrate를 한 뒤에 아래를 진행하면, user_auth테이블이 이미 있어서, dependency(의존성) 오류가 떠버린다 - 한번이라도 migrate를 한 뒤에 Auth모델을 수정하려면, migration관련 파일을 수정하고, 삭제하고 초기화 시키는 방식이 있긴 하지만 추천하진 않는다. - 아래는 커스텀 Auth모델을 만드는 방법이다. 1. django-admin startapp 명령어로 새로운 앱을 만든다. - 앱 이름을 auth로 만들경우 Application labels aren't unique, duplicates: auth 에러가 뜨니 유의바람# 해당 설정후에 /static 폴더를 생성해야 한다. STATIC_URL = '/static/' STATICFILES_DIRS = [ BASE_DIR / 'static', ]
2. config\settings.py에 앱 등록 및 모델 정의 추가C:\django> django-admin startapp authm3. authm\models.py에 새로 정의될 User모델 추가 - 아래와 같이 코딩할 경우, 이미 정의된 auth_user모델의 컬럼에 새로 정의한 컬럼이 추가되는 형태가 된다.AUTH_USER_MODEL = 'authm.User' INSTALLED_APPS = [ 'authm.apps.AuthmConfig', . . . ]
4. makemigrations후에 migrate 실행from django.db import models from django.contrib.auth.models import AbstractUser class User(AbstractUser): level = models.CharField(null=True, max_length=2) # 권한 department = models.CharField(null=True, max_length=100) # 부서 position = models.CharField(null=True, max_length=100) # 직책
5. DB에 접속해서 확인해보면, 원래 생겨야 하는 auth_user테이블 대신, authm_user 테이블이 생긴 것을 확인 할 수 있다. - 차후 user모델에 새로운 컬럼을 추가 할 일이 생기면 위 모델을 통해 수정이 가능하다 config/urls.py - URL 맵핑 페이지 - path등록시 주소뒤에 "/"안붙이면 페이지 오류 뜸. - 일반적인 url 설정 방식 config\urls.pyC:\django> python manage.py makemigrations Migrations for 'authm': authm\migrations\0001_initial.py - Create model User C:\django> python manage.py migrate Operations to perform: Apply all migrations: admin, auth, authm, contenttypes, sessions Running migrations: Applying contenttypes.0001_initial... OK . . Applying auth.0012_alter_user_first_name_max_length... OK . . Applying sessions.0001_initial... OKauthm\urls.py(새로 만들어야함)from django.contrib import admin from django.urls import path, include from django.contrib.auth import views as auth_views urlpatterns = [ path('admin/', admin.site.urls), path('login/', auth_views.LoginView.as_view(template_name='login.html'), name='login'), path('logout/', auth_views.LogoutView.as_view(), name='logout'), path('authm/', include('authm.urls')), ]
authm/views.pyfrom django.urls import path from . import views app_name = 'authm' urlpatterns = [ path('test1', views.test1), ]
- 위와 같이 코딩시에 /authm/test1에 접속시 'authm test1 page'문구가 뜨게 된다 모델 -from django.shortcuts import render from django.http import HttpResponse def test1(request): return HttpResponse('authm test1 page')
python manage.py makemigrations
migration파일 생성 -python manage.py migrate
migration파일을 바탕으로 실제 테이블 생성 - 모델 예제- 필드 타입 종류 링크1: https://docs.djangoproject.com/ko/3.2/ref/models/fields/ 링크2: https://brunch.co.kr/@ddangdol/4 - 쿼리 사용 예제from django.db import models class test(models.Model): class Meta: db_table = 'test' idx = models.AutoField(primary_key=True) name = models.CharField(null=True, max_length=50) type = models.IntegerField(null=True) r_date = models.DateTimeField(null=True)
- 조건 키워드 - 참고링크: https://brownbears.tistory.com/63from django.http import HttpResponse from django.utils import timezone from authm.models import testbl_1 def orm_test(request): now = timezone.now() # delete - all() # 모든 행을 삭제 q = testbl_1.objects.all() q.delete() # insert q = testbl_1(name='aaa', memo='memo1', r_date=now) q.save() # insert - used dictionary tmp1 = { 'name': 'bbb', 'memo': 'memo2', 'r_date': now, } q = testbl_1(**tmp1) q.save() # insert - creat() tmp1 = { 'name': 'ccc', 'memo': 'memo3', 'r_date': now, } testbl_1.objects.create(**tmp1) # select - all() # order_by에 -를 붙이면 해당 컬럼에 대해서 내림차순으로 가져옴 q = testbl_1.objects.all().order_by('-idx') for v in q: # 기본적으로는 object형태로 되어 있음 print(v.name, v.memo, v.r_date) # dictionary로 결과 출력 v_d = v.__dict__ print( v_d['name'], v_d['memo'], v_d['r_date'] ) # print 결과 # bbb memo2 2021-05-06 08:00:45.774422+00:00 # aaa memo1 2021-05-06 08:00:45.774422+00:00 # select - filter() q = testbl_1.objects.filter(name='aaa') for v in q: print(v.name, v.memo, v.r_date) # aaa memo1 2021-05-06 08:00:45.774422+00:00 # select - filter() - used dictionary tmp1 = { 'name': 'bbb', 'memo': 'memo2', } q = testbl_1.objects.filter(**tmp1) for v in q: print(v.name, v.memo, v.r_date) # bbb memo2 2021-05-06 08:05:04.338555+00:00 # select - latest() # filter는 검색결과가 없으면 []을 반환해서 상관 없지만, # latest(), get()은 반환결과가 없으면 DoesNotExist오류가 뜨기 때문에 try문 필수 try: max = testbl_1.objects.latest('idx') max_idx = max.idx+1 except testbl_1.DoesNotExist: max_idx = 1 print(max_idx) # select - get() # get()은 단일 결과만 가져오기 때문에 결과가 2개 이상이면, MultipleObjectsReturned오류가 뜬다 try: ddd = testbl_1.objects.get(name='ddd') # ddd = testbl_1.objects.get(memo__icontains='memo') c_name = ddd.name except testbl_1.DoesNotExist: c_name = 'DoesNotExist' except testbl_1.MultipleObjectsReturned: c_name = 'MultipleObjectsReturned' print(c_name) # Nothing # update - get() # 하나의 요소만 가져와서 update 하는 방식 q = testbl_1.objects.get(name='aaa') q.name = 'abc' q.save() # update - filter() # 여러개 결과를 for문으로 update 하는 방식 q = testbl_1.objects.filter(memo__icontains='memo') # memo like검색 for v in q: v.name = 'ddd' v.save() # update - filter(), update() # 여러개 결과를 한번에 update 하는 방식 update_arr ={ 'name': 'eee' } testbl_1.objects.filter(memo__icontains='memo').update(**update_arr) return HttpResponse('orm_test page')
키워드 | 설 명 | 사용예 |
---|---|---|
__lt / __gt __lte / __gte | 보 다 작다 / 보다 크다 같거나 보다 작다 / 같거나 보다 크다 | id가 1보다 큰 자료 검색 >>> Department.objects.filter(id__gt=1) [<Department: Computer Science>] |
__in | 주어진 리스트 안에 존재하는 자료 검색 | id 가 2, 3, 5 인 자료 검색 >>> Department.objects.filter(id__in=[2, 3, 5]) |
__year / __month / __day | 해당 년도, 월, 일 자료 검색 | >>>Entry.objects.filter(pub_date__year=2005) |
__isnull | 해 당 열의 값이 null 인 자료 검색 | >> Department.objects.filter(dName__isnull=True) [] |
__contains / __icontains | 해당 열의 값이 지정한 문자열을 포함하는 자료 검색 (__icontains 는 대소문자를 구별하지 않음) | >>> Department.objects.filter(dName__contains='puter') [<Department: Computer Science>] |
__startswith / __istartswith | 해당 열의 값이 지정한 문자열로 시작하는 자료 검색 (__istartswith 는 대소문자를 구별하지 않음) | >>> Department.objects.filter(dName__startswith='Com') [<Department: Computer Science>] |
__endswith / __iendswith | 해당 열의 값이 지정한 문자열로 끝나는 자료 검색 (__iendswith 는 대소문자를 구별하지 않음) | >>> Department.objects.filter(dName__contains='nce') [<Department: Computer Science>] |
__range | 문 자, 숫자, 날짜의 범위를 지정함 (SQL의 BETWEEN에 | >>> Department.objects.filter(id__range=(2, 10)) |
from django.http import HttpResponse
# from django.contrib.auth.models import User # 기본으로 제공되는 User
from authm.models import User # 새롭게 정의한 User
from django.contrib.auth.hashers import make_password
def user_insert(request):
insert_arr = {
'password': make_password('1234'),
'is_superuser': 0,
'username': 'aaa',
'first_name': 'f_name',
'last_name': 'l_name',
'email': 'aaa@blix.net',
'is_staff': 1,
'is_active': 1,
'level': 1,
'department': 'team1',
'position': 'Senior',
}
User.objects.create(**insert_arr)
return HttpResponse('user insert')
def user_update(request):
update_arr = {
'password': make_password(request.GET['pwd']),
'position': request.GET['position'],
}
User.objects.update(**update_arr)
return HttpResponse('user update')
def user_delete(request):
User.objects.filter(id=1).delete()
return HttpResponse('user delete')
- datatables의 serverSide옵션일때의 ORM
from django.db.models import Q
from datas.models import dt_tbl1
def all_list(request):
tmp_data = {
"data":[],
"diagnosis":{},
}
p_start = int(request.POST['start'])
p_end = p_start+int(request.POST['length'])
order_col = request.POST['columns['+request.POST['order[0][column]']+'][name]']
if request.POST['order[0][dir]'] == 'desc':
order_col = '-'+order_col
if request.POST['search[value]'] == '':
tmp_data['recordsFiltered'] = dt_tbl1.objects.count()
q = dt_tbl1.objects.all().order_by(order_col)[p_start:p_end]
else:
val1 = request.POST['search[value]']
q_filter = Q()
or_filters = {}
for i in range(1,41):
or_filters['a'+str(i)+'__icontains'] = val1
for item in or_filters:
q_filter |= Q(**{item:or_filters[item]})
q = dt_tbl1.objects.filter(q_filter).order_by(order_col)[p_start:p_end]
tmp_data['recordsFiltered'] = dt_tbl1.objects.filter(q_filter).count()
for v in q:
tmp_d = {
"idx": v.idx,
"r_date": str(v.r_date)[:19],
}
v_d = v.__dict__
for i in range(1,41):
j = 'a'+str(i)
tmp_d[j] = v_d[j]
tmp_data['data'].append(tmp_d)
return tmp_data
shell
- from django.contrib.auth.decorators import login_required
# @login_required 사용후 보낼 url을 설정해주면 된다.
@login_required(login_url='login')
def index(request):
...
로그인시에 체크 하는 로직
- 아무 앱의 models.py에 만들어 놓으면 된다.
from django.contrib.auth.signals import user_logged_in
from authm.models import User
# 사용자의 ip를 가져오는 함수
def get_client_ip(request):
x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
if x_forwarded_for:
ip = x_forwarded_for.split(',')[0]
else:
ip = request.META.get('REMOTE_ADDR')
return ip
# 로그인시 실행될 함수
def login_chk(sender, user, request, **kwargs):
update_arr ={
'login_ip': get_client_ip(request)
}
User.objects.filter(username=user).update(**update_arr)
# 로그인시에 실행되도록 하는 부분
user_logged_in.connect(login_chk)