1. request.GET

 

request.GET은 http request의 정보를 dictionary 데이터로 받는 기능이다.

 

topic = request.GET.get("topic",None)

위의 코드를 살펴보면 request에 담겨있는 "topic"이라는 내용을 가져오는 것이다. 뒤에 None은 "topic"이라는 정보가 없으면 None을 가져온다는 의미이다. (오류 방지)

 

 

2. request.META

 

request.META는 사용자의 IP 주소와 사용자 Agent(일반적으로 웹 브라우저의 이름과 버전)를 포함해 지정된 요청에 대해 사용할 수 있는 모든 HTTP 헤더가 들어있는 파이썬 딕셔너리다.

 

  • request.META는 기본 파이썬 딕셔너리이므로 존재하지 않는 키에 접근하면 KeyError 예외 발생.
  • 헤더는 외부 데이터이므로 신뢰할 수 없고, 특정 헤더가 비어있거나 존재하지 않으면 정상적으로 동작하지 않도록 해야한다.
  • 정의되지 않는 키의 대소 문자를 처리하려면 try/except 나 get() 메소드 사용

 

1) 안좋은 예시

def ua_display_bad(request):
    ua = request.META['HTTP_USER_AGENT']  # Might raise KeyError!
    return HttpResponse("Your browser is %s" % ua)

 

2) 좋은 예시

def ua_display_good1(request):
    try:
        ua = request.META['HTTP_USER_AGENT']
    except KeyError:
        ua = 'unknown'
    return HttpResponse("Your browser is %s" % ua)

 

3) 좋은 예시

def ua_display_good2(request):
    ua = request.META.get('HTTP_USER_AGENT', 'unknown')
    return HttpResponse("Your browser is %s" % ua)

 

출처 : https://yonghyunlee.gitlab.io/python/django-master-6/

 

 

3. requests

django에서 POST나 GET을 사용하는 requests라는 모듈이 있다. 

 

https://docs.python-requests.org/en/master/user/quickstart/

 

'Back-End > Django' 카테고리의 다른 글

Wagtail Django_extensions, ipython  (0) 2021.11.19
Django Signals  (0) 2021.10.22
Django ORM  (0) 2021.10.21
Django iamport 적용하기  (0) 2021.10.06
Django Bulma 적용 방법  (0) 2021.08.24

Wagtail이나 Django로 개발을 하다보면 orm을 사용하게 된다. 

보통 shell을 많이 사용하는데 shell은 직접 사용 모듈을 import해야하는 번거로움이 있다. 

Django_extensions은 미리 관련 module을 import 해줘서 효율적인 개발을 도와준다. 

 

 

설치방법은 아래와 같다. 

pip install django-extensions

 

settings/dev.py

INSTALLED_APPS = INSTALLED_APPS + [
    'django_extensions',
]

 

 

설치를 다 했으면 실행시켜보자.

python manage.py shell_plus

 

몇가지 Wagtail과 Django에서 사용하는 orm을 정리해보려고 한다.

 

 

1) all()

BlogDetailPage.objects.all()

모든 BlogDetailPage의 객체들을 가져온다.

 

2) last()

BlogDetailPage.objects.last()

마지막에 작성된 BlogDetailPage의 객체를 가져온다.

 

3) first()

BlogDetailPage.objects.first()

첫번째로 작성된 BlogDetailPage의 객체를 가져온다.

 

4) live()

BlogDetailPage.objects.live()

현재 발행 중인(wagtail) 객체를 가져온다.

 

5) filter()

BlogDetailPage.objects.filter(title="Blog Post #1")

특정 조건의 객체를 가져온다.

 

6) list

posts = BlogDetailPage.objects.all()
first_post = posts[0]

첫번째 순서에 위치 되어 있는 객체를 가져온다.

 

7) __dict__

first_post.__dict__

객체의 모든 정보를 가져온다.

 

8) __dir__

first_post.__dir__

객체가 저장되어 있는 메모리 주소를 가져온다.

 

9) get_parent()

first_post.get_parent()

객체의 부모 페이지 객체를 가져온다.

 

