[쇼피파이] 쇼피파이 테마 2.0 개발을 위한 구조분석 및 이해

Computer 관심/쇼피파이|2021. 12. 26. 11:57
반응형

구성

쇼피파이의 큰 구조는 아래와 같다.

- 아나운스먼트 바

- 헤더

- 템플레이트

- 푸터

 

레이아웃

처음에 실행되는 파일인 theme.liquid 파일을 보면 아래와 같이 {% section %}을 통해 아나운스먼트바, 헤더, 푸터를 불러온다.

{{content_for_header}} liquid 태그는 html <header>태그 사에이 들어가서 스크립트를 불러들이고

{{content_for_layout}} liquid 태그는 는 페이지에 알맞는 템플릿을 불러들이는 역할을 한다.

 

예를 들면 index페이지에선 index.json템플릿을 불러오고 카트페이지에선 cart.json페이지를 불러오는 식으로 말이다.

 

 

theme.liquid가 메인 파일이며 CDN을 설치하고 싶으면 여기 헤더 안에 넣으면 된다.

예를 들면 부트스트랩 설치하고 싶으면 아래의 코드를 layout > theme <head></head>에 사이에 넣는다.

 

<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>

 

 

 

템플레이트

이중 템플레이트는 쇼피파이에 필요한 페이지를 구성하는 JSON/liquid 파일을 말한다. 쇼피파이 쇼핑몰이 필요한 페이지들의 파일 이름이 아래 사진에 보듯 이미 정의가 되어있어서 자신이 만들 페이지명을 확인 하고 만들면 된다.

 

 

Json file과 liquid file 중 쇼피파이 2.0에서는 템플레이트를 JSON으로 만들어 템플레이트 내부의 섹션들을 자유롭게 배치 할 수있도록 한다.

 

섹션 이동 예시

 

아래는 기본적인 템플레이트의 Json파일의 구조이다. 

 

