2022. 5. 19. 16:53ㆍ해커톤, 개인 프로젝트/멋쟁이사자처럼 10기 해커톤
장고에 필요한 파이썬의 핵심 문법들
1. 자료형(딕셔너리)
- 대응이 되는 데이터를 표현해주고 싶을 때 사용
2. 예외처리
- 문법 에러(파싱 에러) : 실행 자체에 영향을 주는 치명적인 오류
- 예외 : 실행중 감지되는 오류, 프로그램 실행 자체를 멈추지는 않는 오류
- 프로그램을 에러로 인해 멈춤 없이 사용하고 싶을 때 사용
try:
# 일단 시도해 볼 것
# 오류가 생길 여지가 있는 코드
except 발생 오류:
# 발생 오류가 발생했을 때 실행할 코드
finally:
#예외가 발생했든 안했든 최종적으로 실행할 코드
3. 클래스와 객체
- 이 세상에 있는 것들은 모두 상태와 동작으로 나타낼 수 있다.
- 상태 -> 변수, 동작 -> 함수
- 상태와 동작을 한번에 여러 개 정의할 수 있는 방법 -> 객체 지향 프로그래밍
class Panda():
hp = 10
def move():
pass
def attack():
pass
# 객체
panda1 = Panda()
panda2 = Panda()
panda3 = Panda()
4. 모듈, 패키지, 라이브러리
- 모듈 -> 파이썬으로 정의된 파일 ex) a.py, b.py
# a.py
def sum(a, b):
return a+b
# b.py
import a
a.sum(1, 2)
- 패키지 -> 모듈의 집합(폴더), 모듈의 계층 단위
# a.py가 data 폴더에 있을 때 data == 패키지
def sum(a, b):
return a+b
# b.py
import data.a
a.sum(1, 2)
- 라이브러리 -> 쓸 만한 기능들을 미리 모듈 / 패키지로 만들어 놓은 것 ex) 내장함수, pip
- 사람들이 만든 라이브러리는 PyPI에 저장되고, 라이브러리를 설치할 때 pip를 이용한다.
웹 서비스란?
- 웹 -> 정보의 그물망
- URL -> 정보 자원이 어디있는지 나타내는 표식
- HTTP -> 정보 자원으로 접근하고 통신하게 해 주는 약속
- GET -> 정보 자원을 가져다줘!
- POST -> 이 데이터를 처리해줘!
- HTML -> 응답으로서의 정보 자원 자체, a태그를 통한 다른 정보 자원가 연결 매개체
- Server -> 요청을 예상하고, 그에 따른 정보 자원을 미리 저장해놓고 제공하는 것
- 웹 서비스란? HTML과 URL을 미리 준비해놓고, 사용자 요청에 대한 응답을 보낼 수 있는 프로그램
웹 프레임워크란?
- 프레임워크 -> 복잡한 문제를 해결하거나 서술하는데 사용되는 기본 개념 구조
- 더 쉬운 말로 정형화 되어있는 웹 개발을 반복되는 코드 작업을 효율적으로 하기위해 미리 만들어 놓은 웹개발의 기능, 설계 단위의 집합
- 프레임워크(django) -> 명확한 목적을 달성하기 위해 이미 설계까지 만들어진 구조, 틀을 무조건 지켜야함
- 라이브러리(react) -> 도구의 모음
MVC, MTV란?
- MVC 디자인 패턴(장고에서는 MTV 패턴이라고 부름)
- 1. DB와 상호작용하는 부분 -> model, model(장고 기준)
- 2. 사용자들 눈에 보이는 부분 -> view, templates(장고 기준)
- 3. 내부 동작의 논리를 담당하는 부분 -> controller, view(장고 기준)
[디자인패턴] MVC, MVP, MVVM 비교
웹 개발자로 일을 하면서 가장 먼저 접한 디자인패턴이 바로 MVC 패턴이었습니다. 그만큼 유명하고 많이 쓰이는 디자인패턴인 MVC 패턴과 MVC 패턴에서 파생되어져 나온 MVP 패턴과 MVVM 패턴을 이야
beomy.tistory.com
가상환경이란?
- 독립적인 개발환경 만들기
- 버젼 충돌이나 여러 상황들로부터 독립적인 환경을 만들어줌.
- 1. 가상환경 생성
- python -m venv 가상환경이름
- 2. 가상환경 실행
- source myvenv/Scripts/activate
- 3. 가상환경 끄기
- deactivate
장고의 기본 파일들
__init__.py란
- __init__.py가 위치한 곳이 패키지라는 것을 알려주는 파일
urls.py란
- url들을 매핑해주고, 관리해주는 곳
장고 프로젝트 시작하기
django-admin startproject 프로젝트명
manage.py란
- 1. 서버 켜기
python manage.py runserver
- 2. Application 만들기
- Application : 하나의 장고 프로젝트를 이루는 단위 ex) 결제기능앱, 게시판기능앱
python manage.py startapp 앱이름
- 3. Database 초기화 및 변경사항 반영
python manage.py migrate
- 4. 관리자 계정 만들기
python manage.py createsuperuser
settings.py란
- 여러 설정값을 저장하고, 지정하는 곳
url을 효율적으로 매핑시키는 방법
- include를 사용하는 방법 ex) product로 시작하는 url은 product app의 urls.py에서 담당할 것이다.
path('product/', include('product.urls'), name='product'),
product app의 아래 url은 product/first/로 매핑된다.
urlpatterns = [
path('first/', views.products, name='products'),
]
웹 서비스 내부 데이터
- Static : 미리 준비된 데이터
- Media : 업로드 된 데이터
static 파일을 관리 하는 법
- STATICFILES_DIRS : static 파일들의 경로 작성
static 파일들을 하나의 폴더에서 관리 할 때
STATICFILES_DIRS = [
BASE_DIR / 'static',
]
# 최상위 디렉토리 아래 static 폴더를 만들겠다는 의미입니다.
static 파일들을 앱마다 각자의 폴더에서 관리 할 때
STATICFILES_DIRS = [
os.path.join(BASE_DIR, '앱이름', 'static'),
os.path.join(BASE_DIR, '앱이름', 'static'),
os.path.join(BASE_DIR, '앱이름', 'static')
]
- STATIC_ROOT : 배포시 static 파일들을 복사하여 모아 놓을 경로
STATIC_ROOT = os.path.join('staticfiles')
python manage.py collectstatic
- STATIC_URL : static 파일을 제공할 url
STATIC_URL = '/static/'
장고에서는 최상위 디렉토리는 Base Directory라고 부른다.
템플릿에서 staic 폴더 안의 것을 사용하는 방법
{% load static %} <--- {% %}은 템플릿에서 장고 기능을 사용할 수 있는 템플릿 언어이다.
<link rel ="stylesheet" type="text/css" href="{% static 'css/style.css' %}">
템플릿 언어란?
<a href="{% url 'url name' %}"></a>
템플릿 상속이란?
- 반복되는 html의 구문을 줄이기 위해서 사용한다.
- 주로 부트스트랩의 Nav Var을 사용할 때 사용한다.
부모 html
중복되는 코드 입력
{% block content %}
자식의 html의 코드가 들어가는 부분
{% endblock %}
중복되는 코드 입력
자식 html
{% extends '부모.html' %}
{% block content %}
자식 html만의 코드 작성
{% endblock %}
Model
https://devdongbaek.tistory.com/65
Django의 모델에 대해서
출처 : https://www.inflearn.com/course/%ED%8C%8C%EC%9D%B4%EC%8D%AC-%EC%9E%A5%EA%B3%A0-%EC%9B%B9%EC%84%9C%EB%B9%84%EC%8A%A4/dashboard 장고(Django)를 배우기 시작한 입문자이시거나, 또는 배우고 싶은 생..
devdongbaek.tistory.com
모델 활용 순서
Django model을 통해, 데이터베이스 형상을 관리할 경우
- 모델 클래스 작성
- 모델 클래스로부터 변경사항이 담긴 마이그레이션 파일 생성 -> makemigrations 명령
- 변경사항이 있는 마이그레이션 파일을 데이터베이스에 적용 -> migrate 명령
migrate -> 초기화, 변경사항 적용
admin 사이트에서 object 1, 2, 3이 아닌 object 이름으로 표시되게 하는 법
class Blog(models.Model):
title = models.CharField(max_length=200)
body = models.TextField()
date = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.title
Html 폼 이용하기
https://devdongbaek.tistory.com/81
Django HTML Form
출처 : https://www.inflearn.com/course/%ED%8C%8C%EC%9D%B4%EC%8D%AC-%EC%9E%A5%EA%B3%A0-%EC%9B%B9%EC%84%9C%EB%B9%84%EC%8A%A4/dashboard 장고(Django)를 배우기 시작한 입문자이시거나, 또는 배우고 싶은 생..
devdongbaek.tistory.com
<form action="{% url 'create' %}" method="POST">
{% csrf_token %}
<div>
<label for="title">제목</label><br/>
<input type="text" name="title" id="title">
</div>
<div>
<label for="body">제목</label><br/>
<textarea name="body" id="body" cols="30" rows="10"></textarea>
</div>
</form>
- 위 코드에서는 팀 이름을 입력하기 위한 텍스트 필드를 단지 한개만 가지는데, 폼이 가질수 있는 입력 요소와 관련 라벨의 갯수에는 제한이 없다. 필드의 type 속성은 어떤 종류의 위젯이 표시될지 정의한다. 필드의 name과 id 가 JavaScript/CSS/HTML에 있는 필드를 확인하는데 사용되고 value는 필드가 처음 표시될 때의 초기값을 정의한다. 관련 팀 라벨은 label태그( 위 코드에서 "제목 : "을 확인)를 이용해 명시된다. 여기서 for필드는 관련된 input의 id값을 포함하고 있다.
- submit 타입의 input 태그는 (기본적으로) 사용자가 누를수 있는 버튼으로 표시되는데, 버튼의 동작에 의해 폼의 다른 모든 input 요소의 데이터가 서버로 업로드된다. 폼 속성으로는 데이터를 보내기 위해 사용되는 HTTP method와 서버상에서 데이타의 목적지를 ( action으로) 정의한다:
html form을 database에 저장하는 로직
from django.shortcuts import render, redirect
from django.utils import timezone
from .models import Blog
def home(request):
return render(request, 'index.html')
# 블로그 글을 저장하는 함수
def create(request):
if(request.method == 'POST'):
post = Blog()
post.title = request.POST['title']
post.body = request.POST['body']
post.date = timezone.now()
post.save()
return redirect('home')
- render 는 템플릿을 불러오고, redirect 는 URL로 이동합니다. URL 로 이동한다는 건 그 URL 에 맞는 views 가 다시 실행될테고 여기서 render 를 할지 다시 redirect 할지 결정할 것 입니다. 이 점에 유의해서 사용하신다면 상황에 맞게 사용하실 수 있을 겁니다.
Django Form
Html Form의 기본 형태
<form action=”데이터가 전달될 주소(요청/이동할 주소)” method=”http 요청 방식"> <input type=”text” name=”title”/>
<button type=”submit”>입력</button>
</form>
form이라는 태그 내에 input 태그, button 태그들로 구성되어 있고 form이 시작되는 form 태그 내부에서는 action과 method의 속성을 기술하도록 되어있다.
Action
입력되는 정보들을 받는 url
Method
HTTP 요청 방식에는 GET / POST / PUT / DELETE 가 있습니다. 보통은 GET / POST를 사용한다.
GET
주소가 노출되어도 괜찮고, 다른 사용자에게 공유가 가능한 정보를 처리할 때 사용
POST
회원가입이나 결제와 같은 다른 사용자와 결제해서는 안되는 정보를 처리할 때 사용
장고에서는 폼을 구성하기 쉽도록 프레임워크단에서 지원하고 있다. 특징은 다음과 같다.
- 모델 클래스의 모델 정보들과 연동할 수 있다. (binding)
- Validation 체크 (입력된 정보들의 유효성 검사)를 쉽게 해준다.
- 악의적인 데이터를 필터링 한다. (sanitisation)
- 짧고 간결한 코드로 폼 인터페이스를 구현한다.
https://devdongbaek.tistory.com/83
Django를 더 Django스럽게 만들어주는 Form
출처 : https://www.inflearn.com/course/%ED%8C%8C%EC%9D%B4%EC%8D%AC-%EC%9E%A5%EA%B3%A0-%EC%9B%B9%EC%84%9C%EB%B9%84%EC%8A%A4/dashboard 장고(Django)를 배우기 시작한 입문자이시거나, 또는 배우고 싶은 생..
devdongbaek.tistory.com
forms
from django import forms
from .models import Blog
class BlogForm(forms.Form):
# 내가 입력받고자 하는 값들
title = forms.CharField()
body = forms.CharField(widget=forms.Textarea)
views
# django form을 이용해서 입력값을 받는 함수
# GET 요청(= 입력값을 받을 수 있는 html을 가져다 줌)
# POST 요청(= 입력한 내용을 데이터베이스에 저장. form에서 입력한 내용을 처리)
# 둘 다 처리가 가능한 함수
def formcreate(request):
# 입력 내용을 DB에 저장
if request.method == 'POST':
# BlogForm 객체를 만들고 인자로 입력한 값들을 넘김
form = BlogForm(request.POST, request.FILES)
# 유효성 검사에 통과했다면
if form.is_valid():
post = Blog()
post.title = form.cleaned_data['title']
post.body = form.cleaned_data['body']
# DB에 최종 저장
post.save()
return redirect('home')
# 입력내용을 받을 수 있는 html 전달
else:
form = BlogForm()
# render()의 세번째 인자로 views.py의 데이터를 딕셔너리 자료형으로 html에 넘겨줄 수 있다.
return render(request, 'form_create.html', {'form':form} )
Django ModelForm
https://devdongbaek.tistory.com/87
Django ModelForm이란?
출처 : https://www.inflearn.com/course/%ED%8C%8C%EC%9D%B4%EC%8D%AC-%EC%9E%A5%EA%B3%A0-%EC%9B%B9%EC%84%9C%EB%B9%84%EC%8A%A4/dashboard 장고(Django)를 배우기 시작한 입문자이시거나, 또는 배우고 싶은 생..
devdongbaek.tistory.com
forms
class BlogModelForm(forms.ModelForm):
class Meta:
model = Blog
#fields = '__all__'
fields = ['title', 'body']
views
def modelformcreate(request):
# 입력 내용을 DB에 저장
if request.method == 'POST':
# BlogForm 객체를 만들고 인자로 입력한 값들을 넘김
form = BlogModelForm(request.POST, request.FILES)
# 유효성 검사에 통과했다면
if form.is_valid():
# DB에 최종 저장
form.save()
return redirect('home')
# 입력내용을 받을 수 있는 html 전달
else:
form = BlogModelForm()
# render()의 세번째 인자로 views.py의 데이터를 딕셔너리 자료형으로 html에 넘겨줄 수 있다.
return render(request, 'form_create.html', {'form':form} )
<table>
{{ form.as_ul }}
</table>
- {{ 인자.as_감쌀태그 }}를 통해서views로 부터 넘겨받은 form 인자를 감싸는 태그를 자동으로 생성할 수 있다.
model 값 update
https://velog.io/@fregataa/django-QuerySet.update-vs-QuerySet.bulkupdate-vs-Model.save
[django] model update
어무해django에서 업데이트, 무엇이 다른가?? QuerySet.bulk_update() QuerySet.update() Model.save()
velog.io
쿼리셋
https://devdongbaek.tistory.com/56
동백 // Django 모델을 통한 조회 ( 기초 )Q
devdongbaek.tistory.com
https://devdongbaek.tistory.com/55
동백 // Django 모델을 통한 조회 ( 기초 )Q
devdongbaek.tistory.com
QuerySet -> 데이터베이스로부터 전달받은 데이터 객체 목록
https://docs.djangoproject.com/ko/4.0/ref/models/querysets/
QuerySet API reference | Django 문서 | Django
Django The web framework for perfectionists with deadlines. Overview Download Documentation News Community Code Issues About ♥ Donate
docs.djangoproject.com
쿼리셋은 RDBMS의 SELECT 문을 생각하면 된다.
디테일 페이지 만들기
https://devdongbaek.tistory.com/109
Django 포스팅 detail view 구현
출처 : https://www.inflearn.com/course/%ED%8C%8C%EC%9D%B4%EC%8D%AC-%EC%9E%A5%EA%B3%A0-%EC%9B%B9%EC%84%9C%EB%B9%84%EC%8A%A4/dashboard 장고(Django)를 배우기 시작한 입문자이시거나, 또는 배우고 싶은 생..
devdongbaek.tistory.com
Model을 작성할 때 primary key를 등록하지 않았다면, Django는 id 값이라는 pk를 스스로 만들어 primary key로 등록해준다.
- id -> 객체가 데이터베이스에 post 된 순서
<a href="{% url 'url이름' 변수 %}">제목 : {{ i.title }}</a>
- url 'url이름' 뒤 오는 변수는 주소 url의 함수에 인자로 넘길 값을 의미합니다.
<a href="{% url 'detail' i.id %}">제목 : {{ i.title }}</a>
프로세스 :
# id는 매개 변수나 인자 값으로 사용되기에 원하는 이름으로 설정가능
!중요한 것은 views나 url에서 사용하는 id는 매개변수이기에 원하는 이름으로 지정가능('url의 <int>:변수'와
'views의 def detail(request, 변수)' 의 이름이 같다는 전제하에) 그러나 html에서는 반드시 {{ 변수.id }} id나 pk로 적어야 한다.
1. url에서 id값이 있는 detail 주소를 받고, detail 함수에 매핑시켜줌
path('detail/<int:id>' , views.detail, name='detail'),
2. detail 함수에서 id 값을 인자로 받고, id번째 글을 데이터베이스로부터 가져와서 detail.html으로 전달
def detail(request, id):
# id 번째 블로그 글을 데이터베이스에서 가져와서 detail.html로 띄워주는 코드
# get_object_or_404는 첫번째 인자로 특정 객체를 가져올 데이터베이스,
# 두번째 인자로는 특정 객체의 pk값을 받습니다.
blog_detail = get_object_or_404(Blog, pk = id)
return render(request, 'detail.html', {'blog_detail':blog_detail} )
- get_object_or_404()는 id값을 이용해 특정 모델 객체 하나만 가져온다.
3. detail.html에서 해당 id 글의 출력
Media 파일 업로드
https://devdongbaek.tistory.com/54
동백 // Django media 파일을 다루는 방법
devdongbaek.tistory.com
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'
1. MEDIA_URL = ""
- 각 media 파일에 대한 URL Prefix #필드명.url 속성에 의해서 참조되는 설정
- 파일에 대한 url 접근시에 사용된다~!
2. MEDIA_ROOT = ""
- 파일필드를 통한 저장 시에, 실제 파일을 저장할 ROOT 경로
Django에서 media 다루는 순서 요약하기
1. MEDIA_URL 설정
# settings.py
MEDIA_URL = "/media/"
2. MEDIA_ROOT 설정
# settings.py
MEDIA_ROOT = os.path.join(BASE_DIR, "media")
3. URL 지정
# settings.py 경로의 urls.py
from django.conf.urls.static import static
...
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
4. pillow 패키지 설치
5. media 파일 저장하기
photo = models.ImageField(blank=True, upload_to='instagram/post/%Y/%m/%d')
6. media 파일 사용하기
<img src={post.photo.url} style="width:100px; height:100px" />
<img src={post.photo.path} style="width:100px; height:100px" />
- url은 Django에서 저장한 사진의 주소이고, path는 실제 사진이 저장된 서버 컴퓨터 내에서의 주소이기에 보안상으로 url 사용 권장
댓글 구현하기
https://devdongbaek.tistory.com/118
Django 댓글 구현하기
출처 : https://www.inflearn.com/course/%ED%8C%8C%EC%9D%B4%EC%8D%AC-%EC%9E%A5%EA%B3%A0-%EC%9B%B9%EC%84%9C%EB%B9%84%EC%8A%A4/dashboard 장고(Django)를 배우기 시작한 입문자이시거나, 또는 배우고 싶은 생..
devdongbaek.tistory.com
class Blog(models.Model):
title = models.CharField(max_length=200)
body = models.TextField()
photo = models.ImageField(blank=True, null=True, upload_to='blog_photo')
date = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.title
class Comment(models.Model):
comment = models.CharField(max_length=200)
date = models.DateTimeField(auto_now_add=True)
# 1:N 관계에서는 N측에 1의 기본키를 가져와 외래키로 구성한다.
post = models.ForeignKey(Blog, on_delete=models.CASCADE)
- 외래키 같은 경우는 데이터베이스 수업 참조
commit=False를 쓰는 이유는?
예를 들어서 필드가 4개가 있는 모델을 모델 폼으로 작성을 받을 때
나는 그 중 1개의 필드만 폼으로 작성하고 싶다!!
![](https://t1.daumcdn.net/keditor/emoticon/friends1/large/005.gif)
이 경우에 view 함수에서 유효성 검사 이후 form.save()를 먼저 하면 나머지 필드들은 값을 받지
못했으므로 오류가 발생합니다!
![](https://t1.daumcdn.net/keditor/emoticon/friends1/large/035.gif)
그러기에 우리는 장고에게 잠시만 저장을 미뤄줘~~! 라는 의미로 commit=False를 적어준 다음
나머지 필드들의 값을 지정해주는겁니다!
{% for comment in blog_detail.comment_set.all %}
- 1:N에서 1측의 특정 객체를 참조하고있는 N측의 집합을 모두 가져오고 싶을 때 필드_set.all 사용
로그인, 로그아웃 구현하기
https://devdongbaek.tistory.com/100
Django 로그인, 로그아웃 구현하기
출처 : https://www.inflearn.com/course/%ED%8C%8C%EC%9D%B4%EC%8D%AC-%EC%9E%A5%EA%B3%A0-%EC%9B%B9%EC%84%9C%EB%B9%84%EC%8A%A4/dashboard 장고(Django)를 배우기 시작한 입문자이시거나, 또는 배우고 싶은 생..
devdongbaek.tistory.com
<form action="{% url 'login' %}" method="POST">
{% csrf_token %}
username : <input type="text" name='username'>
password : <input type="text" name='password'>
<br />
<input type="submit" value='로그인'>
</form>
- 로그인 form
from django.shortcuts import redirect, render
from django.contrib import auth
from django.contrib.auth.models import User
# Create your views here.
def login(request):
# POST 요청이 들어오면 로그인 처리를 해줌
if request.method == 'POST':
# 클라이언트가 입력한 값을 변수에 저장
username = request.POST['username']
password = request.POST['password']
# auth.authenticate()은 사용자가 입력한 username과 password가 데이터에 저장되어 있는지 확인 후
# 저장되어 있으면 user 객체를 반환하고, 없다면 None을 반환하는 함수
user = auth.authenticate(request, username=username, password=password)
if user is not None:
auth.login(request, user)
return redirect('home')
else:
return render(request, 'home')
# GET 요청이 들어오면 login form을 담고있는 login.html을 띄워주는 역할을 함
else:
return render(request, 'login.html')
- 로그인 함수
def logout(request):
auth.logout(request)
return redirect('home')
- 로그아웃 함수
LOGIN_REDIRECT_URL = "/"
- 로그인 성공시 이동할 주소를 settings.py에서 설정 가능
GET과 POST의 차이를 잘 이해하자
- GET은 유저에게 페이지를 보여줄 때
- POST는 유저가 입력한 값을 서버로 전송할 때
https://docs.djangoproject.com/en/4.0/ref/contrib/auth/
django.contrib.auth | Django documentation | Django
Django The web framework for perfectionists with deadlines. Overview Download Documentation News Community Code Issues About ♥ Donate
docs.djangoproject.com
익명 게시판
게시글 작성자가 익명으로 보이게 하는 것
<div class="card-body">
<div class="table-responsive">
<table class="table table-bordered" id="dataTable" width="100%" cellspacing="0">
<thead>
<tr>
<th width='70%'>글 제목</th>
<th>작성 날짜</th>
<th>작성자</th>
</tr>
</thead>
<tbody>
{% for post in posts %}
<tr>
<td><a href="#">{{ post.title }}</a></td>
<td>{{ post.date }}</td>
<td>익명</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
- 작성자를 표시 하지 않고 그냥 작성자라고 아예 명시함
글 제목을 누를 시 이동하게 하는 법
<tbody>
{% for post in posts %}
<tr>
<td><a href="{% url 'detail' post.id %}">{{ post.title }}</a></td>
<td>{{ post.date }}</td>
<td>익명</td>
</tr>
{% endfor %}
</tbody>
<tbody> 태그는 HTML 테이블에서 내용 콘텐츠(body content)들을 하나의 그룹으로 묶을 때 사용합니다.
<tbody> 요소는 테이블의 각 영역(header, body, footer)을 명시하기 위해 <thead>, <tfoot> 요소와 함께 사용됩니다.
브라우저는 이러한 요소들을 사용하여 테이블의 헤더나 푸터와는 독립적으로 테이블의 내용만 스크롤되게 할 수 있으며, 여러 페이지에 걸쳐 있는 큰 테이블을 인쇄할 때 각 페이지의 상단과 하단에 테이블의 헤더와 푸터가 모두 인쇄되도록 할 수도 있습니다.
<tbody> 요소는 <table> 요소의 자식 요소로써, 반드시 모든 <caption>, <colgroup>, <thead> 요소 다음에 위치해야 합니다. 또한, <tbody> 요소는 반드시 하나 이상의 <tr> 요소를 포함하고 있어야 합니다.
<thead>와 <tbody>, <tfoot> 요소는 기본적으로 웹 페이지의 레이아웃에 전혀 영향을 주지 않지만, 이 요소들의 스타일을 CSS를 사용하여 변경할 수는 있습니다.
- 글들을 표현할 때는 table을 이용하여 목록을 구성
https://getbootstrap.com/docs/4.1/content/tables/
Tables
Documentation and examples for opt-in styling of tables (given their prevalent use in JavaScript plugins) with Bootstrap.
getbootstrap.com
댓글 입력받은 값을 데이터에 저장하기
# 댓글 저장
def new_comment(request, pk):
filled_form = CommentForm(request.POST)
if filled_form.is_valid():
filled_form.save(commit=False)
filled_form.post = get_object_or_404(Post, pk=pk)
filled_form.save()
return redirect('detail', pk)
- commit=False를 통해서 Comment의 외래키를 해당 포스트의 글 pk로 지정 후 최종 저장한다.
로그인 실패시 문구가 뜨게 하는 법
{% if form.errors %}
<p style="color:red;">아이디, 비밀번호가 일치하지 않습니다. 다시 시도해주세요.</p>
{% endif %}
클래스 뷰(CBV)를 사용해서 로그인, 로그아웃 구현
from django.contrib.auth.views import LoginView, LogoutView, logout_then_login
login = LoginView.as_view(template_name= "login.html")
#def logout(request):
#return logout_then_login(request)
logout = LogoutView.as_view(next_page = "login")
Form들에 부트스트랩을 적용하기 위해서는 클래스를 적용해야 한다.
from django import forms
from .models import Post, Comment
class PostForm(forms.ModelForm):
class Meta:
model = Post
fields = '__all__'
def __init__(self, *args, **kwargs):
super(PostForm, self).__init__(*args, **kwargs)
self.fields['title'].widget.attrs = {
'class': 'form-control',
'placeholder': "글 제목을 입력해주세요",
'rows': 20
}
self.fields['body'].widget.attrs = {
'class': 'form-control',
'placeholder': "글 제목을 입력해주세요",
'rows': 20,
'cols' : 100
}
class CommentForm(forms.ModelForm):
class Meta:
model = Comment
fields = ['comment']
def __init__(self, *args, **kwargs):
super(CommentForm, self).__init__(*args, **kwargs)
self.fields['comment'].widget.attrs = {
'class': 'form-control',
'placeholder': "댓글을 입력해주세요",
'rows': 10
}
- widget.attrs은 widget에 클래스를 부여해주고, 아래 처럼 이 클래스를 통해 부트스트랩이나 css를 적용할 수 있습니다.
<input type="text" class="form-control bg-light border-0 small"
placeholder="Search for..." aria-label="Search"
aria-describedby="basic-addon2">
https://docs.djangoproject.com/en/4.0/ref/forms/widgets/
Widgets | Django documentation | Django
Django The web framework for perfectionists with deadlines. Overview Download Documentation News Community Code Issues About ♥ Donate
docs.djangoproject.com
[Django] widget (1) widget의 원리와 widget 만들어보기 - 실시간 글자수 표시 widget
input 태그는 type 속성에 따라 여러 모습을 보여줍니다. text 일 때는 글을 입력할 수 있도록, date 일 때는 날짜를 지정할 수 있도록, password 일 때는 비밀번호를 입력할 수 있도록 하는 등 다양한 type
ssungkang.tistory.com
자유 게시판 구현하기
from django.contrib.auth.models import User
# 자유 게시물 모델
class FreePost(models.Model):
title = models.CharField(max_length=200)
body = models.TextField()
date = models.DateTimeField(auto_now_add=True)
author = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self):
return self.title
- User를 외래키로 삼아서 작성자를 저장
def freepostcreate(request):
if request.method == 'POST' or request.method == 'FILES':
# BlogForm 객체를 만들고 인자로 입력한 값들을 넘김
form = FreePostForm(request.POST, request.FILES)
# 유효성 검사에 통과했다면
if form.is_valid():
# DB에 최종 저장
finished_form = form.save(commit=False)
finished_form.author = request.user
finished_form.save()
return redirect('freehome')
# 입력내용을 받을 수 있는 html 전달
else:
form = FreePostForm()
# render()의 세번째 인자로 views.py의 데이터를 딕셔너리 자료형으로 html에 넘겨줄 수 있다.
return render(request, 'free_post_form.html', {'form':form})
- 현재 유저를 글 작성자로 지정한다.
finished_form.author = request.user
회원가입 구현하기
https://devdongbaek.tistory.com/92
Django 회원가입, 로그인 구현하기!!!
출처 : https://www.inflearn.com/course/%ED%8C%8C%EC%9D%B4%EC%8D%AC-%EC%9E%A5%EA%B3%A0-%EC%9B%B9%EC%84%9C%EB%B9%84%EC%8A%A4/dashboard 장고(Django)를 배우기 시작한 입문자이시거나, 또는 배우고 싶은 생..
devdongbaek.tistory.com
from django.shortcuts import render, redirect
from django.contrib.auth.views import LoginView, LogoutView, logout_then_login
from django.contrib import auth
from django.contrib.auth.models import User
def signup(request):
if request.method == "POST":
# 만약 첫 비밀번호와 나중 비밀번호가 같다면
if request.POST['password'] == request.POST['repeat']:
# 회원가입
new_user = User.objects.create_user(username=request.POST['username'], password=request.POST['password'])
# 로그인
auth.login(request, new_user)
# 홈 리다이렉션
return redirect('home')
# 같지 않다면 다시 회원가입 페이지로
return render(request, 'register.html')
<form class="user" method="POST">
{% csrf_token %}
<div class="form-group row">
</div>
<div class="form-group">
<input type="text" name="username" class="form-control form-control-user" id="exampleInputEmail"
placeholder="Enter Your ID...">
</div>
<div class="form-group row">
<div class="col-sm-6 mb-3 mb-sm-0">
<input type="password" name="password" class="form-control form-control-user"
id="exampleInputPassword" placeholder="Password">
</div>
<div class="col-sm-6">
<input type="password" name="repeat" class="form-control form-control-user"
id="exampleRepeatPassword" placeholder="Repeat Password">
</div>
</div>
<br/>
<br/>
<br/>
<input type="submit" class="btn btn-success btn-user btn-block" value="회원가입">
<hr>
</form>
<div class="text-center">
<a class="small" href="{% url 'login' %}">Already have an account? Login!</a>
</div>
Pagination
[Django] 11. Pagination 을 알아보자
안녕하세요 강민성입니다. 이번 시간에도 마찬가지로 blog project를 이어서 진행해보도록 하겠습니다. 글을 계속 추가할수록 글은 아래로 쌓이게 됩니다. 하지만 대부분의 웹사이트는 일정 수준
ssungkang.tistory.com
Pagination -> 객체들의 목록을 페이지 별로 나눠서 보여주도록 하는 것
from django.core.paginator import Paginator
def home(request):
# 최신글 기준으로 order_by
posts = Post.objects.filter().order_by('-date')
# Paginator 함수의 첫 인자로는 페이징할 객체, 두번째 인자로는 몇 개씩 끉을 것인지
paginator = Paginator(posts, 10)
# page에 해당되는 value를 가져오면 page의 번호를 리턴 받을 수 있습니다.
pagenum = request.GET.get('page')
# 해당 pagenum에 해당하는 posts 객체들을 저장
posts = paginator.get_page(pagenum)
return render(request, 'index.html', {'posts':posts} )
blog_list = Blog.objects.all()
그 전에도 사용한 적 있습니다. Blog 클래스의 모든 객체들을 blog_list에 담아두게 됩니다.
paginator = Paginator(blog_list, 3)
위에서 import한 Paginator입니다.
2개의 인자를 받는데 첫 번째로 페이지로 분할될 객체, 두 번째로 한 페이지에 담길 객체의 수를 받습니다.
page = request.GET.get('page')
request는 사용자가 보낸 총체적인 정보를 담고 있습니다.
어디서 어떤 페이지로 정보를 보내는지 등 말이죠.
GET은 request 방식 중 하나 입니다.
GET 방식으로 정보를 받아오는 데이터를 가르키게 됩니다.
get 은 딕셔너리 자료형에서 key값으로 value를 찾을 때 사용됩니다.
그 말인 즉슨, request.GET 으로 받아온 값은 딕셔너리 자료형 이라는 의미죠.
ex) http://127.0.0.1:8000/title=first&body=hello
{'title':first, "body":hello}
여기서 page에 해당되는 value를 가져오면 page의 번호를 리턴 받을 수 있습니다.
posts = paginator.get_page(page)
get_page 메소드는 페이지 번호를 받아 해당 페이지를 리턴하게 됩니다.
그 후 이 페이지를 다시 render를 통해 넘겨주게 됩니다.
https://velog.io/@kimkrh/Django-request.GET.get
[Django] request.GET.get()
request.get()과 request.GET.get()의 차이점
velog.io
-> page를 프론트엔드 단에 표시하는 방법
{% extends 'base.html' %}
{% load bootstrap4 %}
{% block content %}
<!-- Page Heading -->
<!-- DataTales Example -->
<div class="card shadow mb-4">
<div class="card-header py-3">
<h6 class="m-0 font-weight-bold text-success">익명게시판</h6>
</div>
<div class="card-body">
<div class="table-responsive">
<table class="table table-bordered" id="dataTable" width="100%" cellspacing="0">
<thead>
<tr>
<th width='70%'>글 제목</th>
<th>작성 날짜</th>
<th>작성자</th>
</tr>
</thead>
<tbody>
{% for post in posts %}
<tr>
<td><a href="{% url 'detail' post.id %}">{{ post.title }}</a></td>
<td>{{ post.date }}</td>
<td>익명</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
{% if user.is_authenticated %}
<a href="{% url 'postcreate' %}" class="btn btn-success btn-icon-split">
<span class="icon text-white-50">
<i class="fas fa-flag"></i>
</span>
<span class="text">글쓰기</span>
</a>
{% endif %}
<!-- 페이지네이션 -->
{% bootstrap_pagination posts size="small" justify_content="center" %}
<a href="?page=1">첫 페이지</a>
{% if posts.has_previous %}
<a href="?page={{ posts.previous_page_number }}">이전 페이지</a>
{% endif %}
<span>현재 페이지 : {{ posts.number }}</span>
<span>/</span>
<span>{{ posts.paginator.num_pages }}</span>
{% if posts.has_next %}
<a href="?page={{ posts.next_page_number }}">다음 페이지</a>
<a href="?page={{ posts.paginator.num_pages }}">마지막 페이지</a>
{% endif %}
{% endblock %}
외부 DB 연동하기
mariaDB를 Django와 연동하기
1. mariaDB 설치
- ! root 계정 비밀번호와 port번호가 3306인지 확인하기
- mariaDB 설치시 자동으로 HeidiSQL이 설치되는데 이는 mariaDB안 테이블들을 쉽게 확인할 수 있는 SQL이다.
https://mariadb.com/kb/en/mariadb-server-10-6-8/
MariaDB Server 10.6.8
<div class="pdl-cta"> Thank you for downloading. Create your MariaDB account to receive download release notifications, product updates an...
mariadb.com
2. Django와 연동하기 위해서 mysqlclient를 설치해줘야함
pip install mysqlclient
https://victorydntmd.tistory.com/275
[Python3.6] mysqlclient 설치 에러 해결
윈도우 환경에서 python mysql을 사용하기 위해 pip install mysqlclient 으로 mysql을 설치하려고 하면, 아래와 같은 에러들이 발생하는 경우가 있습니다. 1. 이 메시지는 윈도우에서 Python module을 설..
victorydntmd.tistory.com
https://lemontia.tistory.com/756
[python-pip] mysqlclient 설치 중 에러날때(mysql.h)
pip3로 mysqlclient를 설치할때 다음의 에러가 발생할 수 있습니다. mysql.c _mysql.c(29): fatal error C1083: 포함 파일을 열 수 없습니다. 'mysql.h': No such file or directory error: command 'C:\\Program..
lemontia.tistory.com
3. settings.py에 DB 관련 설정
MYDATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'mysql',
'USER': 'root',
'PASSWORD': '루트계정암호',
'HOST': '127.0.0.1',
'PORT': '3306'
}
}
! settings.py의 DB PASSWORD와 SECRET_KEY는 절대 외부에 노출되어서는 안된다.
그래서 보통 my_settings.py라는 파일을 만들고 그곳에 DB PASSWORD와 SECRET_KEY를 저장하고 import한다.
from .my_settings import MYSECRET_KEY, MYDATABASES
SECRET_KEY = MYSECRET_KEY
DATABASES = MYDATABASES
소셜 로그인
https://django-allauth.readthedocs.io/en/latest/installation.html
Installation — django-allauth 0.43.0 documentation
Post-Installation In your Django root execute the command below to create your database tables: Now start your server, visit your admin pages (e.g. http://localhost:8000/admin/) and follow these steps: Add a Site for your domain, matching settings.SITE_ID
django-allauth.readthedocs.io
1. 패키지를 설치
$ pip install django-allauth
2. settings.py에 등록
INSTALLED_APPS = [
...
# The following apps are required:
'django.contrib.auth',
'django.contrib.messages',
'django.contrib.sites',
'allauth',
'allauth.account',
'allauth.socialaccount',
# ... include the providers you want to enable:
'allauth.socialaccount.providers.agave',
'allauth.socialaccount.providers.amazon',
'allauth.socialaccount.providers.amazon_cognito',
'allauth.socialaccount.providers.angellist',
'allauth.socialaccount.providers.apple',
'allauth.socialaccount.providers.asana',
'allauth.socialaccount.providers.auth0',
'allauth.socialaccount.providers.authentiq',
'allauth.socialaccount.providers.azure',
'allauth.socialaccount.providers.baidu',
'allauth.socialaccount.providers.basecamp',
'allauth.socialaccount.providers.battlenet',
'allauth.socialaccount.providers.bitbucket',
'allauth.socialaccount.providers.bitbucket_oauth2',
'allauth.socialaccount.providers.bitly',
'allauth.socialaccount.providers.box',
'allauth.socialaccount.providers.cern',
'allauth.socialaccount.providers.cilogon',
'allauth.socialaccount.providers.clever',
'allauth.socialaccount.providers.coinbase',
'allauth.socialaccount.providers.dataporten',
'allauth.socialaccount.providers.daum',
'allauth.socialaccount.providers.digitalocean',
'allauth.socialaccount.providers.discord',
'allauth.socialaccount.providers.disqus',
'allauth.socialaccount.providers.douban',
'allauth.socialaccount.providers.doximity',
'allauth.socialaccount.providers.draugiem',
'allauth.socialaccount.providers.drip',
'allauth.socialaccount.providers.dropbox',
'allauth.socialaccount.providers.dwolla',
'allauth.socialaccount.providers.edmodo',
'allauth.socialaccount.providers.edx',
'allauth.socialaccount.providers.eventbrite',
'allauth.socialaccount.providers.eveonline',
'allauth.socialaccount.providers.evernote',
'allauth.socialaccount.providers.exist',
'allauth.socialaccount.providers.facebook',
'allauth.socialaccount.providers.feedly',
'allauth.socialaccount.providers.figma',
'allauth.socialaccount.providers.fivehundredpx',
'allauth.socialaccount.providers.flickr',
'allauth.socialaccount.providers.foursquare',
'allauth.socialaccount.providers.frontier',
'allauth.socialaccount.providers.fxa',
'allauth.socialaccount.providers.gitea',
'allauth.socialaccount.providers.github',
'allauth.socialaccount.providers.gitlab',
'allauth.socialaccount.providers.globus',
'allauth.socialaccount.providers.google',
'allauth.socialaccount.providers.gumroad',
'allauth.socialaccount.providers.hubic',
'allauth.socialaccount.providers.instagram',
'allauth.socialaccount.providers.jupyterhub',
'allauth.socialaccount.providers.kakao',
'allauth.socialaccount.providers.keycloak',
'allauth.socialaccount.providers.lemonldap',
'allauth.socialaccount.providers.line',
'allauth.socialaccount.providers.linkedin',
'allauth.socialaccount.providers.linkedin_oauth2',
'allauth.socialaccount.providers.mailchimp',
'allauth.socialaccount.providers.mailru',
'allauth.socialaccount.providers.mediawiki',
'allauth.socialaccount.providers.meetup',
'allauth.socialaccount.providers.microsoft',
'allauth.socialaccount.providers.naver',
'allauth.socialaccount.providers.nextcloud',
'allauth.socialaccount.providers.odnoklassniki',
'allauth.socialaccount.providers.openid',
'allauth.socialaccount.providers.openstreetmap',
'allauth.socialaccount.providers.orcid',
'allauth.socialaccount.providers.patreon',
'allauth.socialaccount.providers.paypal',
'allauth.socialaccount.providers.persona',
'allauth.socialaccount.providers.pinterest',
'allauth.socialaccount.providers.pocket',
'allauth.socialaccount.providers.quickbooks',
'allauth.socialaccount.providers.reddit',
'allauth.socialaccount.providers.robinhood',
'allauth.socialaccount.providers.salesforce',
'allauth.socialaccount.providers.sharefile',
'allauth.socialaccount.providers.shopify',
'allauth.socialaccount.providers.slack',
'allauth.socialaccount.providers.snapchat',
'allauth.socialaccount.providers.soundcloud',
'allauth.socialaccount.providers.spotify',
'allauth.socialaccount.providers.stackexchange',
'allauth.socialaccount.providers.steam',
'allauth.socialaccount.providers.stocktwits',
'allauth.socialaccount.providers.strava',
'allauth.socialaccount.providers.stripe',
'allauth.socialaccount.providers.telegram',
'allauth.socialaccount.providers.trainingpeaks',
'allauth.socialaccount.providers.trello',
'allauth.socialaccount.providers.tumblr',
'allauth.socialaccount.providers.twentythreeandme',
'allauth.socialaccount.providers.twitch',
'allauth.socialaccount.providers.twitter',
'allauth.socialaccount.providers.untappd',
'allauth.socialaccount.providers.vimeo',
'allauth.socialaccount.providers.vimeo_oauth2',
'allauth.socialaccount.providers.vk',
'allauth.socialaccount.providers.weibo',
'allauth.socialaccount.providers.weixin',
'allauth.socialaccount.providers.windowslive',
'allauth.socialaccount.providers.xing',
'allauth.socialaccount.providers.yahoo',
'allauth.socialaccount.providers.yandex',
'allauth.socialaccount.providers.ynab',
'allauth.socialaccount.providers.zoho',
'allauth.socialaccount.providers.zoom',
'allauth.socialaccount.providers.okta',
'allauth.socialaccount.providers.feishu',
...
]
SITE_ID = 1
3. urls.py에 등록
urlpatterns = [
...
path('accounts/', include('allauth.urls')),
...
]
4. migrate 진행
5. admin단 수정
https://console.cloud.google.com/welcome?project=northern-center-355407
Google 클라우드 플랫폼
로그인 Google 클라우드 플랫폼으로 이동
accounts.google.com
- client id와 Secret Key는 구글 콘솔 사이트에서 입력받음
1. 새 프로젝트 생성하기
2. API 및 서비스에 들어간 후 사용자 인증 정보 만들기 -> OAuth 클라이언트 ID 만들기 -> 사용자 인증정보 만들기 -> OAuth 클라이언트 ID 만들기 -> 어플리케이션 유형(웹 어플리케이션), 승인된 자바스크립트 원본(http://127.0.0.1:8000), 승인된 리다이렉션(http://127.0.0.1:8000/accounts/google/login/callback/)
3. 클라이언트 아이디와 비밀번호를 admin에 이어서 작성
6. settngs.py 이어서 작성
# 어떤 수단을 통해서 로그인 할 것인지에 대해서
AUTHENTICATION_BACKENDS = [
# Needed to login by username in Django admin, regardless of `allauth`
# 기존 장고의 내장되어있는 인증 기능
'django.contrib.auth.backends.ModelBackend',
# `allauth` specific authentication methods, such as login by e-mail
# 소셜 로그인 기능
'allauth.account.auth_backends.AuthenticationBackend',
]
LOGIN_REDIRECT_URL = '/'
7.템플릿단 구현
{% load socialaccount %}
<a href="{% provider_login_url 'google' %}" class="btn btn-google btn-user btn-block">
<i class="fab fa-google fa-fw"></i> 구글 계정으로 가입 </a>
api 연동하기
https://developers.naver.com/docs/serviceapi/search/blog/blog.md#%EB%B8%94%EB%A1%9C%EA%B7%B8
블로그 - Search API
블로그 NAVER Developers - 검색 API 블로그 검색 개발가이드 검색 > 블로그 네이버 블로그 검색 결과를 출력해주는 REST API입니다. 비로그인 오픈 API이므로 GET으로 호출할 때 HTTP Header에 애플리케이션
developers.naver.com
!api 문서를 보는게 매우 중요
1. API를 사용하기 위해서는 오픈 API 이용 신청을 하는게 중요 -> 클라이언트 ID와 클라이언트 Secret Key를 받기 위해서
2. API를 응답받을 URL을 지정 ex) https://openapi.naver.com/v1/search/movie.json
3. 요청 변수는 위 URL 뒤에 ?key='value' 에서 key이며 value를 가져온다.
4. 필수 요청 변수는 반드시 적어주어야 한다. ex)query
API 호출 예시
curl "https://openapi.naver.com/v1/search/movie.xml?query=%EC%A3%BC%EC%8B%9D&display=10&start=1&genre=1" \
-H "X-Naver-Client-Id: {애플리케이션 등록 시 발급받은 client id 값}" \
-H "X-Naver-Client-Secret: {애플리케이션 등록 시 발급받은 client secret 값}" -v
- 한글이 url에 표시될때는 %EC%로 표시된다.
- &은 and를 의미한다.
API 요청 예시
> GET /v1/search/movie.xml?query=%EC%A3%BC%EC%8B%9D&display=10&start=1&genre=1 HTTP/1.1
> Host: openapi.naver.com
> User-Agent: curl/7.49.1
> Accept: */*
> X-Naver-Client-Id: {애플리케이션 등록 시 발급받은 client id 값}
> X-Naver-Client-Secret: {애플리케이션 등록 시 발급받은 client secret 값}
API 응답 예시
< HTTP/1.1 200 OK
< Server: nginx
< Date: Wed, 28 Sep 2016 07:40:17 GMT
< Content-Type: text/xml;charset=utf-8
< Transfer-Encoding: chunked
< Connection: keep-alive
< Keep-Alive: timeout=5
< Vary: Accept-Encoding
< X-Powered-By: Naver
< Cache-Control: no-cache, no-store, must-revalidate
< Pragma: no-cache
<
<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
<channel>
<title>Naver Open API - movie ::'주식'</title>
<link>http://search.naver.com</link>
<description>Naver Search Result</description>
<lastBuildDate>Wed, 28 Sep 2016 16:40:17 +0900</lastBuildDate>
<total>2</total>
<start>1</start>
<display>2</display>
<item>
<title>주마등<b>주식</b>회사</title>
<link>http://openapi.naver.com/l?AAADWLQQvCIBzFP83f48h0zh08uK1B0S2IOm7mUEIts0F9+vQQPN77vQfv+dbxI2DXgyTQ9QV4B+2ATNSLMCk9gEjYjlkurFZXflp1rFRw/yXnbEspNk8vqypvPJBRhZsGMrSMY4ySwLSpN5RT3NSYIScO5nxhdzc18cjq0958w8LneKUy8fz6AdRxjD6YAAAA</link><image>http://imgmovie.naver.com/mdi/mit110/0968/96811_P01_142155.jpg</image>
<subtitle>走馬&amp;#28783;株式&amp;#20250;社</subtitle>
<pubDate>2012</pubDate>
<director>미키 코이치로|</director>
<actor>카시이 유우|쿠보타 마사타카|카지와라 히카리|치요 쇼타|요코야마 메구미|카시와바라 슈지|</actor>
<userRating>4.50</userRating>
</item>
...
</channel>
</rss>
파이썬 API 호출 예제
# 네이버 검색 API예제는 블로그를 비롯 전문자료까지 호출방법이 동일하므로 blog검색만 대표로 예제를 올렸습니다.
# 네이버 검색 Open API 예제 - 블로그 검색
import os
import sys
# 특정 url에 request를 보낼 수 있도록 해주는 라이브러리
import urllib.request
# API 이용 신청을 통해 받은 id와 secret 입력
client_id = "YOUR_CLIENT_ID"
client_secret = "YOUR_CLIENT_SECRET"
# 검색할 단어를 입력받을 변수
# urllib.parse.quote()는 아스키코드 형식이 아닌 글자를 URL 인코딩 시켜줍니다.
encText = urllib.parse.quote("검색할 단어")
# 위에서 알아본 것처럼 query={value}에서 value에 위 encText 변수를 삽입
# encText라는 검색어를 담고있는 url 변수 작성
url = "https://openapi.naver.com/v1/search/blog?query=" + encText # json 결과
# url = "https://openapi.naver.com/v1/search/blog.xml?query=" + encText # xml 결과
# request.Request는 URL 요청의 추상화
request = urllib.request.Request(url)
# url을 요청할 때 보안을 위해 헤더에 추가적인 정보를 요청하는 API들이 있다.
request.add_header("X-Naver-Client-Id",client_id)
request.add_header("X-Naver-Client-Secret",client_secret)
# urlopen은 request를 보낼 인자를 받고, request를 보내 response를 반환한다.
response = urllib.request.urlopen(request)
# 응답 코드를 받는다.
rescode = response.getcode()
# 200(성공 코드)를 받는다면 response를 출력한다.
if(rescode==200):
response_body = response.read()
print(response_body.decode('utf-8'))
else:
print("Error Code:" + rescode)
https://incomeplus.tistory.com/254
파이썬 urllib.request VS requests 차이점?
파이썬으로 웹사이트를 크롤링 할 때 가장 많이 사용되는 함수가 urllib.request와 requests다. 분명히 두 개함수가 차이가 있고, 필요한 상황에 맞춰 사용할 줄 알아야 할 것이다. 먼저 크롤링을 하기
incomeplus.tistory.com
https://developer.mozilla.org/ko/docs/Web/HTTP/Status
HTTP 상태 코드 - HTTP | MDN
HTTP 응답 상태 코드는 특정 HTTP 요청이 성공적으로 완료되었는지 알려줍니다. 응답은 5개의 그룹으로 나누어집니다: 정보를 제공하는 응답, 성공적인 응답, 리다이렉트, 클라이언트 에러, 그리고
developer.mozilla.org
response에 저장된 api 객체를 JSON 형식으로 저장하고 싶을 때
# 네이버 검색 API예제는 블로그를 비롯 전문자료까지 호출방법이 동일하므로 blog검색만 대표로 예제를 올렸습니다.
# 네이버 검색 Open API 예제 - 블로그 검색
import os
import sys
import json
# 특정 url에 request를 보낼 수 있도록 해주는 라이브러리
import urllib.request
# API 이용 신청을 통해 받은 id와 secret 입력
client_id = "YOUR_CLIENT_ID"
client_secret = "YOUR_CLIENT_SECRET"
# 검색할 단어를 입력받을 변수
# urllib.parse.quote()는 아스키코드 형식이 아닌 글자를 URL 인코딩 시켜줍니다.
encText = urllib.parse.quote("검색할 단어")
# 위에서 알아본 것처럼 query={value}에서 value에 위 encText 변수를 삽입
# encText라는 검색어를 담고있는 url 변수 작성
url = "https://openapi.naver.com/v1/search/blog?query=" + encText # json 결과
# url = "https://openapi.naver.com/v1/search/blog.xml?query=" + encText # xml 결과
# request.Request는 URL 요청의 추상화
request = urllib.request.Request(url)
# url을 요청할 때 보안을 위해 헤더에 추가적인 정보를 요청하는 API들이 있다.
request.add_header("X-Naver-Client-Id",client_id)
request.add_header("X-Naver-Client-Secret",client_secret)
# urlopen은 request를 보낼 인자를 받고, request를 보내 response를 반환한다.
response = urllib.request.urlopen(request)
# 응답 코드를 받는다.
rescode = response.getcode()
# 200(성공 코드)를 받는다면 response를 출력한다.
if(rescode==200):
response_body = response.read()
print(response_body.decode('utf-8'))
else:
print("Error Code:" + rescode)
resjson = response_body.decode('utf-8')
with open('movie.json', 'w', encoading='UTF-8-sig') as file:
file.write(json.dumps(resjson, ensure_ascii=False))
JSON 각 key에 접근하는 방법
pydata = json.loads(resdata)
data = pydata['items']
https://www.daleseo.com/python-json/
파이썬의 json 모듈로 JSON 데이터 다루기
Engineering Blog by Dale Seo
www.daleseo.com
검색 기능 구현하기
https://devdongbaek.tistory.com/57
동백 // QuerySet을 통한 간단 검색 구현
devdongbaek.tistory.com
https://ghqls0210.tistory.com/53
django / 검색 기능
이번에는 검색 기능을 만들어보겠습니다. 검색 기능 또한 직전 포스팅인 정렬과 같은 html에 만들면 좋지만 그러면 강제적으로 만들어 놓은 url을 수정해야되서 새로 url을 만들어서 하겠습니다. u
ghqls0210.tistory.com
Django Web Project 개발일지4) 검색 기능 추가
djangoWeb searh 기능 추가
velog.io
https://devdongbaek.tistory.com/91
Django 빌트인 CBV를 통한 Form 처리
출처 : https://www.inflearn.com/course/%ED%8C%8C%EC%9D%B4%EC%8D%AC-%EC%9E%A5%EA%B3%A0-%EC%9B%B9%EC%84%9C%EB%B9%84%EC%8A%A4/dashboard 장고(Django)를 배우기 시작한 입문자이시거나, 또는 배우고 싶은 생..
devdongbaek.tistory.com
formview는 form을 보여주는 로직의 view
Generic editing views | Django documentation | Django
Django The web framework for perfectionists with deadlines. Overview Download Documentation News Community Code Issues About ♥ Donate
docs.djangoproject.com
urls.py
path('search/', views.search.as_view(), name='search'),
forms.py
from django import forms
class SearchForm(forms.Form):
search = forms.CharField(label='검색할 단어를 입력하세요', max_length=100)
views.py
from .forms import SearchForm
class search(Formview):
form_class = SearchForm
templates_name = 'blog/post_search.html'
# form 입력이 성공했을 때
def form_valid(self, form):
# form field 이름과 동일해야 함
searchWord = form.cleaned_data['search']
post_list = Post.objects.filter(Q(title__icontains=searchWord) | Q(description__icontains=searchWord) | Q(content__icontains=searchWord)).distinct()
# 딕셔너리 형식으로 값 저장
"""
form = context.form
searchWord = context.search_term
post_list = context.object_list
"""
context = {}
context['form'] = form
context['search_term'] = searchWord
context['object_list'] = post_list
return render(self.request, self.template_name, context)
. context라는 딕셔너리를 통해 템플릿에 인자를 전달한다.
templates
{% extends "base.html" %}
{% block title %}post_search.html{% endblock %}
{% block content %}
<h1>Blog Search</h1>
<br>
<form action="." method="post"> {% csrf_token %}
{{ form.as_table }} <!-- form을 테이블 형식으로 표시, 여기서 form은 views에서 넘겨준 PostSearchForm 객체임-->
<input type="submit" value="Submit" class="btn btn-primary btn-sm">
</form>
<br/><br/>
{% if object_list %}
{% for post in object_list %}
<h2><a href='{{ post.get_absolute_url }}'>{{ post.title }}</a></h2>
{{ post.modify_date|date:"N d, Y" }}
<p>{{ post.description }}</p>
{% endfor %}
{% elif search_term %}<!-- 검색란이 공란인지 확인-->
<b><i>Search Word({{ search_term }}) Not Found</i></b>
{% endif %}
{% endblock %}
https://velog.io/@jxxwon/Django-Q-%EA%B0%9D%EC%B2%B4
Django Q 객체
장고 Q객체
velog.io
CBV
02) 클래스형 뷰 (CBV)
[TOC] # 클래스형 뷰 (CBV, Class-Based View) 클래스형 뷰는 상속과 믹스인 기능을 이용하여 코드 재사용하고 뷰를 체계적으로 구성할 수 있다. ## ...
wikidocs.net