10) siblings()

first_post.get_siblings()

같은 레벨의 객체들을 가져온다.

 

11) save()

first_post.title = "First Blog Post (test title)"
first_post.save()
first_post
>><BlogDetailPage: First Blog Post (test title)>

객체의 변경내용을 저장한다.

 

 

추가)

하지만 django_extensions보다 더욱 편리하게 사용할 수 있는 방법이 있다. 

 

1. ipython 설치

pip install ipython

 

2. ipython 실행

python manage.py shell_plus --ipython

 

3. using TAB

객체를 입력하고 tab key를 누르면 모든 orm이 나온다. 물론 전부 사용할 수 있는 것이 아니라 객체의 정상적인 orm을 사용해야할 것이다. 

 

종료하고 싶을 때는 

exit

 

'Back-End > Django' 카테고리의 다른 글

Django Request, Requests  (0) 2021.12.16
Django Signals  (0) 2021.10.22
Django ORM  (0) 2021.10.21
Django iamport 적용하기  (0) 2021.10.06
Django Bulma 적용 방법  (0) 2021.08.24

https://velog.io/@ifyouseeksoomi/10.DRF-Level-Three-Django-REST-Framework-1.-Signal

 

Django에서는 로그인, 로그아웃이나 모델 생성등 어떤 기능을 작동할 때, singal을 발생 시킨다. 

그래서 signal을 통해 기능을 추가할 수 있다. (회원가입 했을때 축하 메일을 보내는 것 처럼)

 

Django를 다룰 때 필수적인 기능인 signal에 대해서 정리해보려고 한다. 

 

이번에 할 기능은 회원 가입시 개발 중인 Page에서 자동으로 관련 모델을 생성해주는 기능을 적어보려고 한다. 

 

1. Signals.py

user_management/signals.py

from user.models import User
from django.db.models.signals import post_save
from django.dispatch import receiver
from user_management.models import UserCourseRelationship, UserPyCoin


@receiver(post_save, sender=User)
def create_user_account(sender, instance, created, **kwargs):
    if created:
        UserCourseRelationship.objects.create(user=instance)
        UserPyCoin.objects.create(user=instance)

회원 가입이 되었을 때, 자동으로 UserCourseRelationship 모델과 UserPyCoin 모델을 생성해주려고 한다. 

 

먼저 나는 User 모델이 user.models에 AbstractUser로 재정의 되어 있으니 user.models.py에서 가져왔다.

그리고 django signals을 가져오면 되는데 회원가입, 즉 새로운 User 모델이 생성이 되는 것이므로 post_save(모델이 생성될 때 사용하는 signal)을 사용한다. 

signal에 대한 문서는 

https://docs.djangoproject.com/en/3.2/ref/signals/#django.db.models.signals.post_save

윗 링크를 참고하자 (장고 공식 문서) 이외에도 다양한 signals이 존재한다.

 

@receiver를 통해 어떤 기능을 수행하는지 정의 해 준다. 

@receiver(post_save, sender=User)

위 코드의 뜻은 User 모델에 post_save signal을 보내겠다는 의미이다. 

함수명은 직관적이게 create_user_account로 해주었다.

 

그리고 새로운 User 모델이 생성되었을 때(회원 가입 시), 기본 모델을 생성해주는 것이기 때문에 created를 사용한다. (created를 사용하기 위해 post_save로 해주었다고 생각하면 된다. created가 없으면 User모델이 동작할 때 마다 이벤트가 발생된다. 즉 로그인만 해도 자동으로 기본 모델이 생성되어 버린다.)

 

def create_user_account(sender, instance, created, **kwargs):
    if created:
        UserCourseRelationship.objects.create(user=instance)
        UserPyCoin.objects.create(user=instance)

sender는 User 모델을 의미하고 instance에는 현재 만들어진 인스턴스(회원 가입이므로 방금 회원가입한 사람)가 저장된다. 정리하자면 sender는 모델 그 자체이고 instance는 방금 생성된 instance를 뜻한다.

 

 2. apps.py에 작성

user_management/apps.py