{
"sections":{
    section_name: {
        "type":"",
        "blocks":{
            block_name:{
            "type":"",
            "settings":{}
        },
        "block_order":[],
        "settings":{}
    },
"order":[]
}

 

새로운 섹션을 추가하면  코드에서도  sections 오브젝트에 섹션이 추가 된다. 또한 order에도 섹션의 배치 순서대로 섹션이 배열에 추가된다.

 

 

섹션

아래 사진 처럼 Rich text, collection list 등  template에 넣을 수 있는 요소를 섹션이라 한다. 이러한 섹션은 사용자가 커스터마이즈 하게 제작 할 수도 있다.

섹션들

 

다시 한번 코드를 보면 섹션은 아래처럼 섹션의 이름(사용자가 만들수있음), type, settings, blocks, block_order로 구성되 있으며 "type" 은 section의 이름을 넣으면 되고 "order"은 사용자가 정의한 섹션의 이름을 넣어서 순서를 정한다.

 

{
"sections":{
    section_name: {
        "type":"",
        "blocks":{
            block_name:{
            "type":"",
            "settings":{}
        },
        "block_order":[],
        "settings":{}
    },
"order":[]
}

섹션의 속성들

  • id: refers to the Liquid variable being defined 
  • type: defines the kind of output we are creating
  • label: provides context displayed on the theme editor
  • default: assigns a default value

 

.json파일을 만들때 섹션이 하나라도 등록되어 있어야 다른 섹션을 관리자 페이지에서 넣을 수 있었다. 즉, template이라는 곳에 하나의 섹션은 존재해야 한다. 어떤 유튜버는 main이라고 이름을 정하고 하나의 섹션을 만들어서 넣음. 

 

관리자 페이지에서도 템플릿에 있는 모든 섹션은 지울 수 없다. 적어도 한개는 색션 한개는 있어야 한다. 섹션을 클릭을 해도 지우는 버튼인 remove section이 나오지 않는다.

 

 

 

블록

블럭 역시 섹션처럼 배열의 순서를 바꿈으로써 블록의 순서를 바꿀 수 있는게 특징이다.

 

유용한 자료

 

쇼피파이 테마 구조

https://www.shopify.com/partners/blog/how-to-create-your-first-shopify-theme-section

 

리퀴드

https://shopify.github.io/liquid/basics/introduction/

 

뷰 + 쇼피파이2.0 + tailwindcss를 활용한 스타터 theme :아직 안 써봤지만 좋아보임

https://themelab.uicrooks.com/

 

앱에서 theme에 적용

https://weeklyhow.com/shopify-app-script-tag/

'Computer 관심 > 쇼피파이' 카테고리의 다른 글

Theme app extensions  (0) 2023.01.09
쇼피파이 Theme 개발 시작하기  (0) 2023.01.03

댓글()

firebase rule

Computer 관심/이것저것|2021. 12. 23. 14:50
반응형

https://seizemymoment.tistory.com/11

 

[Firebase] 파이어베이스 보안규칙 (Firestore Security Rules ) 작성 방법

파이어베이스에서 제공하는 보안규칙은 코드가 간단하며 보안규칙을 위해 인프라를 관리하거나 복잡한 서버측 인증 및 인증 코드를 작성할 필요 없다. 하지만 보안규칙을 적용하지 않으면 파

seizemymoment.tistory.com

 

https://dev.to/jamalmoir/firestore-rules-examples-must-know-patterns-to-secure-your-data-bm1

 

Firestore Rules Examples – Must-Know Patterns To Secure Your Data

This post is part of a post originally posted on my blog where I write about coding, software develop...

dev.to

https://cloud.google.com/firestore/docs/security/get-started#auth-required

 

 

 

 

allow write: if request.auth.uid == resource.data.author;

request.auth.uid는 파이어베이스스토어에서 인증된 id며, resource.data.author은 사용자가 author 필드에 넣은 값이다.
즉 id가 author 필드에 있는 값과 같은 것만 alow 된다.

request.resource.data.author로 하게 되면 디비가 아니라 request한 현재의 데이터 값을 사용한다.

 

ex

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /driverList/{driver} {
      allow read: if true;
      allow write: if request.auth.uid != null;
    }
     match /hotPlace/{place} {
      allow read: if true;
      allow write: if request.auth.uid != null;
    }
  }
}

댓글()

[피벗테이블 실전 활용]엑셀로 업체별 영업 트래킹(추적) 쉽게 하기

Computer 관심/Excel & VBA|2021. 12. 18. 16:59
반응형

얼마전 부터 기존에 하고있던 관리 업무에서 소싱영업까지 업무가 추가가 되었다. 영업에 대해는 잘 모르지만 영업관련 부서를 바로 옆에서 지켜본 결과 프로그램 없이 엑셀로 트랙킹을 하는 것은 쉽지 않았다. 

또 나 역시 제품 클레임 제품들을 트래킹해야 했는데 트래킹 프로그래밍을 만드는건 귀찮음에 미루고 미뤘다.

 

일단 결과 화면부터 보자

결과화면은 위와 같이 업체별로 진행상황이 나오도록 할 것이다.

 

 

일단 아주 원시적이지만 직관적으로 트래킹을 하는 경우를 보자

이방법은 쉽게 느껴질 수 있지만 이건 정말 비효율 적이다. 엑셀을 처음 하는 사람들은 아마 이렇게 할지도 모른다. (내가 그랬다..)

처음엔 쉽게 느껴질 수 있지만 나중가면 업체를 찾는거 조차 어렵고 정보가 좌우로 적혀 있어 보기가 많이 불편하다. 또한 상세정보 들이 길어지면 가독성은 더 떨어지게 된다.

 

그러면 이것을 어떻게 해결해야 하는가?

 

 

 

1. DB 형식으로 엑셀을 만든다.

날짜, 업체명, 진행상황, 상세로 칼럼을 나누었고 새로운 상황이 생길때 마다 새로운 열을 추가 시켰다.

이거만 보면 "에이 뭐야 이거 보기 더 어려워 졌잖아." 생각할 지도 모른다. 더 많은 정보가 들어갔고 입력하기 편하지만 시간상으로만 정렬이 되어있을 뿐 업체들이 섞여 있어서 한눈에 파악하기 어렵다. 

 

물론 이때 정렬 기능을 사용하여 이 데이타를 업체별로 정렬하여 보여지게 할 수도 있지만 그렇게하면 입력 할때마다 다시 날짜별로 정렬을 바꾸고 상황을 보고 싶을 또 정렬로 업체별로 수정해야 하는 번거로움이 있다.

 

 

 

 

2. 이 데이터를 바탕으로 피벗테이블을 만든다.

해결책은 피벗테이블을 만드는 것이다. 

 

1) 데이터가 지속적으로 입력되기 때문에 테이블로 만든다.

이렇게 테이블을 만들면 새로운 열을 입력할 때 마다. 자동으로 테이블의 범위가 변경된다.

 

2) 피벗테이블의 범위를 테이블로 선택한다.

