@ -8,11 +8,11 @@ import xlwt
from django . conf import settings
from django . conf import settings
from django . template import Template , RequestContext
from django . template import Template , RequestContext
from django . template . base import BLOCK_TAG_START , BLOCK_TAG_END , VARIABLE_TAG_START , VARIABLE_TAG_END
from django . template . base import BLOCK_TAG_START , BLOCK_TAG_END , VARIABLE_TAG_START , \
VARIABLE_TAG_END
from commons . xls import ( get_xlwt_style_list , copy_cells , width_cols , horz_page_break , mm_to_twips ,
sum_src_heights , sum_dst_heights )
from commons . xls import ( get_xlwt_style_list , copy_cells , width_cols ,
horz_page_break , mm_to_twips , sum_src_heights , sum_dst_heights )
TAG_RE = re . compile ( ' ( %s .*? %s | %s .*? %s ) ' % (
TAG_RE = re . compile ( ' ( %s .*? %s | %s .*? %s ) ' % (
re . escape ( BLOCK_TAG_START ) , re . escape ( BLOCK_TAG_END ) ,
re . escape ( BLOCK_TAG_START ) , re . escape ( BLOCK_TAG_END ) ,
@ -35,7 +35,7 @@ def render_xls_to_string(request, xls_template, dictionary=None):
try :
try :
# откуда
# откуда
src_book = xlrd . open_workbook ( src_xls , encoding_override = ' cp1251 ' ,
src_book = xlrd . open_workbook ( src_xls , encoding_override = ' cp1251 ' ,
on_demand = True , formatting_info = True )
on_demand = True , formatting_info = True )
src_sheet = src_book . sheet_by_index ( 0 )
src_sheet = src_book . sheet_by_index ( 0 )
# достать список стилей
# достать список стилей
@ -50,8 +50,7 @@ def render_xls_to_string(request, xls_template, dictionary=None):
apply_page_settings ( dst_sheet , xls_settings )
apply_page_settings ( dst_sheet , xls_settings )
# import ipdb;ipdb.set_trace()
# import ipdb;ipdb.set_trace()
# заполнить данными
# заполнить данными
fill_xls ( request , dictionary , src_sheet , dst_sheet , style_list ,
fill_xls ( request , dictionary , src_sheet , dst_sheet , style_list , xls_settings )
xls_settings )
# закрыть исходную книгу и сохранить созданную
# закрыть исходную книгу и сохранить созданную
src_book . release_resources ( )
src_book . release_resources ( )
@ -73,8 +72,6 @@ def fill_xls(request, dictionary, src_sheet, dst_sheet, style_list, xls_settings
context = RequestContext ( request , dictionary )
context = RequestContext ( request , dictionary )
# -------------------------------------------------------------------------
def write ( row , col , val , src_row = None , src_col = None , commands = None ) :
def write ( row , col , val , src_row = None , src_col = None , commands = None ) :
""" Записывает данные в ячейку с сохранением стилей. """
""" Записывает данные в ячейку с сохранением стилей. """
src_row = src_row or row
src_row = src_row or row
@ -92,18 +89,21 @@ def fill_xls(request, dictionary, src_sheet, dst_sheet, style_list, xls_settings
return template . render ( context )
return template . render ( context )
def parse_cells ( row_from = 0 , row_to = None , col_from = 0 , col_to = None ,
def parse_cells ( row_from = 0 , row_to = None , col_from = 0 , col_to = None ,
dst_row_shift = 0 , dst_col_shift = 0 , * * kwargs ) :
dst_row_shift = 0 , dst_col_shift = 0 , * * kwargs ) :
""" Ищет шаблонные теги и переменные в ячейках заданного диапазона. Если находит, то передает содержимое ячейки
"""
целиком на обработку в process_template . После чего записывает полученный результат обратно в ячейку .
Ищет шаблонные теги и переменные в ячейках заданного диапазона .
Если находит , то передает содержимое ячейки
целиком на обработку в process_template . После чего записывает
полученный результат обратно в ячейку .
Также ищет спец . токены и выполняет соответствующие действия .
Также ищет спец . токены и выполняет соответствующие действия .
"""
"""
row_to = row_to or src_sheet . nrows - 1
row_to = row_to or src_sheet . nrows - 1
col_to = col_to or src_sheet . ncols - 1
col_to = col_to or src_sheet . ncols - 1
for row in range ( row_from , row_to + 1 ) :
for row in range ( row_from , row_to + 1 ) :
cmd_fix_height = [ ]
cmd_fix_height = [ ]
for col in range ( col_from , col_to + 1 ) :
for col in range ( col_from , col_to + 1 ) :
cell = src_sheet . cell ( row , col )
cell = src_sheet . cell ( row , col )
cell_value = new_value = cell . value
cell_value = new_value = cell . value
@ -121,7 +121,6 @@ def fill_xls(request, dictionary, src_sheet, dst_sheet, style_list, xls_settings
new_value = process_template ( new_value , * * kwargs )
new_value = process_template ( new_value , * * kwargs )
# пофиксить переводы строки
# пофиксить переводы строки
#new_value = new_value.strip().replace('\r\n', '\n')
new_value = new_value . strip ( ) . replace ( ' \r \n ' , ' ' )
new_value = new_value . strip ( ) . replace ( ' \r \n ' , ' ' )
# команда 'конвертировать во float'
# команда 'конвертировать во float'
@ -162,8 +161,8 @@ def fill_xls(request, dictionary, src_sheet, dst_sheet, style_list, xls_settings
try :
try :
dst_sheet . insert_bitmap (
dst_sheet . insert_bitmap (
new_value ,
new_value ,
row = row + dst_row_shift ,
row = row + dst_row_shift ,
col = col + dst_col_shift ,
col = col + dst_col_shift ,
)
)
new_value = ' '
new_value = ' '
except :
except :
@ -173,28 +172,26 @@ def fill_xls(request, dictionary, src_sheet, dst_sheet, style_list, xls_settings
# print "Error inserting image from file '%s'" % new_value
# print "Error inserting image from file '%s'" % new_value
raise
raise
write (
write (
row = row + dst_row_shift ,
row = row + dst_row_shift ,
col = col + dst_col_shift ,
col = col + dst_col_shift ,
val = new_value ,
val = new_value ,
src_row = row ,
src_row = row ,
src_col = col ,
src_col = col ,
commands = { ' draw_thin_bottom_border ' : cmd_draw_thin_bottom_border ,
commands = { ' draw_thin_bottom_border ' : cmd_draw_thin_bottom_border }
}
)
)
# --- конец цикла по ячейкам в строке
# --- конец цикла по ячейкам в строке
# подобрать высоту строки в ячейках
# подобрать высоту строки в ячейках
dst_row = row + dst_row_shift # строка назначения
dst_row = row + dst_row_shift # строка назначения
row_height = dst_sheet . row ( dst_row ) . height # текущая высота
row_height = dst_sheet . row ( dst_row ) . height # текущая высота
max_height = 0
max_height = 0
for fh in cmd_fix_height :
for fh in cmd_fix_height :
#print '---FIX_HEIGHT:', 'dst_row=', dst_row, 'col=', fh['col']
# print '---FIX_HEIGHT:', 'dst_row=', dst_row, 'col=', fh['col']
# взять ширину ячейки
# взять ширину ячейки
width = 0
width = 0
# учитываем только объединенные ячейки
# учитываем только объединенные ячейки
for r1 , r2 , c1 , c2 in src_sheet . merged_cells :
for r1 , r2 , c1 , c2 in src_sheet . merged_cells :
if r1 != row or c1 != fh [ ' col ' ] :
if r1 != row or c1 != fh [ ' col ' ] :
continue
continue
for colx in range ( c1 , c2 ) :
for colx in range ( c1 , c2 ) :
@ -208,7 +205,8 @@ def fill_xls(request, dictionary, src_sheet, dst_sheet, style_list, xls_settings
width_in_pixels = width / 36.5
width_in_pixels = width / 36.5
width_in_chars = width_in_pixels / 5.8
width_in_chars = width_in_pixels / 5.8
# может быть 0, если команда @@FIX_HEIGHT@@ задана в простой (не объединенной) ячейке
# может быть 0, если команда @@FIX_HEIGHT@@ задана в простой
# (не объединенной) ячейке
if width_in_chars == 0 :
if width_in_chars == 0 :
# print ('WARNING. xls generation, cmd @@FIX_HEIGHT@@. '
# print ('WARNING. xls generation, cmd @@FIX_HEIGHT@@. '
# 'variable `width_in_chars` = %s. skip this command.' % width_in_chars)
# 'variable `width_in_chars` = %s. skip this command.' % width_in_chars)
@ -219,14 +217,15 @@ def fill_xls(request, dictionary, src_sheet, dst_sheet, style_list, xls_settings
min_rows = 1
min_rows = 1
need_rows = math . ceil ( len ( value ) / width_in_chars )
need_rows = math . ceil ( len ( value ) / width_in_chars )
need_rows = int ( max ( min_rows , need_rows ) )
need_rows = int ( max ( min_rows , need_rows ) )
#print 'need_rows=', need_rows
# print 'need_rows=', need_rows
new_height = row_height * need_rows
new_height = row_height * need_rows
# не фиксить высоту, если новая высота данной ячейки меньше либо равна текущей высоте
# не фиксить высоту, если новая высота данной ячейки меньше либо
# равна текущей высоте
if new_height > max_height :
if new_height > max_height :
max_height = new_height
max_height = new_height
else :
else :
#print 'SKIP,', new_height, '<=', max_height
# print 'SKIP,', new_height, '<=', max_height
continue
continue
dst_sheet . row ( dst_row ) . height = new_height
dst_sheet . row ( dst_row ) . height = new_height
@ -253,12 +252,12 @@ def fill_xls(request, dictionary, src_sheet, dst_sheet, style_list, xls_settings
# --- !!! ------ вывести начало документа включительно по шапку табл. части
# --- !!! ------ вывести начало документа включительно по шапку табл. части
copy_cells ( src_sheet , dst_sheet , style_list , row_from = 0 , row_to = p . TBL_BODY_ROW - 1 )
copy_cells ( src_sheet , dst_sheet , style_list , row_from = 0 , row_to = p . TBL_BODY_ROW - 1 )
parse_cells ( row_to = p . TBL_BODY_ROW - 1 )
parse_cells ( row_to = p . TBL_BODY_ROW - 1 )
# для отладки - выйти здесь
# для отладки - выйти здесь
#return
# return
# --- !!! ------------ вывести таблицу с учетом переходов на новую страницу
# --- !!! ------------ вывести таблицу с учетом переходов на новую страницу
@ -273,24 +272,24 @@ def fill_xls(request, dictionary, src_sheet, dst_sheet, style_list, xls_settings
row = 0
row = 0
row_shift = 0
row_shift = 0
#print '---table:'
# print '---table:'
def write_tbl_body_row ( ) :
def write_tbl_body_row ( ) :
""" Хелпер для отрисовки строки таблицы.
""" Хелпер для отрисовки строки таблицы.
Зависит от внешних переменных row_shift , row и item !
Зависит от внешних переменных row_shift , row и item !
"""
"""
#print '---table body row, dst_row_shift =', row_shift
# print '---table body row, dst_row_shift =', row_shift
copy_cells (
copy_cells (
src_sheet , dst_sheet , style_list ,
src_sheet , dst_sheet , style_list ,
row_from = p . TBL_BODY_ROW , row_to = p . TBL_BODY_ROW ,
row_from = p . TBL_BODY_ROW , row_to = p . TBL_BODY_ROW ,
dst_row_shift = row_shift
dst_row_shift = row_shift
)
)
parse_cells (
parse_cells (
row_from = p . TBL_BODY_ROW ,
row_from = p . TBL_BODY_ROW ,
row_to = p . TBL_BODY_ROW ,
row_to = p . TBL_BODY_ROW ,
dst_row_shift = row_shift ,
dst_row_shift = row_shift ,
item = item ,
item = item ,
item_npp = row + 1
item_npp = row + 1
)
)
def write_tbl_page_footer ( ) :
def write_tbl_page_footer ( ) :
@ -298,19 +297,19 @@ def fill_xls(request, dictionary, src_sheet, dst_sheet, style_list, xls_settings
Зависит от внешних переменных row_shift , last_page_item_idx и row !
Зависит от внешних переменных row_shift , last_page_item_idx и row !
"""
"""
dst_row_shift = row_shift - ( p . TBL_PAGE_FOOTER_FROM - p . TBL_BODY_ROW )
dst_row_shift = row_shift - ( p . TBL_PAGE_FOOTER_FROM - p . TBL_BODY_ROW )
#print '---table page footer, dst_row_shift =', dst_row_shift, \
# print '---table page footer, dst_row_shift =', dst_row_shift, \
# 'items_start =', last_page_item_idx, 'items_stop =', row
# 'items_start =', last_page_item_idx, 'items_stop =', row
copy_cells (
copy_cells (
src_sheet , dst_sheet , style_list ,
src_sheet , dst_sheet , style_list ,
row_from = p . TBL_PAGE_FOOTER_FROM , row_to = p . TBL_PAGE_FOOTER_TO ,
row_from = p . TBL_PAGE_FOOTER_FROM , row_to = p . TBL_PAGE_FOOTER_TO ,
dst_row_shift = dst_row_shift
dst_row_shift = dst_row_shift
)
)
parse_cells (
parse_cells (
row_from = p . TBL_PAGE_FOOTER_FROM ,
row_from = p . TBL_PAGE_FOOTER_FROM ,
row_to = p . TBL_PAGE_FOOTER_TO ,
row_to = p . TBL_PAGE_FOOTER_TO ,
dst_row_shift = dst_row_shift ,
dst_row_shift = dst_row_shift ,
items_start = last_page_item_idx ,
items_start = last_page_item_idx ,
items_stop = row
items_stop = row
)
)
def write_tbl_header ( ) :
def write_tbl_header ( ) :
@ -318,17 +317,17 @@ def fill_xls(request, dictionary, src_sheet, dst_sheet, style_list, xls_settings
Зависит от внешних переменных row и add_offset !
Зависит от внешних переменных row и add_offset !
"""
"""
dst_row_shift = p . TBL_HEADER_ROWS + row + add_offset
dst_row_shift = p . TBL_HEADER_ROWS + row + add_offset
#print '---table header, dst_row_shift =', dst_row_shift
# print '---table header, dst_row_shift =', dst_row_shift
copy_cells (
copy_cells (
src_sheet , dst_sheet , style_list ,
src_sheet , dst_sheet , style_list ,
row_from = p . TBL_HEADER_FROM , row_to = p . TBL_HEADER_TO ,
row_from = p . TBL_HEADER_FROM , row_to = p . TBL_HEADER_TO ,
dst_row_shift = dst_row_shift
dst_row_shift = dst_row_shift
)
)
# цикл по табличной части документа
# цикл по табличной части документа
for row , item in enumerate ( obj_items ) :
for row , item in enumerate ( obj_items ) :
row_shift = row + add_offset
row_shift = row + add_offset
#print 'row = %s, add_offset = %s' % (row, add_offset)
# print 'row = %s, add_offset = %s' % (row, add_offset)
write_tbl_body_row ( )
write_tbl_body_row ( )
row_height = dst_sheet . row ( p . TBL_BODY_ROW + row_shift ) . height
row_height = dst_sheet . row ( p . TBL_BODY_ROW + row_shift ) . height
@ -340,13 +339,13 @@ def fill_xls(request, dictionary, src_sheet, dst_sheet, style_list, xls_settings
if curr_height + p . TBL_PAGE_FOOTER_HEIGHT + p . TBL_FOOTER_HEIGHT > p . WORK_HEIGHT :
if curr_height + p . TBL_PAGE_FOOTER_HEIGHT + p . TBL_FOOTER_HEIGHT > p . WORK_HEIGHT :
# если это первая строка, то:
# если это первая строка, то:
if row == 0 :
if row == 0 :
#print '---table new page, row =', row
# print '---table new page, row =', row
# 1. добавить разрыв страницы перед первой шапкой
# 1. добавить разрыв страницы перед первой шапкой
horz_page_break ( dst_sheet , p . TBL_HEADER_FROM )
horz_page_break ( dst_sheet , p . TBL_HEADER_FROM )
curr_height = p . TBL_HEADER_HEIGHT + row_height
curr_height = p . TBL_HEADER_HEIGHT + row_height
# если это не последняя строка, то:
# если это не последняя строка, то:
elif row < len ( obj_items ) - 1 :
elif row < len ( obj_items ) - 1 :
#print '---table new page, row =', row
# print '---table new page, row =', row
# 1. вместо строки вывести подитог
# 1. вместо строки вывести подитог
if p . TBL_PAGE_FOOTER_ROWS > 0 :
if p . TBL_PAGE_FOOTER_ROWS > 0 :
write_tbl_page_footer ( )
write_tbl_page_footer ( )
@ -355,7 +354,8 @@ def fill_xls(request, dictionary, src_sheet, dst_sheet, style_list, xls_settings
add_offset + = p . TBL_PAGE_FOOTER_ROWS
add_offset + = p . TBL_PAGE_FOOTER_ROWS
row_shift + = add_offset
row_shift + = add_offset
# 2. добавить разрыв страницы
# 2. добавить разрыв страницы
horz_page_break ( dst_sheet , ( p . TBL_HEADER_FROM + p . TBL_HEADER_ROWS + row + add_offset ) )
horz_page_break ( dst_sheet ,
( p . TBL_HEADER_FROM + p . TBL_HEADER_ROWS + row + add_offset ) )
# 3. вывести шапку
# 3. вывести шапку
write_tbl_header ( )
write_tbl_header ( )
add_offset + = p . TBL_HEADER_ROWS
add_offset + = p . TBL_HEADER_ROWS
@ -365,28 +365,28 @@ def fill_xls(request, dictionary, src_sheet, dst_sheet, style_list, xls_settings
write_tbl_body_row ( )
write_tbl_body_row ( )
curr_height + = row_height
curr_height + = row_height
else : # for ... else
else : # for ... else
# вывести подитог, если только что не выводили его в цикле
# вывести подитог, если только что не выводили его в цикле
if p . TBL_PAGE_FOOTER_ROWS > 0 and not just_wrote_page_footer :
if p . TBL_PAGE_FOOTER_ROWS > 0 and not just_wrote_page_footer :
#print '---tbl last page, row =', row
# print '---tbl last page, row =', row
row + = 1 # чтоб захватить в подитог и последнюю запись тоже
row + = 1 # чтоб захватить в подитог и последнюю запись тоже
row_shift = row + add_offset
row_shift = row + add_offset
write_tbl_page_footer ( )
write_tbl_page_footer ( )
curr_height + = p . TBL_PAGE_FOOTER_HEIGHT
curr_height + = p . TBL_PAGE_FOOTER_HEIGHT
add_offset + = row - p . TBL_PAGE_FOOTER_ROWS
add_offset + = row - p . TBL_PAGE_FOOTER_ROWS
#print '---end table'
# print '---end table'
# для отладки - выйти здесь
# для отладки - выйти здесь
#return
# return
# --- !!! --------------------------------------- вывести остаток документа
# --- !!! --------------------------------------- вывести остаток документа
copy_cells (
copy_cells (
src_sheet , dst_sheet , style_list ,
src_sheet , dst_sheet , style_list ,
row_from = p . TBL_FOOTER_FROM ,
row_from = p . TBL_FOOTER_FROM ,
dst_row_shift = add_offset
dst_row_shift = add_offset
)
)
# добавить разрыв страницы, если остаток документа не уместится целиком
# добавить разрыв страницы, если остаток документа не уместится целиком
@ -426,13 +426,14 @@ def get_settings(src_book, sheet_name=u'settings'):
def apply_page_settings ( dst_sheet , settings ) :
def apply_page_settings ( dst_sheet , settings ) :
""" Применить параметры страницы. """
""" Применить параметры страницы. """
def setparam ( attr , key ) :
def setparam ( attr , key ) :
if key in settings :
if key in settings :
setattr ( dst_sheet , attr , settings [ key ] )
setattr ( dst_sheet , attr , settings [ key ] )
def setparam_as_inch ( attr , key ) :
def setparam_as_inch ( attr , key ) :
if key in settings :
if key in settings :
setattr ( dst_sheet , attr , settings [ key ] / 25.4 )
setattr ( dst_sheet , attr , settings [ key ] / 25.4 )
setparam ( ' portrait ' , ' PAGE_PORTRAIT ' )
setparam ( ' portrait ' , ' PAGE_PORTRAIT ' )
setparam ( ' header_str ' , ' PAGE_HEADER_STR ' )
setparam ( ' header_str ' , ' PAGE_HEADER_STR ' )
@ -448,12 +449,16 @@ def apply_page_settings(dst_sheet, settings):
def get_all_these_boring_params ( src_sheet , xls_settings ) :
def get_all_these_boring_params ( src_sheet , xls_settings ) :
""" Достает нужные настройки из словаря и проверят, некоторые вычисляет -
и всё это складывает в класс , который потом и возвращает .
Если какие - то обязательные настройки не заданы , сообщает об этом в консоль и возвращает None .
"""
"""
Достает нужные настройки из словаря и проверят , некоторые вычисляет -
и всё это складывает в класс , который потом и возвращает .
Если какие - то обязательные настройки не заданы , сообщает
об этом в консоль и возвращает None .
"""
class Params ( object ) :
class Params ( object ) :
pass
pass
p = Params ( )
p = Params ( )
# строка контента таблицы - обязательно
# строка контента таблицы - обязательно
@ -507,7 +512,8 @@ def get_all_these_boring_params(src_sheet, xls_settings):
# высота в строках
# высота в строках
p . TBL_PAGE_FOOTER_ROWS = int ( p . TBL_PAGE_FOOTER_TO - p . TBL_PAGE_FOOTER_FROM + 1 )
p . TBL_PAGE_FOOTER_ROWS = int ( p . TBL_PAGE_FOOTER_TO - p . TBL_PAGE_FOOTER_FROM + 1 )
# высота в twips
# высота в twips
p . TBL_PAGE_FOOTER_HEIGHT = sum_src_heights ( src_sheet , p . TBL_PAGE_FOOTER_FROM , p . TBL_PAGE_FOOTER_TO )
p . TBL_PAGE_FOOTER_HEIGHT = sum_src_heights ( src_sheet , p . TBL_PAGE_FOOTER_FROM ,
p . TBL_PAGE_FOOTER_TO )
else :
else :
p . TBL_PAGE_FOOTER_ROWS = 0
p . TBL_PAGE_FOOTER_ROWS = 0
p . TBL_PAGE_FOOTER_HEIGHT = 0
p . TBL_PAGE_FOOTER_HEIGHT = 0