class AccountConfig(AppConfig):
    name = 'user_management'

    def ready(self):
        import user_management.signals

다음은 apps.py에 우리가 만든 signals.py를 등록해줘야한다. 여기서 name에는 signals.py가 있는 app이름을 적어야 한다. 

 

3. __init__.py 작성 (settings.py에 작성)

user_management/__init__.py

default_app_config = "user_management.apps.AccountConfig"

init 파일에 AccountConfig를 실행해주라는 코드를 작성한다. (하지만 Django에서는 installed_app에 적는 것을 권장하고 있다.)

 

settings.py

INSTALLED_APPS = [
	#'user_management', 대신에
    'user_management.apps.AccountConfig', # 로 적으면 된다.
]

위와 같이 바꾸어 주자.

 

이제 회원가입할 때 마다 자동으로 모델이 생성되어지는 것을 확인할 수 있다. signals를 사용하면 정말 다양한 기능을 구현할 수 있을 것으로 생각된다. 다음에는 회원가입을 했을 때, 자동으로 축하 메세지를 보내는 기능을 구현해보고 싶다.

 

추가)

user_management/apps.py

from django.apps import AppConfig


class UserManagementConfig(AppConfig):
    default_auto_field = 'django.db.models.BigAutoField'
    name = 'user_management'

    def ready(self):
        import user_management.signals

단순하게 기존 apps.py에 def ready만 추가하고 signals을 받으면 된다.

 

settings.py

INSTALLED_APPS = [
	'user_management', # 그냥 기존과 같이 적으면 된다.
]

 

정리하자면 INSTALLED_APPS에 app이름을 등록을 해주면 일단 __init__.py을 실행한다. (기본적으로 아무 것도 정의되어 있지 않음) 그러면 자동으로 apps.py에 가서 AppConfig를 실행해주게 된다.

 

참고로 AutoField는 Django ORM에서 자동적으로 생성되는 Auto increment Primary key를 말한다.

출처: https://www.morenice.kr/263 [morenice's blog]

'Back-End > Django' 카테고리의 다른 글

Django Request, Requests  (0) 2021.12.16
Wagtail Django_extensions, ipython  (0) 2021.11.19
Django ORM  (0) 2021.10.21
Django iamport 적용하기  (0) 2021.10.06
Django Bulma 적용 방법  (0) 2021.08.24

https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=dudwo567890&logNo=220924729927 

 

Django, SQL query와 ORM 정리

