|
1 | 1 | import logging |
2 | 2 | from collections import OrderedDict |
3 | 3 |
|
| 4 | +from openpyxl.cell.cell import ILLEGAL_CHARACTERS_RE |
| 5 | + |
4 | 6 | from partner_programs.models import PartnerProgramUserProfile |
5 | 7 | from project_rates.models import Criteria, ProjectScore |
6 | 8 |
|
@@ -132,6 +134,34 @@ def get_project_scores_info(self) -> dict[str, str]: |
132 | 134 | ("team_size", "Количество человек в команде"), |
133 | 135 | ("leader_full_name", "Имя фамилия лидера"), |
134 | 136 | ] |
| 137 | +EXCEL_CELL_MAX = 32767 # лимит символов в ячейке Excel |
| 138 | + |
| 139 | + |
| 140 | +def sanitize_excel_value(value): |
| 141 | + """ |
| 142 | + Приводит значение к безопасному для openpyxl виду: |
| 143 | + - None -> "" |
| 144 | + - для строк: вычищает запрещённые символы, нормализует переносы строк, |
| 145 | + и обрезает до лимита Excel (32767). |
| 146 | + - для чисел/булевых оставляет как есть. |
| 147 | + """ |
| 148 | + if value is None: |
| 149 | + return "" |
| 150 | + |
| 151 | + if isinstance(value, (int, float, bool)): |
| 152 | + return value |
| 153 | + |
| 154 | + text = str(value) |
| 155 | + # нормализуем переносы (на всякий случай) |
| 156 | + text = text.replace("\r\n", "\n").replace("\r", "\n") |
| 157 | + # выкидываем запрещённые символы (в т.ч. \x0B) |
| 158 | + text = ILLEGAL_CHARACTERS_RE.sub(" ", text) |
| 159 | + |
| 160 | + # Excel не примет строки длиннее 32767 |
| 161 | + if len(text) > EXCEL_CELL_MAX: |
| 162 | + text = text[: EXCEL_CELL_MAX - 3] + "..." |
| 163 | + |
| 164 | + return text |
135 | 165 |
|
136 | 166 |
|
137 | 167 | def _leader_full_name(user): |
|
0 commit comments