python-docx如何合并行单元格

问题描述 投票:0回答:1

我正在使用python-docx从数据创建Word文档。我可以毫无问题地创建所有行和单元格,但在某些情况下,当数据库中的当前记录在字段注释中有一些内容时,我需要添加一个新行来显示长内容。

我尝试添加一个段落,但结果是注释被附加在表之后,我需要将它添加到当前表行之下。

我认为解决方案是附加一个表行,所有单元格合并,但我找不到文档。

这是我生成docx文件的代码:

class OperationDOCXView(viewsets.ViewSet):
    exclude_from_schema = True

    def list(self, request):
        from ReportsManagerApp.controllers import Operations2Controller

        self.profile_id = request.query_params['profile_id']
        self.operation_date = request.query_params['operation_date']
        self.operation_type = request.query_params['operation_type']
        self.format = request.query_params['doc_format']

        operation_report_controller = Operations2Controller(self.profile_id, self.operation_date, self.operation_type)
        context = operation_report_controller.get_context()

        if self.format == 'json':
            return Response(context)
        else:
            word_doc = self.get_operation_word_file(request, context)

        return Response("{}{}{}".format(request.get_host(), settings.MEDIA_URL, word_doc))

    def get_operation_word_file(self, request, context):
        import unicodedata
        from django.core.files import File
        from django.urls import reverse
        from docx import Document
        from docx.shared import Inches, Pt

        operation_type = {
            'arrival': 'Llegadas',
            'departure': 'Salidas',
            'hotel': 'Hotel-Hotel',
            'tour': 'Tours',
        }

        weekdays = {
            '0': 'LUNES',
            '1': 'MARTES',
            '2': 'MIÉRCOLES',
            '3': 'JUEVES',
            '4': 'VIERNES',
            '5': 'SÁBADO',
            '6': 'DOMINGO',
        }

        titles = ['Booking', 'Nombre', '#', 'Vuelo', 'Hr', 'P Up', 'Traslado', 'Circuito', 'Priv?', 'Agencia', '']
        widths = [Inches(1), Inches(2), Inches(0.5), Inches(1), Inches(1), Inches(1), Inches(2), Inches(3), Inches(0.5), Inches(3), Inches(0.5)]

        document = Document()

        section = document.sections[-1]
        section.top_margin = Inches(0.5)
        section.bottom_margin = Inches(0.5)
        section.left_margin = Inches(0.3)
        section.right_margin = Inches(0.2)

        style = document.styles['Normal']
        font = style.font
        font.name ='Arial'
        font.size = Pt(10)

        company_paragraph = document.add_heading("XXXX TTOO INC")
        company_paragraph.alignment = WD_ALIGN_PARAGRAPH.CENTER

        description_paragraph = document.add_paragraph("Operación de {} del día {}".format(operation_type[self.operation_type], self.operation_date))
        description_paragraph.alignment = WD_ALIGN_PARAGRAPH.CENTER
        operation_date = self.get_operation_date().date()
        operation_week_day = operation_date.weekday()
        day_paragraph = document.add_paragraph(weekdays[str(operation_week_day)])
        day_paragraph.alignment = WD_ALIGN_PARAGRAPH.CENTER

        for provider_unit, transfers in context.items():
            provider_unit_paragraph = document.add_paragraph(provider_unit)
            provider_unit_paragraph.style.font.size = Pt(10)
            provider_unit_paragraph.style.font.bold = False

            table = document.add_table(rows=1, cols=11)
            hdr_cells = table.rows[0].cells
            runs = []
            for i in range(len(hdr_cells)):
                runs.append(self.get_hdr_cells_run(hdr_cells[i], titles[i]))
            for row in table.rows:
                for idx, width in enumerate(widths):
                    row.cells[idx].width = width
            adults = 0
            minors = 0
            for transfer in transfers:
                # table = document.add_table(rows=1, cols=11)
                row_cells = table.add_row().cells
                row_cells[0].text = transfer['booking']
                row_cells[1].text = transfer['people']
                row_cells[2].text = transfer['pax']
                flight = transfer.get("flight","") if transfer.get("flight","") is not None else ""
                row_cells[3].text = flight
                flight_time = self.get_flight_time(flight) if flight != '' else ''
                row_cells[4].text = flight_time
                row_cells[5].text = transfer['pickup_time'].strftime('%H:%M') if transfer['pickup_time'] is not None else ''
                row_cells[6].text = transfer['place']
                row_cells[7].text = transfer['roundtrip']
                row_cells[8].text = transfer['is_private']
                row_cells[9].text = transfer['agency']
                people = transfer['pax'].split('.')
                adults = adults + int(people[0])
                minors = minors + int(people[1])

                if transfer['comment'] is not None:
                    document.add_paragraph("Comentarios: {}".format(transfer['comment']))

            for row in table.rows:
                for idx, width in enumerate(widths):
                    row.cells[idx].width = width
                for cell in row.cells:
                    paragraphs = cell.paragraphs
                    for paragraph in paragraphs:
                        for run in paragraph.runs:
                            font = run.font
                            font.size = Pt(8)

            row_cells = table.add_row().cells
            row_cells[10].text = "{}.{}".format(adults, minors)

        current_directory = settings.MEDIA_DIR
        file_name = "Operaciones {} {}.docx".format(self.operation_type, self.operation_date)
        document.save("{}{}".format(current_directory, file_name))

        return file_name

    def get_flight_time(self, flight):
        from OperationsManagerApp.models import Flight

        operation_types = {
            'arrival': 'ARRIVAL',
            'departure': 'DEPARTURE'
        }

        operation_date = datetime.strptime(self.operation_date, '%Y-%m-%d')

        try:
            flight = Flight.objects.get(flight_type=operation_types[self.operation_type], number=flight)
        except:
            return ''
        else:
            weekday_times = {
                '0': flight.time_monday,
                '1': flight.time_tuesday,
                '2': flight.time_wednesday,
                '3': flight.time_thursday,
                '4': flight.time_friday,
                '5': flight.time_saturday,
                '6': flight.time_sunday,
            }

        weekday_time = weekday_times[str(operation_date.weekday())]

        return weekday_time.strftime('%H:%M') if weekday_time is not None else ''

    def get_hdr_cells_run(self, hdr_cells, title):
        from docx.shared import Pt

        new_run = hdr_cells.paragraphs[0].add_run(title)
        new_run.bold = True
        new_run.font.size = Pt(8)

        return new_run

    def get_operation_date(self):
        date_array = self.operation_date.split('-')
        day = int(date_array[2])
        month = int(date_array[1])
        year = int(date_array[0])

        operation_date = datetime(year, month, day)

        return operation_date
python python-docx
1个回答
2
投票

一种方法是在其中一个单元格中添加一个段落:

cell.add_paragraph(transfer['comment'])

这将把它放在相对于它所属的行的正确位置,而不是在表之后。

如果对于已经有其他数据项并且您想要添加行的单个单元格而言需要太多空间,则在分配表时需要考虑该行。但假设你得到了解决方案,合并细胞很容易:

row.cells[0].merge(row.cells[-1])
© www.soinside.com 2019 - 2024. All rights reserved.