PyYAML+Jinja2를 사용하여 다양한 질문집 만들기

11321 단어 Python3Python
교육용으로 사용되는지는 물론이고 YAML에서 문제집을 일으킨 파이썬 스크립트를 썼다.(템플릿 출력만 해당)

하고 싶은 일

  • 좋은 느낌으로 출력하고 싶은데 메일로 보내고 싶어요.
  • HTML 파일을 통해 보냅니다.서류 수납.
  • (CSS 프레임워크 또는 JavaScript의 라이브러리는 CDN이 공개한 라이브러리를 이용한다)
  • 대답을 숨기고 싶다
  • 템플릿으로 나눈다.HTML이기 때문에 JavaScript가 노력하는 방법도 있고...
  • 문제 관리에 DB를 사용하고 싶지 않음
  • yaml이면 됩니다
  • 이루어지다


    이렇게 사용할 프로그램 라이브러리를 결정했습니다.
  • yaml로 문제를 정의할 수 있다면 쉬울 거예요
  • 앙자2는 ansible에서도 사용해 봤기 때문에 익숙하고 야임에서 읽은 결과를 그대로 흘릴 수 있다
  • markdown에yaml문제를 쓰면 비교적 편리합니다.문득 생각나다
  • HTML인 경우 JavaScript의 highlightjs에 구문 강조를 추가합니다.문득 생각나다
  • 입력 데이터 예


    큰 프로젝트와 문제 두 단계를 가정해 보세요.
    traning.yml
    ---
    - title: ディレクトリの移動・操作
      quizzes:
        - question: |-
            現在の作業中のディレクトリ(ワーキングディレクトリ)のパスを表示するコマンドは何か
          answer: |-
            ~~~{.bash}
            pwd
            ~~~
        - question: |-
            現在のディレクトリから`/tmp`に移動する操作を書きなさい
          answer: |-
            ~~~{.bash}
            cd /tmp
            ~~~
    
    |-를 사용하면 여러 칸을 사용할 수 있습니다.끝에서 행 분리를 삭제합니다.

    코드 생성


    generater.py
    import yaml 
    import markdown
    import jinja2
    import sys, io
    
    # always utf-8 encoding. 
    sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
    
    # markdown extension
    MARKDOWN_EXTENSIONS = ['markdown.extensions.extra']
    
    # add filter (markdown)
    loader = jinja2.FileSystemLoader('./templates')
    env = jinja2.Environment(autoescape=True, loader=loader)
    env.filters['markdown'] = lambda text: markdown.markdown(text, MARKDOWN_EXTENSIONS)
    
    # render
    tranings = yaml.load(sys.stdin.buffer)
    template : jinja2.Template = env.get_template("traning.j2")
    html = template.render(tranings = tranings)
    
    # output
    print(html)
    
    마크다운의 변환 처리를 진자2 필터로 쓰는 데 신경을 썼다.

    템플릿 예


    답변을 숨기고 싶을 때는 <div class="quiz-answer"> 근처를 삭제하면 된다.
    templates/tranings.j2
    <!DOCTYPE html>
    
    <head>
        <meta charset="utf-8">
        <title>とれーにんぐ</title>
        <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/default.min.css">
        <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/highlight.min.js"></script>
        <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.1/css/bootstrap.min.css" integrity="sha384-WskhaSGFgHYWDcbwN70/dfYBj47jz9qbsMId/iRN3ewGhXQFZCSftd1LZCfmhktB"
            crossorigin="anonymous">
        <style>
        .quiz-content{
            margin-left: 1em;
        }
        .quiz-answer::before{
            content: "A."
        }
        </style>
        <script>
        window.addEventListener('load', function(){
            Array.from(document.querySelectorAll('pre code')).forEach(function(el){
                hljs.highlightBlock(el);
            })
        })
        </script>
    </head>
    
    <body>
        <div class="container-fluid">
            <section>
                <ul>
                    {% for traning in tranings %} {% set traning_loop = loop %}
                    <li>
                        <div><a href="#{{traning.title}}">{{ traning_loop.index }}.{{traning.title}}</a></div>
                        <ul>
                        {% for quiz in traning.quizzes %}
                        <li><a href="#quiz-{{ traning_loop.index }}-{{ loop.index }}">{{ traning_loop.index }}.{{ loop.index }}. {{quiz.question}}</a></li>
                        {% endfor %}
                    </ul>
                    </li>
                    {% endfor %}
                </ul>
    
            </section>
    
            {% for traning in tranings %} {% set traning_loop = loop %}
            <section class="traning">
                <h2 id="{{ traning.title }}">{{ traning_loop.index }}. {{ traning.title }}</h2>
                {% for quiz in traning.quizzes %}
                <div class="quiz">
                    <h3 id="quiz-{{ traning_loop.index }}-{{ loop.index }}" class="quiz-no">Q. {{ traning_loop.index }}-{{ loop.index }}.</h3>
                    <div class="quiz-content">
                        <div class="quiz-question">
                            {{ quiz.question | markdown | safe }}
                        </div>
                        <div class="quiz-answer">
                            {{ quiz.answer | markdown | safe }}
                        </div>
                    </div>
                </div>
                {% endfor %}
            </section>
            {% endfor %}
        </div>
    </body>
    

    사용 예

    python generator.py < traning.yml > output.html
    

    출력 예



    이렇게까지 했지만 문제가 생겨 귀찮아서 사용할지 모르겠다.

    좋은 웹페이지 즐겨찾기