Django, SQL query와 ORM 정리models.pyclass Site(models.Model): name = models.CharField(ma...

blog.naver.com

 

ORM이란, 객채(Object)의 관계(Relational)를 연결(Mapper)해주는 것을 뜻한다. 객체 지향적인 방법을 사용하여 데이터베이스의 데이터를 쉽게 조작할 수 있게 해주는 것이다.

 

 

Django, SQL query와 ORM 정리

models.py

class Site(models.Model):

    name = models.CharField(max_length=255,)

 

class Category(models.Model):

    name = models.CharField(max_length=255,)

 

class Article(models.Model):

    subject = models.CharField(max_length=255,)

    url = models.URLField(unique=True,)

    date = models.DateTimeField()

    site = models.ForeignKey(Site)

    category = models.ManyToManyField(Category)

    hit = models.IntegerField(default=0)

 

SQL

CREATE TABLE `web_site` (

  `id` INT(11) NOT NULL AUTO_INCREMENT,

  `name` VARCHAR(255) NOT NULL,

  PRIMARY KEY (`id`)

) ENGINE=INNODB AUTO_INCREMENT=0

 

CREATE TABLE `web_category` (

  `id` INT(11) NOT NULL AUTO_INCREMENT,

  `name` VARCHAR(255) NOT NULL,

  PRIMARY KEY (`id`)

) ENGINE=INNODB AUTO_INCREMENT=0

 

CREATE TABLE `web_article` (

  `id` INT(11) NOT NULL AUTO_INCREMENT,

  `subject` VARCHAR(255) NOT NULL,

  `url` VARCHAR(200) NOT NULL,

  `date` DATETIME(6) NOT NULL,

  `site_id` INT(11) NOT NULL,

  `hit` INT(11) NOT NULL,

  PRIMARY KEY (`id`),

  UNIQUE KEY `url` (`url`),

  KEY `web_article_site_id_8dbc8100_fk_web_site_id` (`site_id`),

  CONSTRAINT `web_article_site_id_8dbc8100_fk_web_site_id` FOREIGN KEY (`site_id`) REFERENCES `web_site` (`id`)

) ENGINE=INNODB AUTO_INCREMENT=0

 

CREATE TABLE `web_article_category` (

  `id` INT(11) NOT NULL AUTO_INCREMENT,

  `article_id` INT(11) NOT NULL,

  `category_id` INT(11) NOT NULL,

  PRIMARY KEY (`id`),

  UNIQUE KEY `web_article_category_article_id_9ea0efa6_uniq` (`article_id`,`category_id`),

  KEY `web_article_category_category_id_d2d88408_fk_web_category_id` (`category_id`),

  CONSTRAINT `web_article_category_article_id_5b4eba1c_fk_web_article_id` FOREIGN KEY (`article_id`) REFERENCES `web_article` (`id`),

  CONSTRAINT `web_article_category_category_id_d2d88408_fk_web_category_id` FOREIGN KEY (`category_id`) REFERENCES `web_category` (`id`)

) ENGINE=INNODB AUTO_INCREMENT=0

 

SELECT

ALL

SQL

SELECT * FROM web_article;

ORM

Article.objects.all()

 

WHERE

SQL

SELECT * FROM web_article WHERE id=1;

ORM

Article.objects.filter(id=1)

 

LIMIT n

SQL

SELECT * FROM web_article LIMIT 10;

ORM

Article.objects.all()[:10]

 

LIMIT n,n

SQL

SELECT * FROM web_article LIMIT 5,5;

ORM

Article.objects.all()[5:10]

 

fetchone

SQL

SELECT * FROM web_article WHERE id=1;

ORM

Article.objects.get(id=1) #Return : Object

 

fetchall

SQL

SELECT * FROM web_article WHERE site_id=1;

ORM

Article.objects.filter(site_id=1) #Return : QuerySet

 

AND

SQL

SELECT * FROM web_article WHERE site_id=1 AND hit=0;

ORM

Article.objects.filter(site_id=1,hit=0)

 

OR

SQL

SELECT * FROM web_article WHERE site_id=1 OR hit=0;

ORM

from django.db.models import Q

Article.objects.filter(Q(site_id=1)|Q(hit=0))

 

LIKE '%s%'

SQL

SELECT * FROM web_article WHERE subject LIKE '%공무원%';

ORM

Article.objects.filter(subject__icontains='공무원')

 

LIKE 's%'

SQL

SELECT * FROM web_article WHERE SUBJECT LIKE '유승민%';

ORM

Article.objects.filter(subject__startswith='유승민')

 

LIKE '%s'

SQL

SELECT * FROM web_article WHERE SUBJECT LIKE '%의혹';

ORM

Article.objects.filter(subject__endswith='의혹')

 

>=

SQL

SELECT * FROM web_article WHERE hit >= 2;

ORM

Article.objects.filter(hit__gte=2)

 

<=

SQL

SELECT * FROM web_article WHERE hit <= 2;

ORM

Article.objects.filter(hit__lte=2)

 

>

SQL

SELECT * FROM web_article WHERE hit > 1;

ORM

Article.objects.filter(hit__gt=1)

 

<

SQL

SELECT * FROM web_article WHERE hit < 1;

ORM

Article.objects.filter(hit__lt=1)

 

LEFT JOIN(ManyToManyField)

SQL

SELECT b.id FROM web_article_category AS a LEFT JOIN web_article AS b ON a.article_id = b.id LEFT JOIN web_category AS c ON c.id=a.category_id WHERE c.name='정치';

ORM

Category.objects.get(name='정치').article_set.all()

 

INSERT

집어넣기

SQL

INSERT INTO web_site SET name='뉴스타파';

ORM

site = Site(name='뉴스타파')

site.save() #commit 

 

있으면 가져오고 없으면 집어 넣기

SQL

INSERT INTO web_site SET name='한겨레';

ORM

site = Site.objects.get_or_create(name='한겨레') #save 메서드 호출 없이도 바로 입력됨

 

ForeignKey, ManyToManyField

SQL

INSERT INTO web_site SET name='PPSS'; #id = 7

INSERT INTO web_article SET subject='뉴스제목', url='http://news.com/12345', date='2017-02-02 12:34:56', site_id=7; #id = 60

INSERT INTO web_category SET name='정치'; #id = 1

INSERT INTO web_category SET name='뉴스'; #id = 7

INSERT INTO web_article_category SET article_id=60, category_id=1; #category = 정치

INSERT INTO web_article_category SET article_id=60, category_id=7; #category = 뉴스

ORM

site, created = Site.objects.get_or_create(name='PPSS')

article = Article(subject='뉴스제목', url='http://news.com', date='2017-02-0 2 12:34:56', site=site)

article.save() #commit

cate1, created = Category.objects.get_or_create(name='정치')

cate2, created = Category.objects.get_or_create(name='뉴스')

article.category.add(cate1)  #relationship 추가

article.category.add(cate2)

article.category.remove(cate2) #relationship 취소

article.category.add(cate2)

 

DELETE

web_article 테이블의 기사를 하나 지우려고 할때, 

SQL에서는 relationshop이 있는 web_article_category의 해당 article_id를 삭제해 주어야 한다.

하지만, ORM에서는 article 객체의 delete 메서드를 이용하면 relationshop에 대한 부분까지 고려해가면서 코딩을 할필요가 없어진다.

SQL

DELETE FROM web_article_category WHERE article_id=2;

DELETE FROM web_article WHERE id=2;

ORM

Article.objects.get(id=2).delete()

 

UPDATE

SQL

UPDATE web_article SET subject = '제목변경' WHERE id=4;

ORM

article = Article.objects.get(id=4)

article.subject = '제목변경'

article.save() #commit

'Back-End > Django' 카테고리의 다른 글

Wagtail Django_extensions, ipython  (0) 2021.11.19
Django Signals  (0) 2021.10.22
Django iamport 적용하기  (0) 2021.10.06
Django Bulma 적용 방법  (0) 2021.08.24
Django template 태그 모음  (0) 2021.08.12

https://yellowdonkey0329.blogspot.com/2018/12/django.html

위의 블로그를 참고하여 만들었다. 

 

공식문서를 확인하고 싶다면

https://docs.iamport.kr/implementation/payment

접속하면 된다.

 

1. iamport 가입

일단 iamport 홈페이지에 접속해서 회원 가입을 한 뒤 로그인을 하고

다음 정보를 기억하자 (메모장에 적어놓으면 된다.)

1. 가맹점 식별코드

2. REST API 키 

3. REST API secret

 

2. billing app 만들기

굳이 app을 만들필요는 없지만 나는 billing app을 만들어 적용을 하였다. 나중에 결제 기능을 수정할 수도 있으니 app을 만들어서 관리하는 것이 좋다고 생각한다. 

 

python manage.py startapp billing을 해주고 settings/base.py에 billing을 등록시켜준다. 그리고 당장은 Django의 view를 사용할 계획이니 urls.py에 billing의 urls을 등록해준다. 

 

base.py
urls.py

3. templates 작성

templates/billing/pay.html

<!doctype html>
<html>
    <head>
        <meta charset="utf-8" />
        <script src="http://code.jquery.com/jquery-1.12.4.min.js" ></script>
        <script src="http://service.iamport.kr/js/iamport.payment-1.1.5.js"></script>
        <script>
            IMP.init('imp');
            let csrftoken = '{{ csrf_token }}'
            IMP.request_pay({
                pg: 'html5_inicis',
                pay_method: 'card',
                merchant_uid: 'merchant_' + new Date().getTime(),
                name: '테스트입니다.',
                amount: 100,
                buyer_email: 'iamport@siot.do',
                buyer_name: 'yellowdonkey',
                buyer_tel: '010-1234-5678',
                buyer_addr: '서울특별시 강남구 삼성동',
                buyer_postcode: '123-456'
            }, function (rsp) {
                if (rsp.success) {
                    //[1] 서버단에서 결제정보 조회를 위해 jQuery ajax로 imp_uid 전달하기
                    jQuery.ajax({
                        url: "/payments/complete/", //cross-domain error가 발생하지 않도록 동일한 도메인으로 전송
                        headers:{'X-CSRFToken':csrftoken},
                        type: 'POST',
                        dataType: 'json',
                        data: {
                            imp_uid: rsp.imp_uid
                            //기타 필요한 데이터가 있으면 추가 전달
                        },
                    }).done(function (data) {
                        //[2] 서버에서 REST API로 결제정보확인 및 서비스루틴이 정상적인 경우
                        alert("ajax done");               
                        console.log("ajax done");
                        if (data.status=='success') {
                            var msg = '결제가 완료되었습니다.';
                            msg += '\n고유ID : ' + rsp.imp_uid;
                            msg += '\n상점 거래ID : ' + rsp.merchant_uid;
                            msg += '\결제 금액 : ' + rsp.paid_amount;
                            msg += '카드 승인번호 : ' + rsp.apply_num;
                            alert(msg);
                            console.log(msg);
                        } else {
                            //[3] 아직 제대로 결제가 되지 않았습니다.
                            //[4] 결제된 금액이 요청한 금액과 달라 결제를 자동취소처리하였습니다.
                            var msg = '아직 제대로 결제가 되지 않았습니다.';
                            alert(msg);
                            console.log(msg);
                        }
                    }).fail(function () {
                        alert("ajax fail");
                        console.log("ajax fail");
                    }).always(function () {
                        alert("ajax always");
                        console.log("ajax always");
                    });
                } else {
                    var msg = '결제에 실패하였습니다.';
                    msg += '에러내용 : ' + rsp.error_msg;
                    alert(msg);
                }
            });
        </script>
    </head>

    <body>
    </body>

</html>

IMP.init에는 아까 저장해놓은 가맹점 식별코드를 넣으면 된다.

 

추후에 템플릿 언어로 관련 정보를 바꿔주면 될 것이다. 결제가 완료되면 ajax을 통해 POST로 json 형태의 데이터를 서버에 보내줄 것이다. 

 

4. urls.py 작성

ajax 부분을 통해 결제가 성공했을 때, 관련정보가 /payments/complete/을 통해 전달되는 것을 확인할 수 있다. 이제 billing app의 urls를 작성해보자.

 

billing/urls.py

from . import views
from django.conf.urls import url
from django.views.generic import TemplateView


urlpatterns = [
    url(r'^payment_test/$', TemplateView.as_view(template_name='billing/pay.html'), name='payment_test'),
    url(r'^payments/complete/$', views.payment_complete, name='payment_complete'),
]

 

5. View.py 작성

이제 POST를 통해 데이터가 왔을 때, 처리하기 위해 view를 정의하면된다. 현재는 블로그의 튜토리얼을 따라하는 과정이라 wagtail의 page가 아닌 view로 해보려고 한다.

 

from django.shortcuts import render
from django.views.decorators.csrf import csrf_exempt
from django.http import HttpResponse
from django.utils.decorators import method_decorator
import json
import requests


# Create your views here.
@method_decorator(csrf_exempt)
def payment_complete(request):

    if request.method == 'POST' and request.is_ajax():
        imp_uid = request.POST.get('imp_uid')

        # // 액세스 토큰(access token) 발급받기
        data = {
            "imp_key": "",
            "imp_secret": ""
        }

        response = requests.post('https://api.iamport.kr/users/getToken', data=data)
        data = response.json()
        my_token = data['response']['access_token']

        #  // imp_uid로 아임포트 서버에서 결제 정보 조회
        headers = {"Authorization": my_token}
        response = requests.get('https://api.iamport.kr/payments/'+imp_uid, data=data, headers = headers)
        data = response.json()

        # // DB에서 결제되어야 하는 금액 조회 const
        order_amount = 100
        amountToBePaid = data['response']['amount']  # 아임포트에서 결제후 실제 결제라고 인지 된 금액
        status = data['response']['status']  # 아임포트에서의 상태

        if order_amount==amountToBePaid:
            # DB에 결제 정보 저장
            # await Orders.findByIdAndUpdate(merchant_uid, { $set: paymentData}); // DB에
            if status == 'ready':
                # DB에 가상계좌 발급정보 저장
                return HttpResponse(json.dumps({'status': "vbankIssued", 'message': "가상계좌 발급 성공"}),
                                    content_type="application/json")

            elif status=='paid':
                return HttpResponse(json.dumps({'status': "success", 'message': "일반 결제 성공"}),
                                    content_type="application/json")

            else:
                pass

        else:
            return HttpResponse(json.dumps({'status': "forgery", 'message': "위조된 결제시도"}), content_type="application/json")
    else:
        return render('payment_complete.html', locals())

처음에 저장해놓은 key와 secret을 넣으면 된다.

view에서 하는 일은 html을 통해 결제가 될 때, 결제 정보를 받아서 imp_uid를 통해 iamport 서버에서 조회하여 확인하는 과정을 거친다. 

 

'Back-End > Django' 카테고리의 다른 글

Django Signals  (0) 2021.10.22
Django ORM  (0) 2021.10.21
Django Bulma 적용 방법  (0) 2021.08.24
Django template 태그 모음  (0) 2021.08.12
Django Admin Custom 3(간단한 Custom 연습)  (0) 2021.08.09

Django에서 Bulma를 적용하는 방법에 대해서 소개하려고 한다.

Bulma는 Bootstrap대신 쓸 수 있는 디자인 기능이다. 개인적인 생각으로는 좀 더 이쁜 것 같다. 

https://bulma.io/

 

Bulma: Free, open source, and modern CSS framework based on Flexbox

Bulma is a free, open source CSS framework based on Flexbox and built with Sass. It's 100% responsive, fully modular, and available for free.

bulma.io

자세한 내용은 여기서 확인 할 수 있다. 

 

설치 방법은 CDM을 사용하여 사용할 수 있으나 Customize하기를 원하므로 Customize 방법으로 적어보도록 하겠다. 

총 3가지 방법을 소개하고 있는데 그중 With node-sass 방법으로 진행해보도록 하겠다.

 

원문이 보고 싶다면

https://bulma.io/documentation/customize/with-node-sass/

 

1.폴더 생성, 시작

 

django static폴더에 mybulma라는 폴더를 만들고 폴더로 이동해준다. 

 

cd static
mkdir mybulma
cd mybulma
npm init

 

입력하면 여러가지를 입력하라고 나오는데 전부 enter만 눌러주고 entry point가 나왔을 때 sass/mystyles.scss 

을 입력해주자. 

그러면 mybulma 폴더 안에 package.json 가 생긴 것을 확인 할 수 있다.

 

 

2. 필요 모듈 설치

 

필요 모듈 설치해준다.

npm install node-sass --save-dev
npm install bulma --save-dev

 

 

 

3. SCSS파일 생성

sass폴더를 만들어주고 안에다가 mystyles.scss 파일을 만들어준다.

static/mybulma/sass/mystyles.scss

@charset "utf-8";
@import "../node_modules/bulma/bulma.sass";

 

 

테스트할 html 파일에 다음 내용을 적는다. 

templates/test.html

{% load static %}
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>My custom Bulma website</title>
    <link rel="stylesheet" href="{% static 'css/mystyles.css' %}">
  </head>
  <body>
     <h1 class="title">
        Bulma
      </h1>

      <p class="subtitle">
        Modern CSS framework based on <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Flexible_Box_Layout/Basic_Concepts_of_Flexbox">Flexbox</a>
      </p>

      <div class="field">
        <div class="control">
          <input class="input" type="text" placeholder="Input">
        </div>
      </div>

      <div class="field">
        <p class="control">
          <span class="select">
            <select>
              <option>Select dropdown</option>
            </select>
          </span>
        </p>
      </div>

      <div class="buttons">
        <a class="button is-primary">Primary</a>
        <a class="button is-link">Link</a>
      </div>
  </body>
</html>

 

지금은 html 파일을 실행해보면 오류가 날 것이다. 

아까 생성된 package.json 파일에 다음 코드를 수정해주자. 

 

 

 

4. JSON파일 수정

package.json

"scripts": {
  "css-build": "node-sass --omit-source-map-url sass/mystyles.scss css/mystyles.css",
  "css-watch": "npm run css-build -- --watch",
  "start": "npm run css-watch"
}

 

 

 

5. CSS-BUILD

터미널에 다음과 같이 입력해주자 

npm run css-build

 

 

 

Rendering Complete, saving .css file...
Wrote CSS to /path/to/mybulma/css/mystyles.css

여기까지 하면 기본 bulma setting은 완료되었다. html 페이지를 확인해보면 적용된 것을 볼 수 있다. 

 

 

 

추가) Customize

 