3) 보여질 정보들을 row에다 넣는다.

 업체명 별로 분류가 되고 내부에 날짜가 있고 그 날짜에 대한 진행상황과 상세내용이 나와있지만 밑으로 주주룩 나와서 보기가 어렵다.

 

4) 피벗테이블 디자인 바꾸기

레포트 레이아웃에 들어가서 show in tabular form 을 클릭한다. 

단지 저 버튼을 클릭했을 뿐인데

위와 같이 보기 더욱 쉽게 보여진다.

이건 계산 관련 피봇이 아니기 때문에 grand totals 버튼을 클릭해서 안보이게 바꿀 수 있다.

 

5)피봇 스타일 바꾸기

이렇게 하면 업체별로 눈에 더 쉽게 들어오게 바꿀 수 있다.

 

 

 

3. 데이터 추가하기

이후 정보를 더 추가하게 되면

 

 

피봇테이블에 아직 데이터가 변경된게 적용 안됬는데

데이터를 리프레쉬하면

아래와 같이 추가가 된것을 볼 수 있다.

 

위의 방식대로 하면 영업뿐만이 아니라 재품별 클레임 상황도 쉽게 관리가 가능하다. 

 

+ 슬라이더 추가

 

아래와 쉽게 같이 업체 A, B만 선택하여 볼 수 있다.

 

댓글()

스벨트 파이어베이스 로그인 하기

Computer 관심/Svelte|2021. 11. 11. 16:58
반응형

파이어베이스 로그인 구현이 새롭게 바뀌면서 기존에 있던 튜토리얼과 예제들이 작동되지 않아서 약간 애를 먹었다.

그러므로 파이어베이스 로그인을 구현할때 예전의 예제를 보기보단 파이어베이스 사이트에서 새로운 버전으로 보는것이 좋다.

 

스벨트에서 구현은 다음과 같이 했다. 맞는지 아닌지는 모르겠지만... 물론 추가로 수정해야 할 부분들이 있다.

 

 

 

로그인 하기전

 

로그인 버튼 클릭했을때 팝업

 

 

파이어베이스로 방금 가입된 유저

 

 

로그인 되면 보인는 화면

 

1. 파이어베이스 사이트에 들어간 뒤 새로운 프로젝트를 만든다.

 

2. config 정보를 복사

 

3. __layout.svelte 파일에서 파이어베이스 init를 한다.

import { initializeApp } from 'firebase/app';
import { getAuth, onAuthStateChanged } from "firebase/auth";
import {isLogin} from '../store'


onMount(()=>{
    const firebaseConfig = {
        #config들어갈 정보 복사
        };
        // Initialize Firebase
        initializeApp(firebaseConfig);
        
        
        // 로그인 정보가 체인지가 될때 실행되는 리스너 함수
        const auth = getAuth();
        onAuthStateChanged(auth, (user) => {
        if (user) {
            // User is signed in, see docs for a list of available properties
            // https://firebase.google.com/docs/reference/js/firebase.User
            const uid = user.uid;
            console.log(user)
            $isLogin = true
        } else {
            // User is signed out
            // ...
        }
   });
})

 

