Django

2022. 10. 24. 14:23AI/프로그래머스 AI 코스

장고의 구조

수정사항마다 4가지 관계를 고려해서 모두 수정해주어야함

URL - urls.py파일에서 view.py의 함수를 import 

View - views.py에서 url에서의 동작을 define

DB - model.py에서 Db의 구조 정의(Class와 column 정의)

Template - .html 파일

 

urls.py - view.py (+model.py) - 'abc.html'

 

개발 환경 세팅

#version
python 3.10
django 4.1


# 프로젝트 생성 : 프로젝트의 config 폴더와 manage.py 파일 생성
django-admin startproject config .

# pybo 앱 생성 : 프로젝트의 구성하는 하나의 app 생성
django-admin startapp pybo

# 서버 실행
python manage.py runserver

# timezone
TIME_ZONE = "Asia/Seoul"

# 언어 설정
LANGUAGE_CODE = "ko-kr"

# template 폴더 정보 추가 - setting.py에 TEMPLATES
TEMPLATES = [
    { ...  
        "DIRS": [os.path.join(BASE_DIR, "pybo", "template")], ...	# template 폴더 경로 추가
# app 정보 추가 - setting.py에 INSTALLED_APPS 변수에 내용 추가
INSTALLED_APPS = [...
    'pybo', ...]	# app 폴더명 추가

URL mapping 추가

# config/urls.py
from pybo import views
urlpatterns = [
    path("admin/", admin.site.urls),
    path('pybo/', views.index)
]

view.py 에 함수 추가

# pybo/views.py 

from django.http import HttpResponse
def index(request):
    return HttpResponse('hello')		# 간단 HttpResponse 타입으로 string 전달
    return render(request, 'index.html', # index.html 파일을 이용해서 page rendering 
    {'my_name' : name, "my_list" : my_list})	# index.html에 전달할 arg
    
    
from .models import Coffee		# DB에서 Coffee 라는 class(테이블) import

def coffee_view(request):
    coffee_all = Coffee.objects.all()   # SELECT * FROM Coffee
    
    return render(request, 'coffee.html', 
    {"coffee_list" : coffee_all})		# Db에 있는 Coffee 테이블의 데이터를 coffee.html로 전달

URL 분리

# config/url.py
from django.urls import path, include		# include 함수 사용
from pybo import views

urlpatterns = [
    path("admin/", admin.site.urls),
    path('pybo/', include('pybo.urls')),	# pybo app의 url은 'pybo.urls' 참조
    ]

pybo/urls.py 만들기

# pybo/urls.py
from django.urls import path
from . import views

urlpatterns = [path("", views.index),]	# url = /pybo/
# config/urls.py에서 /pybo/로 연결되는 url을 pybo/urls.py로 연결하였고, 
# path("test", veiw.text)인 경우 최종 url은 pybo/test가 된다

이미지 출력

이미지 경로

pybo\static\pybo\cat.jpg 

# HTML 문서에 코드 입력
{% load static %}
    <img src="{% static '/pybo/cat.jpg' %}" alt="My image">		# image 경로 지정

DB 관리

Model.py 수정, ORM 방식으로 db 관리하며 테이블은 class로 생성

# models.py
class Coffee(models.Model):
    name = models.CharField(default = "", null = False, max_length = 30)
    price = models.IntegerField(default = 0)
    is_ice = models.BooleanField(default = False)

admin에 Coffee class를 연결하면 /admin 페이지에서 db를 관리할수 있다

# admin.py
from django.contrib import admin
from .models import Coffee		# DB class를 import

# Register your models here.
admin.site.register(Coffee)		# admin 페이지에 Coffee를 추가

superuser 만들기

python manage.py createsuperuser
# 사용자 이름, 이메일 주소, 비밀번호 입력

/admin 에서 로그인하고 admin.py 에 등록된 모델을 관리할수 있다


변경내용 반영이 안될때  -- migrate 하기

python manage.py makemigration pybo		# 'pybo' 라는 app의 변경내용 migration 만들기
python manage.py migrate		# 현재까지 만들어진 migration을 migrate 진행

python manage.py showmigration # 현재까지 만들어진 migration 확인

Form 만들기

form class 만들기

# form.py
from django import forms

from .models import Coffee  # Model 호출

class CoffeeForm(forms.ModelForm):  # ModelForm을 상속받는 Coffee
    class Meta:
        model = Coffee
        fields = ('name', 'price', 'is_ice')

view.py에서 form object를 .html로 전달

# view.py
from .forms import CoffeeForm		# form.py에서 CoffeeForm 클래스 import

def coffee_view(request):
    coffee_all = Coffee.objects.all()   # SELECT * FROM Coffee
    form = CoffeeForm()		# form 객체 생성

    return render(request, 'coffee.html', 
    {"coffee_list" : coffee_all, "coffee_form" : form})		# form

.html에서 장고 form 표현

<form>
        {{ coffee_form.as_p}}	# .as_p로 나타내기
    </form>

 

CSRF 검증 실패 오류

csrf 토큰 생성하기

<form method="POST"> {% csrf_token %}		# form 내에 {% csrf_token %} 추가
        {{ coffee_form.as_p}}
        <button type = 'submit'>Save</button>
</form>

https://eunjin3786.tistory.com/133

ORM 테이블 만들기

from django.db import models
class Orm(models.Model):
	def __str__(self):	# 데이터 조회시 default는 id가 출력, 출력할 내용으로 함수로 작성할수 있다
    	return self.name
        
	name = models.CharField(default = "", null = False, max_length = 30)
    price = models.IntegerField(default = 0)
    is_ice = models.BooleanField(default = False)

ORM 테이블 객체 생성

o = Orm(name = 'ice americano', price = 2000, is_ice = True)	# 데이터 한개의 열생성
o.save()		# 데이터 추가

데이터 조회

o.id			# id 출력
Orm.objects.all()		# 모델의 전체 데이터 조회
Orm.objects.filter(id=1)	# filter로 전체 데이터에서 조건에 맞는 데이터(여러개) 추출
Orm.objects.get(id=1)	# 조건에 맞는 데이터 1개 출력
Orm.objects.filter(name__contatins = 'ice')	# name 속성에 ice가 포함되는 데이터 추출

ORM 데이터 수정

o = Orm.objects.get(name = 'ice americano')
o.name = 'latte'
o.save()

ORM 데이터 삭제

o = Orm.objects.get(name = 'latte')
o.delete()

HTML form으로 전달받은 value들을 template에 보여주기

POST method일때, 유효한 form에 한해서 save하고 rendering 진행

# view.py 

def coffee_view(request):
    coffee_all = Coffee.objects.all()   # SELECT * FROM Coffee
    # 만약 request가 POST라면 
        # POST를 바탕으로 Form을 만들고
        # Form이 유효하면 저장
    
    if request.method == 'POST':		# method가 POST일때만
        form = CoffeeForm(request.POST) # 완성된 Form
        if form.is_valid(): # 완성된 Form이 유효하다면:
            form.save()     # Form을 model에 저장

    return render(request, 'coffee.html', 
    {"coffee_list" : coffee_all, "coffee_form" : form})

장고에서 form 만들기

forms.Form을 상속받으면 폼, forms.ModelForm을 상속받으면 모델 폼이라 한다

# forms.py

from django import forms
from .models import Coffee  # models.py 에서 정의한 class import

class CoffeeForm(forms.ModelForm):  # forms.ModelForm을 상속받는 Coffee
    class Meta:
        model = Coffee
        fields = ('name', 'price', 'is_ice')
        
        # 장고폼에 style 만들기, 
        # .as_p로 입력항목을 생성할경우 부트스트랩을 적용할수 없어서 widgets 속성을 만든다
        widgets = {
            'name' : forms.TextInput(attrs={'class': 'form-control'}),
            'price' : forms.TextInput(attrs={'class': 'form-control'}),
        }

URL에서 인수 전달 받기

url.py 에서 url과 (<type:arg_name>/) 호출 함수 지정

# urls.py
urlpatterns = [path("<int:question_id>/", views.detail),    ]

# views.py
def detail(request, question_id):
	return HttpResponse('arg is %s' %question_id)

 

URL name과 namespace

urls.py에서 url의 name과 app_name 설정

# urls.py
app_name = 'pybo'

urlpatterns = [path("<int:question_id>/", views.detail, name = 'detail'),	]

템플릿에서 namespace 만들기

<a href = "/pybo/{{ question.id}}/">		# 하드코딩
<a href = "{% url 'pybo:detail' question.id %}">	# 네임스페이스와 별칭사용

get_object_or_404

get object에 실패하면 debug 화면대신 404 화면 출력 

# view.py 
def action(request, question_id):
	c = get_object_or_404(Coffee, id=question_id)	# model class와 arg 전달
    ...
 
HTML에서 view.py로 arg 전달
<form method="POST"> {% csrf_token %}		# Method 정하기
        ID : <input type="text" name="id">	# input form 은 text 타입, name = 'id'
        <button type = 'submit'>Delete</button>	# submit 타입의 버튼
    </form>

view.py에서 arg로 동작 정의

템플릿(html)에서 정의된 name을 request.<method>.get()으로 가져오기

id = request.POST.get('id')     # POST request에서 name='id' 값을 받아온다
c = get_object_or_404(Coffee, id=id)    # model의 데이터를 받아오며, 없을경우 404 출력
c.delete()      # 데이터 delete

CSS 사용

static file을 추가할 디렉토리 경로 정보 추가

# settings.py

STATIC_URL = "static/"
STATICFILES_DIRS = [BASE_DIR / 'pybo/static/pybo', ]	# STATICFILES_DIRS 추가

style.css 생성

# static/style.css

input[type=submit]{
    margin-top:10px
}

템플릿에 스타일 적용

# .html 파일에 아래 코드 적용

# static load 
{% load static%}

# css file 연결 또는 link 연결
<link rel="stylesheet" href="{% static 'css/bootstrap.min.css' %}">	# css file을 경로
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-Zenh87qX5JnK2Jl0vWa8Ck2rdkQ2Bzep5IDxbcnCeuOxjzrPF/et3URy9Bv1WTRi" crossorigin="anonymous">


# table에 style 적용
<body>
    <h1>Coffee List</h1>
    <div class="container my-3">	# class명 지정
        <table class="table">
            <thread>
                <tr class="thread-dark">
                    <th>번호</th>
                </tr>
            </thead>
            <tbody>

    {% for element in coffee_list %}
    <tr>
        <td> {{element.id}}</td>
        <td> {{element.name}}</td>
        <td> {{element.price}}</td>
    </tr>

    {% endfor%}
</tbody>
</table>
</div>

템플릿 상속

base.html을 상속받아서 모든 템플릿에 적용하기

# base.html

{% load static%}
<!doctype html>
<html lang='ko'>
    <head>
        <!-- Required meta tags-->
        <meta charse = 'utf-8'>
        <meta name = 'viewport' content='width=device-width, initial-scale=1, shrink-to-fit=no'>
        <!-- Bootstrap CSS -->
        <link rel="stylesheet" type = 'text/css' href="{% static 'css/bootstrap.min.css' %}">
        <!-- pybo CSS-->
        <link rel="stylesheet" type = 'text/css' href="{% static 'css/style.css' %}">
        <title>Hello, pybo!</title>
    </head>
    <body>
        <!-- 기본 템플릿 안에 삽입될 내용 start -->
        {% block content %}
        {% endblock %}
        <!-- 기본 템플릿 안에 삽입될 내용 end -->
    </body>
</html>

상속 받는 html

# extend.html

{% extends 'base.html' %}
{% block content %}

<!-- content 작성 -->

{% endblock %}

CSS로 네비게이션바, 로그인 버튼 만들기

bast.html에 기능을 추가하고 템플릿에서 상속한다

# base.html

<!-- 네비게이션바  -->
        <nav class = 'navbar navbar-expand-lg navbar-light bg-light border-bottom'>
            <a class = 'navbar-brand' href ="{% url 'pybo:home'  %}">pybo</a>
            <!-- 화면 크기에 따라서 버튼의 모양이 바뀐다 -->
            <!-- 작은 화면일때 햄버거 메뉴 버튼 -->
            <button class = 'navbar-toggler ml-auto' type = 'button' data-toggle='collapse'
            data-target = '#navbarNav' aria-controls = 'navbarNav'
            aria-expanded='false' aria-label='Toggle navigation'>
            <span class ='navbar-toggler-icon'></span>
            </button>
            <!-- 큰 화면일때 로그인 버튼 -->
            <div class = 'collapse navbar-collapse flex-grow-0' id='navbarNav'>
                <ul class = 'navbar-nav'>
                    <li class = 'nav-item'>
                        <a class = 'nav-link' href='#'>로그인</a>
                    </li>
                </ul>
            </div>
         </nav>

부트스트랩 자바스크립트 파일 추가

부트스트랩을 사용한 버튼은 자바스크립트 파일이 html에 포함되어 있어야 동작한다. 자바스크립트 파일은 제이쿼리를 기반으로 동작하므로, 1. 자바스크립트 파일과 2. 제이쿼리 파일을 추가해준다

https://jquery.com/download/

 

Download jQuery | jQuery

link Downloading jQuery Compressed and uncompressed copies of jQuery files are available. The uncompressed file is best used during development or debugging; the compressed file saves bandwidth and improves performance in production. You can also download

jquery.com

compressed production으로 링크 저장

 

템플릿에서 include 사용

navbar.html 파일로 만든후, base.html에서 include로 재사용

# base.html

<body>
        {% include 'navbar.html' %}		# include 사용
        <!-- 기본 템플릿 안에 삽입될 내용 start -->
        {% block content %}
        {% endblock %}
            <!-- 기본 템플릿 안에 삽입될 내용 end -->
        <!-- jQuery JS -->
        <script src="{% static 'jquery-3.6.1.min.js' %}"></script>
        <!-- Bootstrap JS JS -->
        <script src="{% static 'bootstrap.min.js' %}"></script>
        
</body>

HTML 태그

<a> : 하이퍼링크

<a href = 'https://....' title = '표시할내용'>

 

<div> : 구역으로 묶음

<link> : 외부 파일 연결, css 파일을 외부에서 연결

<style> : css 파일을 내부에서 정의

<img src = '이미지 경로'>

HTML 입력 폼

https://www.devkuma.com/docs/html/html-%EC%9E%85%EB%A0%A5-input-%EC%9A%94%EC%86%8C-%ED%83%80%EC%9E%85-type

 

Heroku로 배포하기

https://velog.io/@ansfls/Heroku%EB%A1%9C-%EA%B0%84%EB%8B%A8%ED%95%98%EA%B2%8C-%EC%9B%B9-%EC%82%AC%EC%9D%B4%ED%8A%B8-%EB%B0%B0%ED%8F%AC%ED%95%98%EA%B8%B0

 

https://incomeplus.tistory.com/155

git init
git add .
git commit -m 'first'


heroku login
heroku git:remote -a 'app_name'

# file 만들기
requirement.txt		# django, gunicorn 설치 
Procfile		# web: gunicorn appname.wsgi 
runtime.txt		# python-3.10.8 

git push heroku master

 

https://www.youtube.com/watch?v=uOhfiYvvcjg&ab_channel=BIPASORI

 

Heroku Truble Shooting

정상 동작시 log 참고

https://devcenter.heroku.com/articles/getting-started-with-python#deploy-the-app

project app 할일

requirements.txt, Procfile, runtime.txt 파일 만들기

# Procfile
web: gunicorn config.wsgi
web: gunicorn <app name>.wsgi

# runtime.txt
python-3.10.8

setting.py 수정

 

buildpack error

https://velog.io/@nemo/heroku-error-buildpack-nodejs

runtime.txt 만들기

 

Error while running '$ python manage.py collectstatic --noinput'

heroku config:set DISABLE_COLLECTSTATIC=1

CSS 적용안됨 -> whitenoise 라이브러리 설치, 설정 추가

https://eveningdev.tistory.com/53

pip install gunicorn whitenoise dj-database-url psycopg2-binary

 

# settings.py

MIDDLEWARE = [...,
'whitenoise.middleware.WhiteNoiseMiddleware',
... ]

import dj_database_url
db_from_env = dj_database_url.config(conn_max_age=500)
DATABASES['default'].update(db_from_env)

 

어쨌든 성공...

'AI > 프로그래머스 AI 코스' 카테고리의 다른 글

Flask  (0) 2022.10.13
Git 요약  (0) 2022.10.04
MySQL  (0) 2022.09.28
Selenium  (0) 2022.09.28
BeautifulSoup4  (0) 2022.09.27