1) 

다음 패키지들을 설치해주자.

pip install libsass django-compressor django-sass-processor

 

 

 

2)

settings.py에 다음과 같이 추가한다. 

myproject/settings.py

INSTALLED_APPS = [
    ...
    'sass_processor',
    ...
]
SASS_PROCESSOR_ENABLED = True
SASS_PROCESSOR_ROOT = os.path.join(BASE_DIR, 폴더명(있을 경우), 'static')
SASS_PROCESSOR_ROOT = os.path.join(BASE_DIR,'static') # 없으면
# SASS_OUTPUT_STYLE = 'compact' # 추가 사항 
# SASS_PRECISION = 8 # 부트스트랩 sass일 경우

 

 

 

3)

html에 다음과 같이 적어주자.

 

{% load sass_tags %}

<link href="{% sass_src 'mybulma/sass/mystyles.scss' %}" rel="stylesheet" type="text/css" />

Customize 준비가 완료되었다. 

 

 

 

4)

setting은 끝났으니 직접 사용해보자. 

mystyles.scss 내용을 다음과 같이 바꿔주자. 

 

mybulma/sass/mystyles.scss

@charset "utf-8";

// Import a Google Font
@import url('https://fonts.googleapis.com/css?family=Nunito:400,700');

// Set your brand colors
$purple: #8A4D76;
$pink: #FA7C91;
$brown: #757763;
$beige-light: #D0D1CD;
$beige-lighter: #EFF0EB;