4. 스토어에 등록한 isLogin 변수를 사용하여 로그인상태를 변경함

//store.js

import { writable } from 'svelte/store';
export const isLogin = writable(false);

 

5. 로그인로그아웃 필요한 페이지에서 구글로그인 로그아웃 함수 사용

import { getAuth, signInWithPopup, GoogleAuthProvider, signOut } from "firebase/auth";
import {isLogin} from '../store';

  async function loginWithGoogle() {
    const auth = getAuth();
    const provider = new GoogleAuthProvider();
    signInWithPopup(auth, provider)
    .then((result) => {
        // This gives you a Google Access Token. You can use it to access the Google API.
        const credential = GoogleAuthProvider.credentialFromResult(result);
        const token = credential.accessToken;
        // The signed-in user info.
        const user = result.user;
       console.log(user)
    }).catch((error) => {
        // Handle Errors here.
        const errorCode = error.code;
        const errorMessage = error.message;
        // The email of the user's account used.
        const email = error.email;
        // The AuthCredential type that was used.
        const credential = GoogleAuthProvider.credentialFromError(error);
        // ...
    });
  }
  
 async function signOutGoogle(){
    const auth = getAuth();
    console.log(auth)
    signOut(auth).then(() => {
        $isLogin = false
        }).catch((error) => {
        // An error happened.
        });
   }

댓글()

판다스와 플라스크 sqlAlchemy 연결하기

Computer 관심/Pandas|2021. 10. 18. 19:20
반응형

판다스에서 DB로

 

https://stackoverflow.com/questions/43571991/pandas-df-to-database-using-flask-sqlalchemy

 

Pandas df to database using flask-sqlalchemy

I'm trying to insert a pandas dataframe into a mysql database. I am using flask-sqlalchemy. I have created this table: class Client_Details(db.Model): __tablename__ = "client_history"

stackoverflow.com

 

DB에서 판다스로

 

https://stackoverflow.com/questions/29525808/sqlalchemy-orm-conversion-to-pandas-dataframe

 

SQLAlchemy ORM conversion to pandas DataFrame

Is there a solution converting a SQLAlchemy to a pandas DataFrame? Pandas has the capability to use pandas.read_sql but this requires use of raw SQL. I have two reasons for wan...

stackoverflow.com

 

댓글()

sveltekit에서 프린팅 하는 노하우 (scoped css)

Computer 관심/Svelte|2021. 10. 15. 20:41
반응형

웹으로 회사전산 시스템을 만들때 필연적으로 문서를 프린팅을 해야하는 기능이 필요하다.

스벨트킷에서 프린팅 기능을 만들때 필요한 CSS태그를 알아보자

 

내가 원했던 방법은 특정 요소만 프린팅을 하고 싶었다. 

div가 두개가 있는데 하나는 인풋용 하나는 출력용 프리뷰인 셈이다.

또한 출력할 화면에는 내가 원하지 않는 Navigation bar가 들어있었다.

 

 

인터넷을 찾아보니 아래와 같은 방법이 있었다.

function printDiv(divName) {
     var printContents = document.getElementById(divName).innerHTML;
     var originalContents = document.body.innerHTML;

     document.body.innerHTML = printContents;

     window.print();

     document.body.innerHTML = originalContents;
}

즉, 출력할 요소만 html로 만든뒤 출력 후 복사해낸 원래의 화면을 넣어주는 것이다. 프린팅은 되지만 원래 화면을 넣어줬을때 더 이상 스벨트킷이 아니게 된다. 

 

그래서 다른 방법을 적용하기로 하였고 이것은 CSS를 사용하는 방법이다.

