【问题标题】:How to make Images/PDF of Timetable using Python如何使用 Python 制作时间表的图像/PDF
【发布时间】:2021-12-10 14:30:33
【问题描述】:

我正在解决一个时间表安排问题,并希望以 PDF 或一组图像的形式打印出最终输出。我有多个部分,每个部分都有自己的时间表。

我为每个部分创建了一个二维数组。该数组大小为 5 x 5(5 天,每天有 5 个五个插槽),数组的每个索引代表一个讲座插槽。现在,这个二维数组包含该特定部分时间表中每门课程的讲座。示例输出如下,(这是一个字典,每个键都是一个部分。每个键的值是一个二维数组

CS-3B :  [['', '', 'DS ', '', 'COaAL '], ['', 'COaAL ', '', 'DS ', 'OOP '], ['DS-L ', 'DS-L ', 'OOP-L ', 'OOP-L ', 'FoM '], ['COaAL-L ', 'COaAL-L ', 'OOP ', '', ''], ['', 'FoM ', 'DE ', '', 'DE ']]
SE-3A :  [['', 'OOP-L ', 'OOP-L ', '', 'SRE '], ['SRE ', 'OOP ', 'DS-L ', 'DS-L ', ''], ['', 'DS ', '', '', 'MM '], ['DS ', 'MM ', '', 'LA ', ''], ['OOP ', 'HCI ', '', 'LA ', 'HCI ']]
CS-7F :  [['', '', '', '', ''], ['RSaG ', '', '', '', ''], ['ST ', '', 'RSaG ', '', ''], ['', '', '', '', ''], ['', 'ST ', '', '', '']]
CS-1C :  [['IS ', 'ECaC-L ', 'ECaC-L ', '', 'PF '], ['ECaC ', 'PF-L ', 'PF-L ', 'ECaC-L ', 'ECaC-L '], ['DLD ', 'ECaC ', '', 'PF ', 'ItIaCT '], ['DLD-L ', 'DLD-L ', 'IS ', 'LA ', ''], ['ECaC ', 'ECaC ', 'ItIaCT ', 'DLD ', 'LA ']]
CS-1D :  [['PF-L ', 'PF-L ', 'ECaC-L ', 'ItIaCT ECaC-L ', 'ItIaCT '], ['IS ', 'AP ', 'ECaC-L ', 'ECaC-L ', ''], ['PF ', 'PF ', '', 'ECaC ', ''], ['CaAG ', 'ECaC ', 'ECaC ', '', 'IS '], ['', 'CaAG ', '', 'ECaC ', 'AP ']]
CS-7A :  [['', 'DM ', '', 'PPiI ', 'DS '], ['AI-L ', 'AI-L ', '', 'AI ', 'IS '], ['', '', 'DS ', '', ''], ['SE ', 'SE ', '', 'PPiI ', ''], ['', 'AI ', 'IS ', '', 'DM ']]
CS-7B :  [['', 'DS ', '', 'DS ', 'DM '], ['', '', '', 'PPiI ', ''], ['', 'PPiI ', '', 'SE ', ''], ['', 'DM ', '', 'IS ', ''], ['', '', 'IS ', 'SE ', '']]
CS-1B :  [['LA ', '', '', 'DLD ', 'DLD '], ['ECaC ', 'IS ', '', 'PF ', 'ECaC '], ['ECaC-L ', 'ECaC-L ', 'DLD-L ', 'DLD-L ', 'ItIaCT '], ['ECaC ', 'PF-L ', 'PF-L ', 'ECaC-L ', 'ECaC-L '], ['ECaC ', 'PF ', 'IS ', 'LA ', 'ItIaCT ']]
CS-1A :  [['', 'PF-L ', 'PF-L ', 'ECaC ', ''], ['ECaC ', '', 'ItIaCT ', 'LA ', 'ECaC '], ['PF ECaC-L ', 'ItIaCT ECaC-L ', '', 'DLD-L ', 'DLD-L '], ['IS ', 'PF ', 'ECaC-L ', 'ECaC-L ', ''], ['DLD ', 'IS ', 'LA ', 'DLD ', 'ECaC ']]
CS-7D :  [['AML ', '', 'IS ', '', 'AML '], ['', '', '', '', ''], ['IS ', 'SfMD ', '', '', ''], ['', '', '', '', 'SfMD '], ['PPiI ', '', 'PPiI ', '', '']]
CS-7C :  [['SfMD ', '', '', 'AML ', ''], ['PPiI ', '', '', '', ''], ['', 'SfMD ', '', '', ''], ['', '', 'AML ', 'IS ', ''], ['', '', 'PPiI ', 'IS ', '']]
CS-3C :  [['MM ', 'COaAL-L ', 'COaAL-L ', 'DS ', ''], ['', '', '', '', ''], ['DS-L ', 'DS-L ', 'DS ', '', 'DE '], ['', '', '', '', ''], ['', 'DE ', '', '', 'MM ']]
CS-5C :  [['', 'CN-L ', 'CN-L ', '', 'CN '], ['PaS ', 'CN ', '', '', 'ToA '], ['', '', '', 'SDaA ', 'AP '], ['AP ', '', '', 'ToA ', 'SDaA '], ['', 'PaS ', '', '', '']]
CS-5B :  [['', '', 'WP ', '', ''], ['WP ', 'ToA ', 'MM ', 'CN-L ', 'CN-L '], ['SDaA ', '', '', 'MM ', 'CN '], ['SDaA ', '', '', 'ToA ', ''], ['', '', '', 'CN ', '']]
CS-1E :  [['PF-L ', 'PF-L ', 'AP ', 'ECaC ', 'ECaC '], ['ECaC-L ', 'ECaC-L ', 'PS ', 'ItIaCT ', 'AP '], ['', 'PF ', 'CaAG ', 'ECaC-L ', 'ECaC-L '], ['PS ', '', 'ItIaCT ', '', ''], ['', 'CaAG ', 'PF ', 'ECaC ', 'ECaC ']]
SE-3B :  [['LA ', '', '', '', ''], ['DS ', 'HCI ', '', '', ''], ['DS ', 'LA ', '', '', ''], ['', 'DS-L ', 'DS-L ', 'SRE ', 'F&A '], ['F&A ', 'HCI ', '', '', 'SRE ']]
SE-5B :  [['', '', '', 'PaS ', 'TaBW '], ['SCaD-L ', 'SCaD-L ', 'SCaD ', 'OR ', 'SQE '], ['', '', 'TaBW ', '', 'SCaD '], ['', 'SQE ', '', '', ''], ['PaS ', '', '', '', 'OR ']]
SE-5A :  [['OS-L ', 'OS-L ', 'OS ', 'SCaD-L ', 'SCaD-L '], ['OR ', 'DS ', '', 'OR ', 'TaBW '], ['DS-L ', 'DS-L ', 'PaS ', 'SCaD ', 'OS '], ['', 'SQE ', 'SCaD ', 'PaS ', 'TaBW '], ['', '', 'DS ', '', 'SQE ']]
CS-3A :  [['DS-L ', 'DS-L ', 'LA ', 'CaAG ', 'DS '], ['F&A ', 'DS ', 'DLD ', 'DS ', 'OOP '], ['CaAG ', 'LA ', 'COaAL ', 'OOP-L ', 'OOP-L '], ['DE AP ', 'COaAL-L ', 'COaAL-L ', 'OOP ', 'COaAL '], ['AP ', 'DE ', 'F&A ', 'DLD ', 'DS ']]

请注意以 CS-1D 为例,

CS-1D :  [['PF-L ', 'PF-L ', 'ECaC-L ', 'ItIaCT ECaC-L ', 'ItIaCT '], ['IS ', 'AP ', 'ECaC-L ', 'ECaC-L ', ''], ['PF ', 'PF ', '', 'ECaC ', ''], ['CaAG ', 'ECaC ', 'ECaC ', '', 'IS '], ['', 'CaAG ', '', 'ECaC ', 'AP ']]

有两件事我需要处理。首先,每个实验室(以 -L 结尾的课程在连续插槽中都有讲座。这意味着,我希望在表示时将单元格(时间表中的两个单元格)水平合并一个实验室。

其次,在某些索引上,有两场讲座同时发生。例如,请注意 CS-1D 中星期一的第 4 个插槽(0 索引)。 ItIaCT和ECaC-L是两个不同的课程,但同时有讲座。 (在这个 2D 数组中,如果同时发生两个或多个讲座,则它们在该索引中由 空格 分隔)。为此,我希望该讲座槽的单元格被水平划分以适应两个讲座。

最终输出示例如下所示(每个单元格还将告诉哪个讲师正在教授课程以及课程在哪个房间举行)

我不想要 13 个不同的插槽,而是每天只需要 五个插槽。我的问题是,

  • 我必须使用 Python 执行此操作,但我不知道如何开始。我为每个部分使用算法创建了时间表(如上所示),但我不知道如何从中制作时间表(输出

  • 其次,我想制作一个 PDF 文件,其中包含所有部分的时间表。我不知道该怎么做。我假设我需要为每个部分的时间表制作一个 Image,然后将所有这些图像(就像我在上面分享一个部分时间表的一张图像一样)合并到一个 PDF 中。但是,我不知道如何将一个时间表转换为 Image。

另外,请注意,我使用纯 HTML 制作了类似的东西,我将在下面分享其代码和结果。我正在尝试使用 Python 复制一些类似的东西。

<!DOCTYPE html>
<html>
  <style>
.center
{
  text-align: center;
 
}
td{
  height:75px;
  width:150px;
}


  </style>
<body>
<!-- Heading -->
    <h1 class="center">BCS-7D</h1>

<!-- Table -->
    <table border="5" cellspacing="5" align="center">
        
<!-- Day/Periods -->
        <tr>
            <td class="center" ><br>
                <b>Day/Period</b></br>
            </td>
            <td class="center" >
                <b>I</b>
            </td>
            <td class="center" >
                <b>II</b>
            </td>
            <td class="center">
                <b>III</b>
            </td>
            <td class="center">
                <b>1:15-1:45</b>
            </td>
            <td class="center" >
                <b>IV</b>
            </td>
            <td class="center" >
                <b>V</b>
            </td>
           
        </tr>
<!-- Monday -->
        <tr>
            <td class="center">
                <b>Monday</b></td>
            <td class="center">Linear Algebra, Mr. Raheel Ahmad, Room 1</td>
            <td class="center">X</td>
            <td class="center">X</td>
            <td rowspan="6" class="center">
                <h2>L<br>U<br>N<br>C<br>H</h2>
            </td>
            <td colspan="2" class="center">LAB</td>
        
        </tr>
<!-- Tuesday -->
        <tr>
            <td class="center">
                <b>Tuesday</b>
            </td>
            <td class="center">X</td>
            <td colspan="2" class="center">LAB
            </td>
            
            <td class="center">X</td>
            <td class="center">X</td>
        </tr>
<!-- Wednesday -->
        <tr>
            <td class="center">
                <b>Wednesday</b>
            </td>
            <td class="center">Object Oriented Programming, Ms. Jen Ledger, Room 13<hr>Programming Fundamentals, Mr. Zahid Iqbal, Room 6</td>
            <td class="center">X</td>
            <td class="center">X</td>
            <td class="center">X</td>
            <td colspan="3" class="center">X
            </td>
        </tr>
<!-- Thursday -->
        <tr>
            <td class="center">
                <b>Thursday</b>
            </td>
            <td class="center">X</td>
            <td class="center">X</td>
            <td class="center">X</td>
            <td colspan="3" class="center">Object Oriented Programming - Lab, Ms. Zain Malik, Lab 6
            </td>
          
        </tr>
<!-- Friday -->
        <tr>
            <td class="center">
                <b>Friday</b>
            </td>
            <td colspan="2" class="center">LAB
            </td>
            <td class="center">X</td>
            <td class="center">X</td>
            <td class="center">X</td> 

        </tr>
       
    </table>
</body>
  
</html>

输出的屏幕截图,(请注意,这是硬编码的布局。实验可以在时间表中的任何位置(对于一个实验,两个连续的时间段必须结合起来),同时两个讲座可以也随时发生。为此,该讲座位置上应该有一个水平分隔符)

【问题讨论】:

    标签: python timetable prettytable


    【解决方案1】:

    您可以使用jinja 进行html 模板和pdfkit 转换为pdf(要使pdfkit 工作,您可能必须在您的操作系统(不是python)上安装wkhtmltopdf)。我根据您的数据和您的 html 示例做了一个直接的示例:

    from typing import List
    
    import pdfkit
    from jinja2 import FileSystemLoader, Environment
    
    input_data = {
        "CS-3B": [['', '', 'DS ', '', 'COaAL '], ['', 'COaAL ', '', 'DS ', 'OOP '],
                  ['DS-L ', 'DS-L ', 'OOP-L ', 'OOP-L ', 'FoM '], ['COaAL-L ', 'COaAL-L ', 'OOP ', '', ''],
                  ['', 'FoM ', 'DE ', '', 'DE ']],
        "SE-3A": [['', 'OOP-L ', 'OOP-L ', '', 'SRE '], ['SRE ', 'OOP ', 'DS-L ', 'DS-L ', ''], ['', 'DS ', '', '', 'MM '],
                  ['DS ', 'MM ', '', 'LA ', ''], ['OOP ', 'HCI ', '', 'LA ', 'HCI ']],
        "CS-7F": [['', '', '', '', ''], ['RSaG ', '', '', '', ''], ['ST ', '', 'RSaG ', '', ''], ['', '', '', '', ''],
                  ['', 'ST ', '', '', '']],
        "CS-1C": [['IS ', 'ECaC-L ', 'ECaC-L ', '', 'PF '], ['ECaC ', 'PF-L ', 'PF-L ', 'ECaC-L ', 'ECaC-L '],
                  ['DLD ', 'ECaC ', '', 'PF ', 'ItIaCT '], ['DLD-L ', 'DLD-L ', 'IS ', 'LA ', ''],
                  ['ECaC ', 'ECaC ', 'ItIaCT ', 'DLD ', 'LA ']],
        "CS-1D": [['PF-L ', 'PF-L ', 'ECaC-L ', 'ItIaCT ECaC-L ', 'ItIaCT '], ['IS ', 'AP ', 'ECaC-L ', 'ECaC-L ', ''],
                  ['PF ', 'PF ', '', 'ECaC ', ''], ['CaAG ', 'ECaC ', 'ECaC ', '', 'IS '],
                  ['', 'CaAG ', '', 'ECaC ', 'AP ']],
        "CS-7A": [['', 'DM ', '', 'PPiI ', 'DS '], ['AI-L ', 'AI-L ', '', 'AI ', 'IS '], ['', '', 'DS ', '', ''],
                  ['SE ', 'SE ', '', 'PPiI ', ''], ['', 'AI ', 'IS ', '', 'DM ']],
        "CS-7B": [['', 'DS ', '', 'DS ', 'DM '], ['', '', '', 'PPiI ', ''], ['', 'PPiI ', '', 'SE ', ''],
                  ['', 'DM ', '', 'IS ', ''], ['', '', 'IS ', 'SE ', '']],
        "CS-1B": [['LA ', '', '', 'DLD ', 'DLD '], ['ECaC ', 'IS ', '', 'PF ', 'ECaC '],
                  ['ECaC-L ', 'ECaC-L ', 'DLD-L ', 'DLD-L ', 'ItIaCT '], ['ECaC ', 'PF-L ', 'PF-L ', 'ECaC-L ', 'ECaC-L '],
                  ['ECaC ', 'PF ', 'IS ', 'LA ', 'ItIaCT ']],
        "CS-1A": [['', 'PF-L ', 'PF-L ', 'ECaC ', ''], ['ECaC ', '', 'ItIaCT ', 'LA ', 'ECaC '],
                  ['PF ECaC-L ', 'ItIaCT ECaC-L ', '', 'DLD-L ', 'DLD-L '], ['IS ', 'PF ', 'ECaC-L ', 'ECaC-L ', ''],
                  ['DLD ', 'IS ', 'LA ', 'DLD ', 'ECaC ']],
        "CS-7D": [['AML ', '', 'IS ', '', 'AML '], ['', '', '', '', ''], ['IS ', 'SfMD ', '', '', ''],
                  ['', '', '', '', 'SfMD '], ['PPiI ', '', 'PPiI ', '', '']],
        "CS-7C": [['SfMD ', '', '', 'AML ', ''], ['PPiI ', '', '', '', ''], ['', 'SfMD ', '', '', ''],
                  ['', '', 'AML ', 'IS ', ''], ['', '', 'PPiI ', 'IS ', '']],
        "CS-3C": [['MM ', 'COaAL-L ', 'COaAL-L ', 'DS ', ''], ['', '', '', '', ''], ['DS-L ', 'DS-L ', 'DS ', '', 'DE '],
                  ['', '', '', '', ''], ['', 'DE ', '', '', 'MM ']],
        "CS-5C": [['', 'CN-L ', 'CN-L ', '', 'CN '], ['PaS ', 'CN ', '', '', 'ToA '], ['', '', '', 'SDaA ', 'AP '],
                  ['AP ', '', '', 'ToA ', 'SDaA '], ['', 'PaS ', '', '', '']],
        "CS-5B": [['', '', 'WP ', '', ''], ['WP ', 'ToA ', 'MM ', 'CN-L ', 'CN-L '], ['SDaA ', '', '', 'MM ', 'CN '],
                  ['SDaA ', '', '', 'ToA ', ''], ['', '', '', 'CN ', '']],
        "CS-1E": [['PF-L ', 'PF-L ', 'AP ', 'ECaC ', 'ECaC '], ['ECaC-L ', 'ECaC-L ', 'PS ', 'ItIaCT ', 'AP '],
                  ['', 'PF ', 'CaAG ', 'ECaC-L ', 'ECaC-L '], ['PS ', '', 'ItIaCT ', '', ''],
                  ['', 'CaAG ', 'PF ', 'ECaC ', 'ECaC ']],
        "SE-3B": [['LA ', '', '', '', ''], ['DS ', 'HCI ', '', '', ''], ['DS ', 'LA ', '', '', ''],
                  ['', 'DS-L ', 'DS-L ', 'SRE ', 'F&A '], ['F&A ', 'HCI ', '', '', 'SRE ']],
        "SE-5B": [['', '', '', 'PaS ', 'TaBW '], ['SCaD-L ', 'SCaD-L ', 'SCaD ', 'OR ', 'SQE '],
                  ['', '', 'TaBW ', '', 'SCaD '], ['', 'SQE ', '', '', ''], ['PaS ', '', '', '', 'OR ']],
        "SE-5A": [['OS-L ', 'OS-L ', 'OS ', 'SCaD-L ', 'SCaD-L '], ['OR ', 'DS ', '', 'OR ', 'TaBW '],
                  ['DS-L ', 'DS-L ', 'PaS ', 'SCaD ', 'OS '], ['', 'SQE ', 'SCaD ', 'PaS ', 'TaBW '],
                  ['', '', 'DS ', '', 'SQE ']],
        "CS-3A": [['DS-L ', 'DS-L ', 'LA ', 'CaAG ', 'DS '], ['F&A ', 'DS ', 'DLD ', 'DS ', 'OOP '],
                  ['CaAG ', 'LA ', 'COaAL ', 'OOP-L ', 'OOP-L '], ['DE AP ', 'COaAL-L ', 'COaAL-L ', 'OOP ', 'COaAL '],
                  ['AP ', 'DE ', 'F&A ', 'DLD ', 'DS ']]
    }
    
    
    def organise_input_data(elements: List[List[str]]) -> List[list]:
        """
        Organises the input data to find double courses for easier use in templates
        """
        new_elements = []
        for day in elements:
            last_course = None
            course_list = []
            index = 0
            for course in day:
                # cleanup data
                course = course.strip().replace(" ", "<hr>")
                # check if long course (and not lunch time)
                if course != "" and course == last_course and index != 3:
                    course_list.remove((course, 1))
                    course_list.append((course, 2))
                    course_list.append(("none", 0))
                else:
                    course_list.append((course.replace(" ", "<hr>"), 1))
                last_course = course
                index += 1
            new_elements.append(course_list)
    
        return new_elements
    
    
    def generate_html(template, name: str, elements: List[list]) -> str:
    
        new_elements = organise_input_data(elements=elements)
    
        rendered = template.render(
            name=name,
            monday=new_elements[0],
            tuesday=new_elements[1],
            wednesday=new_elements[2],
            thursday=new_elements[3],
            friday=new_elements[4]
        )
    
        with open(f"out_{name}.html", "w+") as file:
            file.write(rendered)
    
        return rendered
    
    
    def run():
        # Init jinja
        file_loader = FileSystemLoader('.')
        env = Environment(loader=file_loader)
        template = env.get_template('template.html')
    
        full_text = ""
        for name, elements in input_data.items():
            full_text += generate_html(template=template, name=name, elements=elements)
    
        pdfkit.from_string(full_text, "out.pdf")
    
    
    if __name__ == '__main__':
        run()
    

    organise_input_data 函数仅用于数据准备。 template.html 看起来像:

    <!DOCTYPE html>
    <html>
      <style>
    .center
    {
      text-align: center;
    
    }
    td{
      height:75px;
      width:150px;
    }
    
    
      </style>
    <body>
    <!-- Heading -->
        <h1 class="center">{{name}}</h1>
    
    <!-- Table -->
        <table border="5" cellspacing="5" align="center">
    
    <!-- Day/Periods -->
            <tr>
                <td class="center" ><br>
                    <b>Day/Period</b></br>
                </td>
                <td class="center" >
                    <b>I</b>
                </td>
                <td class="center" >
                    <b>II</b>
                </td>
                <td class="center">
                    <b>III</b>
                </td>
                <td class="center">
                    <b>1:15-1:45</b>
                </td>
                <td class="center" >
                    <b>IV</b>
                </td>
                <td class="center" >
                    <b>V</b>
                </td>
    
            </tr>
    <!-- Monday -->
            <tr>
                <td class="center">
                    <b>Monday</b></td>
                {% for course in monday %}
                    {% if loop.index == 4 %}
                        <td rowspan="6" class="center">
                            <h2>L<br>U<br>N<br>C<br>H</h2>
                        </td>
                    {% endif %}
                    {% if course[1] != 0 %}
                        <td colspan={{course[1]}} class="center">{{course[0]}}</td>
                    {% endif %}
                {% endfor %}
    
            </tr>
    <!-- Tuesday -->
            <tr>
                <td class="center">
                    <b>Tuesday</b>
                </td>
                {% for course in tuesday %}
                    {% if course[1] != 0 %}
                        <td colspan={{course[1]}} class="center">{{course[0]}}</td>
                    {% endif %}
                {% endfor %}
            </tr>
    <!-- Wednesday -->
            <tr>
                <td class="center">
                    <b>Wednesday</b>
                </td>
                {% for course in wednesday %}
                    {% if course[1] != 0 %}
                        <td colspan={{course[1]}} class="center">{{course[0]}}</td>
                    {% endif %}
                {% endfor %}
            </tr>
    <!-- Thursday -->
            <tr>
                <td class="center">
                    <b>Thursday</b>
                </td>
                {% for course in thursday %}
                    {% if course[1] != 0 %}
                        <td colspan={{course[1]}} class="center">{{course[0]}}</td>
                    {% endif %}
                {% endfor %}
    
            </tr>
    <!-- Friday -->
            <tr>
                <td class="center">
                    <b>Friday</b>
                </td>
                {% for course in friday %}
                    {% if course[1] != 0 %}
                        <td colspan={{course[1]}} class="center">{{course[0]}}</td>
                    {% endif %}
                {% endfor %}
    
            </tr>
    
        </table>
    </body>
    
    </html>
    

    输出pdf:

    说明: Jinja 是一种模板语言/库,因此您可以在其中创建包含一些变量和逻辑的 html(主要在 {} 括号中),因此您不必通过 python 本身创建整个 html。 我决定为每门课程创建带有课程名称和持续时间的元组(连续 1 或 2 个时间段)。如果您控制时间表创建的整个过程,您可以直接生成此数据而不是您的 input_data 列表。

    该示例非常简单,并且非常接近您给定的数据,从而使执行该步骤变得非常容易。您还可以通过在 html/jinja 中使用更多逻辑来创建(在我看来)更干净的 html 文件,例如:

    {% for day in days %}
        {% with courses=course_list[loop.index-1] %}
            {% include 'template_day.html' %}
        {% endwith %}
    {% endfor %}
    

    和一个额外的模板文件(template.html),每天都有日志:

    <tr>
        <td class="center">
            <b>{{day}}</b>
        </td>
        {% for course in courses %}
            {% if day == "Monday" and loop.index == 4 %}
                <td rowspan="6" class="center">
                    <h2>L<br>U<br>N<br>C<br>H</h2>
                </td>
            {% endif %}
            {% if course[1] != 0 %}
                <td colspan={{course[1]}} class="center">{{course[0]}}</td>
            {% endif %}
        {% endfor %}
    </tr>
    

    有了这个,html 就更短了(因为所有的日子都在 html 中迭代,而不是手动声明)。因此,如果您想添加更多数据(例如 Room),您只需在一个地方而不是在 5 处进行更改。渲染调用的新部分也将更短:

    rendered = template.render(
            name=name,
            days=["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"],
            course_list=new_elements
        )
    

    【讨论】:

    • 非常感谢您的回答和努力。太感谢了!这解决了我的一个大问题!
    【解决方案2】:

    有很多方法可以使用动态数据生成这样的布局,通常对于 python,我建议您使用 excel,或者使用基于 Web 的布局,然后使用它来生成输出 pdf。

    使用 HTML 操作

    如果我们谈论的是基于 Web 的布局,您需要使用 beautifulsoup,您应该使用的方法如下所示:

    1. 创建一个标准布局,其中每个位置都有唯一 id 的单元格(您可以使用与上一个示例类似的内容)。

    2. 循环遍历可能需要拆分的较大容器,您可以使用带有 if 条件的 beautifulsoup 来添加不同的 html,具体取决于您是否需要拆分数据,例如:

    import bs4
    
    with open("template.html") as t:
        text = t.read()
        soup = bs4.BeautifulSoup(text)
    
    td = soup.find(id="B6")
    entry = soup.new_tag("p")
    entry.append("LAB")
    # insert the new tag after the current tag
    td.insert_after(new_tag)
    
    1. 您可以在此阶段动态添加布局,可能逐行添加 td 标签而不是其内容。

    2. 最后,完成后,您可以使用以下命令保存 html 文件:

    with open("template.html", "w") as t:
        t.write(str(soup))
    
    1. 保存后,您需要使用pdfkit 生成pdf,这非常简单:
    import pdfkit
    pdfkit.from_url('template.html', 'out.pdf')
    

    使用 Excel 操作

    我不会深入介绍 excel 方法,但如果您愿意,可以使用 openpyxl 进行研究,您可以看到许多示例 here

    生成您的excel后,您可以使用pandas以及pdf kit将其转换为pdf,您可以找到有关this问题答案的更多信息,但为了完整起见,请在此处保留信息:

    1. 将 excel 转换为 pandas 对象
    2. 将 pandas 对象转换为 html
    3. 将 html 转换为 pdf

    取自 Thomas Devoogdt 的 answer 的示例代码:

    import pandas as pd
    import pdfkit
    
    df = pd.read_excel("file.xlsx")
    df.to_html("file.html")
    pdfkit.from_file("file.html", "file.pdf")
    

    结论

    虽然有许多其他方法可以生成这种布局(例如使用 OpenCV),但手动生成您想要的布局可能会变得非常复杂,因此使用 excel 或最好使用 HTML 操作(因为您似乎有使用它并可以在 html 中创建您想要的布局)将为您提供一种更灵活的方法来利用该方法。

    【讨论】:

      猜你喜欢
      • 2017-06-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-09-05
      • 2017-10-12
      • 1970-01-01
      • 1970-01-01
      • 2023-02-10
      相关资源
      最近更新 更多