// Update Bulma's global variables
$family-sans-serif: "Nunito", sans-serif;
$grey-dark: $brown;
$grey-light: $beige-light;
$primary: $purple;
$link: $pink;
$widescreen-enabled: false;
$fullhd-enabled: false;

// Update some of Bulma's component variables
$body-background-color: $beige-lighter;
$control-border-width: 2px;
$input-border-color: transparent;
$input-shadow: none;

// Import only what you need from Bulma
@import "../node_modules/bulma/sass/utilities/_all.sass";
@import "../node_modules/bulma/sass/base/_all.sass";
@import "../node_modules/bulma/sass/elements/button.sass";
@import "../node_modules/bulma/sass/elements/container.sass";
@import "../node_modules/bulma/sass/elements/title.sass";
@import "../node_modules/bulma/sass/form/_all.sass";
@import "../node_modules/bulma/sass/components/navbar.sass";
@import "../node_modules/bulma/sass/layout/hero.sass";
@import "../node_modules/bulma/sass/layout/section.sass";

 

 

5) 

이제 기존 mystyles.css와 mystyles.scss를 Mapping 시켜줘야한다. 

 

 

'Back-End > Django' 카테고리의 다른 글

Django ORM  (0) 2021.10.21
Django iamport 적용하기  (0) 2021.10.06
Django template 태그 모음  (0) 2021.08.12
Django Admin Custom 3(간단한 Custom 연습)  (0) 2021.08.09
Django Admin Custom 2(templates 구조 분석)  (0) 2021.08.09

+ Recent posts