프린팅 시 CSS에서 원하는 요소만 visible을 해주고 원하지 않는 요소는 display none을 해주는 방법이다. 여기에도 작은 문제가 있었다. layout에 추가한 navigation 까지 출력이 되는 것이였다. 어떻게 해결해야할지 몰라서 아는 방법으로 임시방편으로 링크를 통해 문서를 출력하는 페이지로 가게 만들고 그 스벨트 폴더에 __layout.reset.svelte를 추가해서 그페이지만 레이아웃 자체를 초기화 시켜버렸다.

  @media print { 
  
      @page {
          size: a4;
      }     
      #main_page{
        display: none;
      }
      #print-area {
        margin: auto;
        width: 220mm;
        min-height: 300mm;
        visibility: visible;
      }
   
     
  }

 

그렇게 쓰고 있다가 문제는 결국 CSS가 적용되는 scope의 문제 였다는게 떠올랐다. (문제가 뭔지 모르면 뭘 구글링 해야할지도 모른다.) 문제를 정확하게 알게 되니 답은 이미 나와있었다.

 

navigation 요소에 id를 만들고 css에 :global(#nav){} 를 추가한다. 여기서 :global()을 사용시 모든 컴포넌트의 # . 요소명이 있으면 CSS에 적용이 된다.

이 방법을 통해 컴포넌트파일 이외의 영역의 스타일을 변경하였다.

이래저래 검색하다가 찾게된 :not(요소명){} 저 요소명 빼고 다 스타일 적용도 유용하게 쓰일거 같다.

 

주의할것은 부모요소를 display: none해버리면 정작 출력하려는 자식요소도 안보여지게 되므로 프린트 하지 않을 형제요소와 다른 특정요소를 display: none하는 방법을 사용한다.  

 

  @media print { 
  
      @page {
          size: a4;
      }
      /* 추가 */
      :global(#nav){
        display: none;
      }
      #main_page{
        display: none;
      }
      #print-area {
        margin: auto;
        width: 220mm;
        min-height: 300mm;
        visibility: visible;
      }
   
     
  }

 

댓글()

pythonanywhere에서 DB 마이그레이션(migration) 하기

Computer 관심/Flask|2021. 10. 9. 23:34
반응형

https://flask-migrate.readthedocs.io/

 

 

로컬 마이그레이션 

set FLASK_APP=main.py

 

1. 마이그레이션 폴더를 추가함

flask db init

2.  마이그레이션 파일 생성

(생성된 파일을 잘 봐야 한다고 함. 왜냐면 테이블 이름이나 칼럼 이름을 바꿀경우 수동으로 수정 필요)

$ flask db migrate -m "Initial migration."

3. 마이그레이션 적용

$ flask db upgrade

 

깃 커밋

1. 깃 커밋 후 푸쉬

 

파이썬 애니웨어에 적용

1. 파이썬 애니웨어에서 git pull (이를통해 적용을 시킬 파일까지 불러 올 수 있다.)

2. 파이선 애니웨어에서도 마이그레이션 적용

$ flask db upgrade

로컬에서 db를 수정한뒤 flask db upgrade명령어를 적어서 pythonanywhere에 적용한 모습

※ 호스팅한 서버의 마이그레이션 파일과 개발서버의 마이그레이션 파일이 같으면 문제가 날 가능성이 적을 겉이다.

 

 

이렇게 마이그레이션이 작동이 안되는 경우 해결법 

해결법 1. 마이그레이션 관련 파일 삭제 후 초기화

 

로컬

1. 다운그레이드로 디비를 되돌림

 

2. migration 폴더를 삭제 +  alembic_version 테이블을 제거

3. 마이그레이션 폴더를 추가함

flask db init

4.  마이그레이션 파일 생성

(생성된 파일을 잘 봐야 한다고 함. 왜냐면 테이블 이름이나 칼럼 이름을 바꿀경우 수동으로 수정 필요)

$ flask db migrate -m "Initial migration."

5. 마이그레이션 적용

$ flask db upgrade

 

6. git push

 

적용서버

1. alembic_version테이블 제거

2. 깃 풀로 새로 만들어진 마이그레이션 파일을 다시 받아옴

