explore 창 - 프로젝트 오른쪽 클릭 - Django - Make Migrations - sqlapp
explore 창 - 프로젝트 오른쪽 클릭 - Django - Migrate
* admin계정 id 생성 - anconda prompt 창 실행
cd C:\work\psou\django_test04_sqlite
python manage.py createsuperuser
=> id / e-mail / password 설정
- http://127.0.0.1/admin/ 접속 후 login
- table data 입력
* admin
from django.contrib import admin
from sqlapp.models import Article
# Register your models here.classArticleAdmin(admin.ModelAdmin):
list_display = ('id', 'code', 'name', 'price', 'pub_date')
admin.site.register(Article, ArticleAdmin)
class 클래스명(admin.ModelAdmin):
list_display = ('칼럼명1', ... )
admin.site.register(테이블명, 클래스명)
=> 테이블과 admin계정 연결
* views
from django.shortcuts import render
from sqlapp.models import Article
# Create your views here.defMain(request):return render(request, "main.html")
defDbTestFunc(request):
datas = Article.objects.all() # 장고의 ORM. select * from Article 이 내부적으로 수행. list 타입으로 리턴.#print(datas) # <QuerySet [<Article: Article object (1)>, <Article: Article object (2)>, <Article: Article object (3)>]>#print(datas[0].name) # 아아return render(request, 'list.html',{'articles':datas}) # QuerySet을 전달.
models.py의 클래스명.objects.all() : select * from 테이블명(클래스명)
* main.html
<!DOCTYPE html><html><head><metacharset="UTF-8"><title>Insert title here</title></head><body><h2>메인</h2><ahref="show/">자료 보기</a></body></html>
* list.html
<!DOCTYPE html><html><head><metacharset="UTF-8"><title>Insert title here</title></head><body>
Article 자료 보기 - Djang template language 사용 <br>
{% if articles.count %}
{% for a in articles %}
<b>{{a.code}}</b> {{a.name}} {{a.price}} {{a.pub_date}}<br>
{% endfor %}
{% else %}
<p>자료가 없습니다.</p>
{% endif %}
</body></html>
{% if 조건 %}
{% else %}
{% endif %}
=> if 문
{% for 변수 in 자료 %}
{% endfor %}
=> for 문
6. where, group by
* settings
INSTALLED_APPS = [
...
'sql_app',
]
=> application연결
* models
from django.db import models
# Create your models here.classProfile(models.Model):
name = models.CharField(max_length = 10)
age = models.IntegerField()
=> DB 테이블 생성
- explore 창 - 프로젝트 오른쪽 클릭 - Django - Create application - sqlapp
-explore 창 - 프로젝트 오른쪽 클릭 - Django - Make Migrations - sqlapp
-explore 창 - 프로젝트 오른쪽 클릭 - Django - Migrate
해당 프로젝트 cmd 창 : python manage.py createsuperuser
* admin
from django.contrib import admin
from sql_app.models import Profile
# Register your models here.classProfileAdmin(admin.ModelAdmin):
list_display = ('id', 'name', 'age')
admin.site.register(Profile, ProfileAdmin)
=> 테이블과 admin 계정 연결.
- http://127.0.0.1/admin/ 접속 후 login
- table data 입력
* urls
from django.contrib import admin
from django.urls import path
from sql_app import views
urlpatterns = [
path('admin/', admin.site.urls),
path('', views.IndexFunc),
path('calldata/', views.CallFunc),
]
=> url과 views 연결
* views
from django.shortcuts import render
from sql_app.models import Profile
from django.db.models.aggregates import Avg, Count, Max, Min, Sum
# Create your views here.
def IndexFunc(request):
return render(request, 'index.html')
def CallFunc(request):
profile_list = Profile.objects.all() # 전체 자료 list로 리턴
forrowin profile_list.values_list(): # 리스트의 값들 리턴
print(row)
print(Profile.objects.aggregate(Avg('age'))) # selectavg(age) from Profile
print(Profile.objects.aggregate(Max('age')))
print(Profile.objects.aggregate(Sum('age')))
print(Profile.objects.aggregate(Count('age')))
print(len(profile_list))
print(Profile.objects.filter(name ='홍길동').aggregate(Avg('age'))) # where 조건
qs = Profile.objects.values('name').annotate(Avg('age')) # group 별 작업
for r in qs:
print(r)
pro_list = []
for pro in profile_list:
pro_dict ={}
pro_dict['name'] = pro.name
pro_dict['age'] = pro.age
pro_list.append(pro_dict)
print(pro_list)
# [{'key1':value1, 'key2':value2, ... }, {'key1':value1, 'key2':value2, ... }, ... ]
context = {'pro_list':pro_list}
return render(request, 'list.html', context)
QuerySet 타입.values_list() : value list 리턴
테이블명.objects.aggregate(Avg('칼럼명')) : select avg(칼럼명) from 테이블명
테이블명.objects.aggregate(Max('칼럼명')) : select max(칼럼명) from 테이블명
테이블명.objects.aggregate(Sum('칼럼명')) : select sum(칼럼명) from 테이블명
테이블명.objects.aggregate(Count('칼럼명')) : select count(칼럼명) from 테이블명
테이블명.objects.filter(칼럼명=값) : select * from 테이블명 where 칼럼명 = 값
테이블명.objects.values('칼럼명').annotate(Avg('칼럼명')) : select avg(칼럼명) from 테이블명 group by 칼럼명
* index.html
<!DOCTYPE html><html><head><metacharset="UTF-8"><title>Insert title here</title></head><body>
메인(QuerySet Test)<br><ahref="calldata/">db 자료를 읽어 dict type으로 출력</a><br><ahref="admin/">장고가 지원하는 관리자 창</a></body></html>
* list.html
<!DOCTYPE html><html><head><metacharset="UTF-8"><title>Insert title here</title></head><body>
자료 보기</p>
{{pro_list}}
</body></html>
7. 원격 DB
= django_test06_mariadb
DB 접속하여 DataBase 생성
explore 창 - 프로젝트 오른쪽 클릭 - Django - Create application - myguset
* settings
INSTALLED_APPS = [
...
'myguest',
]
...
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'yourdb', # DB명 : db는 미리 작성되어 있어야 함. 'USER': 'root', # 계정명 'PASSWORD': '123', # 계정 암호 'HOST': '127.0.0.1', # DB가 설치된 컴의 ip 'PORT': '3306', # DBMS의 port 번호
}
}
DATABASES = { 'default': {
django.db.backends.mysql',
'NAME': 'database명', # DB명 : db는 미리 작성되어 있어야 함. 'USER': 'root', # 계정명 'PASSWORD': '123', # 계정 암호 'HOST': '127.0.0.1', # DB가 설치된 pc의 ip 'PORT': '3306', # DBMS의 port 번호 } }
<!DOCTYPE html><html><head><metacharset="UTF-8"><title>Insert title here</title></head><body><h2>메인화면</h2><ul><li><ahref="list1">상품 제조사 보기</a></li><li><ahref="list2">상품 목록 보기</a></li><li>묻고 답하기</li></ul></body></html>
* list1.html
<!DOCTYPE html><html><head><metacharset="UTF-8"><title>Insert title here</title></head><body><h2>제조사 목록</h2><tableborder="1"><tr><th>아이디</th><th>제조사</th><th>전화번호</th><th>주소</th></tr>
{% if makers %}
{% for m in makers %}
<tr><td>{{m.id}}</td><td><ahref="list3?id={{m.id}}">{{m.mname}}</a></td><td>{{m.tel}}</td><td>{{m.addr}}</td></tr>
{% endfor %}
{% else %}
<tr><tdcolspan="4">자료가 없습니다.</td></tr>
{% endif %}
</table></body></html>
* list2.html
<!DOCTYPE html><html><head><metacharset="UTF-8"><title>Insert title here</title></head><body><h2>상품 목록</h2><tableborder="1"><tr><th>아이디</th><th>상품명</th><th>가격</th><th>제조사</th></tr>
{% if products %}
{% for p in products %}
<tr><td>{{p.id}}</td><td>{{p.pname}}</td><td>{{p.price}}</td><td>{{p.maker_name}}</td></tr>
{% endfor %}
<tr><tdcolspan="4">건수{{pcount}}</td><tr>
{% else %}
<tr><tdcolspan="4">자료가 없습니다.</td></tr>
{% endif %}
</table></body></html>
9. DB - CRUD, 페이징
① 메인 페이지
= django_test08_sangdata
* settings
...
INSTALLED_APPS = [
...
'mysangpum',
]
...
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'test', # DB명 : db는 미리 작성되어 있어야 함. 'USER': 'root', # 계정명 'PASSWORD': '123', # 계정 암호 'HOST': '127.0.0.1', # DB가 설치된 컴의 ip 'PORT': '3306', # DBMS의 port 번호
}
}
...
TIME_ZONE = 'Asia/Seoul'
USE_TZ = False
TIME_ZONE = 'Asia/Seoul' USE_TZ = False
=> admin 페이지에 표시되는 시간은 기본적으로 UTC(UTC+9)이므로, 입력을 해도 9시간 전으로 표시된다. 이에 표시되는 시간과 실제 DB에 입력되는 시간을 모두 Local시간(UTC)으로 맞춰 주어야 한다
* remote DB의 데이터를 Django 형식으로 불러오기
anconda 접속
cd C:\work\psou\django_test08_sangdata
python manage.py inspectdb > abc.py
=> 이미 생성되어 있는 DB를 django 형식으로 abc.py에 코드 자동 작성.
* models
from django.db import models
# Create your models here.classSangdata(models.Model):
code = models.IntegerField(primary_key=True)
sang = models.CharField(max_length=20, blank=True, null=True)
su = models.IntegerField(blank=True, null=True)
dan = models.IntegerField(blank=True, null=True)
classMeta:
managed = False
db_table = 'sangdata'
=> abc.py의 sangdata table 내용 입력
- Django - Make migrations - mysangpum
- Django - Migrate
* urls(django_test08_sangdata)
from django.contrib import admin
from django.urls import path
from mysangpum import views
from django.urls.conf import include
urlpatterns = [
path('admin/', admin.site.urls),
path('', views.MainFunc),
path('sangpum/', include('mysangpum.urls')), # 요청 위임
]
<!DOCTYPE html><html><head><metacharset="UTF-8"><title>Insert title here</title></head><body><h2>메인</h2><ahref="sangpum/list">상품보기(MariaDB)</a></body></html>
<!DOCTYPE html><html><head><metacharset="UTF-8"><title>Insert title here</title><linkrel="stylesheet"href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css"><scriptsrc="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script><scriptsrc="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script></head><body><h2>상품자료</h2><divstyle="width:80%; text-align:right;"><ahref="/sangpum/insert">상품 추가</a></div><tableclass="table"style="width:80%;"><tr><th>code</th><th>상품</th><th>수량</th><th>단가</th><th>기타</th></tr>
{% if sangpums %}
{% for s in sangpums%}
<tr><!-- <td>{{s.0}}</td> --><td>{{s.code}}</td><td>{{s.sang}}</td><td>{{s.su}}</td><td>{{s.dan}}</td><td><ahref="/sangpum/update?code={{s.code}}">수정</a> /
<ahref="/sangpum/delete?code={{s.code}}">삭제</a></td></tr>
{% endfor%}
{% else %}
<tr><tdcolspan="5">자료가 없습니다.</td></tr>
{% endif%}
</table></body></html>
③ 페이징 처리
* views
defListFunc(request):
...
# 페이지 나누기 처리 - Paginator 클래스
datas = Sangdata.objects.all().order_by('-code') # order by code desc
paginator = Paginator(datas, 3) # 페이지당 출력 행수를 생성자로 전달try:
page = request.GET.get('page') # page 값을 readexcept:
page = 1# page 값이 없을 경우 1 page 출력try:
data = paginator.page(page)
except PageNotAnInteger: # page가 숫자가 아닐 경우
data = paginator.page(1)
except EmptyPage:
data = paginator.page(paginator.num_pages()) # 현재 페이지 출력# 클라이언트 화면에 개별 페이지 번호 표시용
allPage = range(paginator.num_pages + 1)
#print('allPage : ', allPage) # range(0, 5)return render(request, 'list2.html', {'sangpums':data, 'allPage':allPage})
paginator = Paginator(데이터, 출력행수) : 객체 생성. 페이지당 출력 행수를 생성자로 전달
paginator.page(출력페이지) : 나눠진 페이지에서 출력할 페이지 입력.
paginator.num_pages : 총페이지 수
* list2.html
<!DOCTYPE html><html><head><metacharset="UTF-8"><title>Insert title here</title><linkrel="stylesheet"href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css"><scriptsrc="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script><scriptsrc="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script><scripttype="text/javascript">functionfunc(){
//alert("aa");let result = confirm("정말 삭제 할까요?")
if(result){
frm.submit();
}
}
</script></head><body><h2>상품자료</h2><divstyle="width:80%; text-align:right;"><ahref="/sangpum/insert">상품 추가</a></div><tableclass="table"style="width:80%;"><tr><th>code</th><th>상품</th><th>수량</th><th>단가</th><th>기타</th></tr>
{% if sangpums %}
{% for s in sangpums%}
<tr><!-- <td>{{s.0}}</td> --><td>{{s.code}}</td><td>{{s.sang}}</td><td>{{s.su}}</td><td>{{s.dan}}</td><td><ahref="/sangpum/update?code={{s.code}}">수정</a> /
<!-- 삭제 전에 묻는 작업이 필요 --><formaction="/sangpum/delete"name="frm"method="get"style="display:inline;"><inputtype="hidden"name="code"value="{{s.code}}"><ahref="javascript:void(0); onclick=func()">삭제</a></form></td></tr>
{% endfor%}
<!-- paging --><tr><tdcolspan="5">
{% if sangpums.paginator.num_pages > 1 %}
<ulclass="pager">
{% if sangpums.has_previous %}
<liclass="previous"><ahref="/sangpum/list?page={{sangpums.previous_page_number}}">Previous</a></li><!-- <li><a href="/sangpum/list?page={{sangpums.previous_page_number}}">«이전</a></li> -->
{% endif %}
{% if sangpums.has_next %}
<liclass="next"><ahref="/sangpum/list?page={{sangpums.next_page_number}}">Next</a></li><!-- <li><a href="/sangpum/list?page={{sangpums.next_page_number}}">다음»</a></li> -->
{% endif %}
<li>(페이지 : {{sangpums.number}} / {{sangpums.paginator.num_pages}})</li></ul><hr>
{% for p in allPage%}
{% if p > 0 %}
{% if p == sangpums.number %}
[{{p}}]
{% elif p != sangpums.number %}
<ahref="/sangpum/list?page={{p}}]"> {{p}} </a>
{% endif %}
{% endif %}
{% endfor%}
{% endif %}
</td></tr>
{% else %}
<tr><tdcolspan="5">자료가 없습니다.</td></tr>
{% endif%}
</table></body></html>
data.number : 현재페이지
data.paginator.num_pages : 총 페이지
④ 게시물 추가
* views
defInsertFunc(request):return render(request, 'insert.html')
defInsertokFunc(request):if request.method == 'POST':
code = request.POST.get("code")
#print('code : ', code)# 새로운 상품 code 유무 검증 작업 후 insert 진행try:
Sangdata.objects.get(code=code) # where#print('code 있음')return render(request, 'insert.html', {'msg':'이미 등록된 번호입니다.'})
except Exception as e:
#print('code 없음')
Sangdata(
code = request.POST.get("code"),
sang = request.POST.get("sang"),
su = request.POST.get("su"),
dan = request.POST.get("dan"),
).save()
return HttpResponseRedirect('/sangpum/list') # 추가 후 목록 보기
defDeleteFunc(request):
delRec = Sangdata.objects.get(code=request.GET.get('code'))
delRec.delete()
return HttpResponseRedirect('/sangpum/list') # 삭제 후 목록 보기
<!DOCTYPE html><html><head><metacharset="UTF-8"><title>Insert title here</title></head><body>
hi {{msg}} <- 장고의 template 변수 태그
<br><ahref="world">world 문서</a></body></html>
- Function views 방법 - Class-base views 방법 - Including another URL conf 방법
= django_test2
* settings.py
INSTALLED_APPS = [
'gpapp',
]
* urls.py(django_test2)
from django.contrib import admin
from django.urls import path
from gpapp import views
from gpapp.views import CallView
from django.urls.conf import include
urlpatterns = [
path('admin/', admin.site.urls),
path('', views.MainFunc, name='MainFunc'), # Function views 방법
path('gpapp/callget', CallView.as_view()), # Class-base views 방법
path('sangpum/', include('gpapp.urls')), # Including another URLconf 방법
]
path('url명', views.메소드명) : 해당 url이 수신 시 view.py의 해당 메소드 실행.
path('url명', 클래스명.as_view()) : 해당 url 수신 시 해당 클래스 실행.
path('url명', include('application명.urls')) : 해당 url이 포함됨 url 수신 시 해당 application의 urls 파일에서 나머지 url 연결하여 실행.
* views
from django.shortcuts import render
from django.views.generic.base import TemplateView
# Create your views here.defMainFunc(request):return render(request, 'index.html')
classCallView(TemplateView):
template_name = "callget.html"defInsertFunc(request):#return render(request, "insert.html") # get/post 모두 처리if request.method == 'GET':
print('GET 요청')
return render(request, "insert.html")
elif request.method == 'POST':
print('POST 요청')
name = request.POST.get("name")
name = request.POST.["name"]
return render(request,"list.html", {"name":name})
else:
print('요청 에러')
defSelectFunc(request):passdefUpdateFunc(request):pass
request.GET.get('key값') : GET 요청에서 key의 value를 get한다.
request.POST.get('key값') : POST 요청에서 key의 value를 get한다.
* index.html
<!DOCTYPE html><html><head><metacharset="UTF-8"><title>Insert title here</title></head><body>
두번째 프로젝트 메인화면
<p/>
GET/POST 연습<br><ahref="/gpapp/callget">callget 파일 요청 (get 방식)</a></body></html>
* callget.html
<!DOCTYPE html><html><head><metacharset="UTF-8"><title>Insert title here</title></head><body>
GET/POST 연습<br><ahref="/sangpum/insert">자료입력</a><br><ahref="/sangpum/select">자료보기</a><br><ahref="/sangpum/update">자료수정</a><br></body></html>
*urls.py(gpapp)
# 메인 urls가 각 app에 처리 위임from django.urls import path
from gpapp import views
urlpatterns = [
path('insert', views.InsertFunc),
path('select', views.SelectFunc),
path('update', views.UpdateFunc),
]
<!DOCTYPE html><html><head><metacharset="UTF-8"><title>Insert title here</title></head><body>
자료입력<p/><formaction="/sangpum/insert"method="post">{% csrf_token %}<!-- 해킹 방지 -->
이름 : <inputtype="text"name="name"><inputtype="submit"value="등록 확인"></form></body></html>
{% csrf_token %} : 해킹방지 코드
* list.html
<!DOCTYPE html><html><head><metacharset="UTF-8"><title>Insert title here</title></head><body>
결과 출력 : {{name}} {{123}} {{'문자열'}} {#주석#}
</body></html>
4. session
= django_test3_session
* settings
INSTALLED_APPS = [
...
'sessionapp'
]
* urls
from django.contrib import admin
from django.urls import path
from sessionapp import views
urlpatterns = [
path('admin/', admin.site.urls),
path('', views.mainFunc), # 1
path('setos', views.setosFunc), # 2
path('shows', views.showsFunc), # 3
]
* views
from django.shortcuts import render
from django.http.response import HttpResponseRedirect
# Create your views here.defmainFunc(request):# 1return render(request, 'main.html')
defsetosFunc(request):# 2if"favorite_os"in request.GET:
print(request.GET['favorite_os'])
request.session['f_os'] = request.GET["favorite_os"] # f_os 라는 키로 세션에 저장return HttpResponseRedirect('/shows') # 클라이언트를 통해서 shows 요청을 발생else:
print('a')
return render(request, 'setos.html')
defshowsFunc(request):# 3
context = {} # dict type 변수 생성if"f_os"in request.session:
context['f_os'] = request.session['f_os'] # request.session.get('f_os')
context['message'] = "선택된 운영체제 %s"%request.session['f_os']
else:
context['f_os'] = None
context['message'] = "운영체제를 선택하지않았습니다."
request.session.set_expiry(5); # session 유효 기간 5초 설정 return render(request, 'show.html', context)
HttpResponseRedirect('url명') : 클라이언트를 통해서 url요청명을 send.
value = request.session.get('key값'): session에 key값에 value값 get.
value = request.session['key값']: session에 key값에 value값 get.
request.session.set_expiry(초) : session 유효 시간 초 단위로 설정.
* main.html
<!DOCTYPE html><html><head><metacharset="UTF-8"><title>Insert title here</title></head><body>
메인화면<p/>
session 연습 : 세션이란 일정시간 동안 같은 사용자로 부터 들어오는 여러 가지 요구들을 하나의 상태를 보고 그 상태를 일정하게 유지 시킨 기술.
클라이언트와 서버 사이의 연결이 유지되는 것 처럼 하기 위해 클라이언트의 정보를 서버 컴퓨터의 일정 공간을 확보해 정보를 기억시킬 수 있다.
<br><ahref="/setos/">운영체제 선택하기</a></body></html>
* setos.html
<!DOCTYPE html><html><head><metacharset="UTF-8"><title>Insert title here</title></head><body><h2>2. 세션 이해하기</h2><p>운영체제 선택</p><ahref="/setos?favorite_os=window">윈도우</a><br><ahref="/setos?favorite_os=mac">mac</a><br><ahref="/setos?favorite_os=linux">리눅스</a><br></body></html>
=> url : setos, key : favorite_os, value : window, mac, linux
* show.html
<!DOCTYPE html><html><head><metacharset="UTF-8"><title>Insert title here</title></head><body><h2>3. 세션 결과보기</h2><p>반환된 context의 message : {{message}}</p><p>반환된 context의 f_os : {{f_os}}</p><p>session의 f_os 값 직접 출력: {{request.session.f_os}}</p><ahref="/setos">운영체제 다시 선택</a><ahref="/">main page</a></body></html>