3. 마이그레이션 파일 적용

export FLASK_APP=main.py

 

$ flask db upgrade

 

 

 

해결법 2.

서버와 같게 만들어줌 - python anywhere에서 bash가 아닌 mysql을 클릭

 

1. alembic_version을 업그레이드 이전 버전으로 맞춤. 

 

2. 만약 alembic_version테이블 자체가 없으면 sql 쿼리를 통해 테이블 생성을 함

 

 

-- 테이블 만들기

CREATE TABLE alembic_version (
    version_num varchar(32) NOT NULL PRIMARY KEY
);

 

-- 테이블에 데이타 변경하기

UPDATE alembic_version SET version_num = '52220a6a6d76' WHERE version_num = 'c2d3b91fd96e';

 

-- 마이그레이션에 엉뚱한 쿼리가 있으면 변경해 줌

 

$ flask db upgrade

 

 

해결법 3. 마이그레이션을 안쓰는법

sql문을 써서 직접 실제 서버의 테이블을 업데이트를 한뒤 ( ALTER TABLE 아래 링크는 sql로 수정하는 법)

https://stackoverflow.com/questions/92082/add-a-column-with-a-default-value-to-an-existing-table-in-sql-server

※ 유용한 쿼리 show tables;, describe <table name>;

 

그냥 git으로 파일을 push 한뒤 sql로 테이블 구조를 바꾸고 alembic_version 테이블에 값을 로컬에 있는 것과 똑같이 만들어줌

 

 

UPDATE alembic_version SET version_num = '52220a6a6d76' WHERE version_num = 'c2d3b91fd96e';

 

 

 

- nullable= false 인 필드를 추가 시켜야 하는 경우

https://medium.com/the-andela-way/alembic-how-to-add-a-non-nullable-field-to-a-populated-table-998554003134

 

Alembic: How to Add a Non-Nullable Field to a Populated Table

It is quite easy to add a non-nullable field to an empty table. Any migration tool, including Alembic, can automatically generate a…

medium.com

간단하게 말하자면 이건 자동이 아니다. ㅠㅠ 직접 마이그레이션 파일을 수정하는 것이다.

nullable = false로 바로 했을 경우 기존에 있던 row들에 값이 없기 때문에 

먼저 nullable = true로 만들어준 뒤 기존 필드에 값을 넣고 그걸 nullable =false로 바꾸어주는 방법이다.

 

 

-nullable = false면서 unique면...

nullable을 true로 바꾸고 기존에 값에 unique한 값 (row의 index나 uid) 을 넣어준 뒤

nullable을 false로 바꾸면 될 것이다. 

 

 

-메이저 체인지는 인식하는데(삭제, 생성) 값의 크기가 변경됬을때 작동 안하면

 

compare_type = True 추가해줘야함 (어디에 추가하는지 중요) 링크 참조

https://stackoverflow.com/questions/58532518/why-flask-migrations-does-not-detect-a-fields-length-change

 

 

- 만약 개발서버에서는 sqlite를 쓰고 실서버를 mysql을 쓰는 경우 엄청 고생하게 됨.

 

 

 

 

 

댓글()

sqlalchemy 사용시 db object를 jason으로 바꾸는 방법

Computer 관심/Flask|2021. 9. 24. 21:31
반응형

디비에서 얻어온 객체는 딕셔너리 형태로 바꿔줘야 한다. 

여러가지 방법을 시도했는데 가장 쉬운 방법은 아래와 같다.

 

 

플러터에서 객체를 json을 바꾸는 방법과 비슷하다.

디비모델에 as_dict함수를 추가한다.

class User(db.Model):
   def as_dict(self):
       return {c.name: getattr(self, c.name) for c in self.__table__.columns}

그리고 바꾸려는 객체.as_dict()를 하면 response를 할 수 있다.

 

이 방법을 안쓰면 하나하나 {'name':instant.value}와 같은 방식으로 딕셔너리를 만들어서 전달해야한다.

댓글()