tum 2 天之前
父节点
当前提交
49a52fb769
共有 5 个文件被更改,包括 2697 次插入1 次删除
  1. 694 0
      app/core/management/commands/seed_all_mock_models.py
  2. 二进制
      app/report/coi_templates.xlsx
  3. 1 1
      app/report/views.py
  4. 1001 0
      data_ms.csv
  5. 1001 0
      e_master_view.csv

+ 694 - 0
app/core/management/commands/seed_all_mock_models.py

@@ -0,0 +1,694 @@
1
+import json
2
+from decimal import Decimal
3
+
4
+from django.apps import apps
5
+from django.contrib.auth import get_user_model
6
+from django.core.management.base import BaseCommand
7
+from django.db import connections, models, router
8
+from django.db.models.fields.files import FileField, ImageField
9
+from django.db.models.fields.related import ForeignKey, OneToOneField
10
+from django.utils import timezone
11
+
12
+from core.models import LotType
13
+
14
+
15
+MASTER_VIEW_SAMPLE_ROWS = [
16
+    {
17
+        "PRO0": "1",
18
+        "PRO1": "4070207560",
19
+        "PRO1C": "NOGUCHI SEIKI",
20
+        "PRO2": "260218548-021",
21
+        "PRO5": "1",
22
+        "PRO8": "35",
23
+        "PRO9": "-",
24
+        "PRO10": "755",
25
+        "PRO11": "65",
26
+        "PRO12": "355",
27
+        "PRO13": "WA",
28
+        "PRO14": "280",
29
+        "PRO15": "J",
30
+        "PRO16": "8",
31
+        "PRO17": "B",
32
+        "PRO18": "57A",
33
+        "PRO21": "0",
34
+        "PRO25": "2026-02-18 00:00:00.000",
35
+        "PRO27": "0",
36
+        "P2": "15578",
37
+        "PRO6": "57000",
38
+        "SPEED": "500",
39
+        "PRO-TOOL": "PA54508-02BANANAS",
40
+        "PRO4": "2100030080-220",
41
+        "MC11": "35",
42
+        "MC12": "DISK",
43
+        "MC14": "755",
44
+        "MC15": "65",
45
+        "MC16": "355",
46
+        "MC19": "WA",
47
+        "MC20": "280",
48
+        "MC21": "J",
49
+        "MC22": "8",
50
+        "MC23": "B",
51
+        "MC24": "57A",
52
+        "MP45": "OUT",
53
+        "MP49": " ",
54
+        "MI13": "1",
55
+        "TC": "4070207560",
56
+        "MI14": "01",
57
+        "MI15": "23",
58
+        "MI16": "280",
59
+        "MI17": "J",
60
+        "MI18": "23",
61
+        "MI19": "52",
62
+        "MI20": "0",
63
+        "MI21": "NULL",
64
+        "MI22": "0",
65
+        "MI23": "0",
66
+        "MI31": "NULL",
67
+        "MI33": "NULL",
68
+        "INSAGM": "NULL",
69
+        "MARAGM": "NULL",
70
+        "MI53": "Q195",
71
+        "MI55": "Q195",
72
+        "MI36": "000000000",
73
+        "MI39": "000",
74
+        "MI24": "0",
75
+        "Ind1": "NULL",
76
+        "Ind2": "NULL",
77
+        "Ind3": "NULL",
78
+        "AGR1": "",
79
+        "AGR2": "",
80
+        "ob_Condition": "RH-60Kg",
81
+        "Japanese_CustomerName": "野口精機",
82
+    },
83
+    {
84
+        "PRO0": "1",
85
+        "PRO1": "4070207560",
86
+        "PRO1C": "NOGUCHI SEIKI",
87
+        "PRO2": "260218549-022",
88
+        "PRO5": "1",
89
+        "PRO8": "35",
90
+        "PRO9": "-",
91
+        "PRO10": "755",
92
+        "PRO11": "65",
93
+        "PRO12": "355",
94
+        "PRO13": "WA",
95
+        "PRO14": "280",
96
+        "PRO15": "J",
97
+        "PRO16": "8",
98
+        "PRO17": "B",
99
+        "PRO18": "57A",
100
+        "PRO21": "0",
101
+        "PRO25": "2026-02-18 00:00:00.000",
102
+        "PRO27": "0",
103
+        "P2": "15578",
104
+        "PRO6": "57000",
105
+        "SPEED": "500",
106
+        "PRO-TOOL": "PA54508-02BANANAS",
107
+        "PRO4": "2100030080-230",
108
+        "MC11": "35",
109
+        "MC12": "DISK",
110
+        "MC14": "755",
111
+        "MC15": "65",
112
+        "MC16": "355",
113
+        "MC19": "WA",
114
+        "MC20": "280",
115
+        "MC21": "J",
116
+        "MC22": "8",
117
+        "MC23": "B",
118
+        "MC24": "57A",
119
+        "MP45": "OUT",
120
+        "MP49": " ",
121
+        "MI13": "1",
122
+        "TC": "4070207560",
123
+        "MI14": "01",
124
+        "MI15": "23",
125
+        "MI16": "280",
126
+        "MI17": "J",
127
+        "MI18": "23",
128
+        "MI19": "52",
129
+        "MI20": "0",
130
+        "MI21": "NULL",
131
+        "MI22": "0",
132
+        "MI23": "0",
133
+        "MI31": "NULL",
134
+        "MI33": "NULL",
135
+        "INSAGM": "NULL",
136
+        "MARAGM": "NULL",
137
+        "MI53": "Q195",
138
+        "MI55": "Q195",
139
+        "MI36": "000000000",
140
+        "MI39": "000",
141
+        "MI24": "0",
142
+        "Ind1": "NULL",
143
+        "Ind2": "NULL",
144
+        "Ind3": "NULL",
145
+        "AGR1": "",
146
+        "AGR2": "",
147
+        "ob_Condition": "RH-60Kg",
148
+        "Japanese_CustomerName": "野口精機",
149
+    },
150
+    {
151
+        "PRO0": "1",
152
+        "PRO1": "4070207551",
153
+        "PRO1C": "NOGUCHI SEIKI",
154
+        "PRO2": "260218548-019",
155
+        "PRO5": "1",
156
+        "PRO8": "35",
157
+        "PRO9": "-",
158
+        "PRO10": "755",
159
+        "PRO11": "65",
160
+        "PRO12": "355",
161
+        "PRO13": "WA",
162
+        "PRO14": "280",
163
+        "PRO15": "K+",
164
+        "PRO16": "8",
165
+        "PRO17": "B",
166
+        "PRO18": "57A",
167
+        "PRO21": "0",
168
+        "PRO25": "2026-02-18 00:00:00.000",
169
+        "PRO27": "0",
170
+        "P2": "15826",
171
+        "PRO6": "57000",
172
+        "SPEED": "500",
173
+        "PRO-TOOL": "PA54508-01BANAARI",
174
+        "PRO4": "2100030080-200",
175
+        "MC11": "35",
176
+        "MC12": "DISK",
177
+        "MC14": "755",
178
+        "MC15": "65",
179
+        "MC16": "355",
180
+        "MC19": "WA",
181
+        "MC20": "280",
182
+        "MC21": "K+",
183
+        "MC22": "8",
184
+        "MC23": "B",
185
+        "MC24": "57A",
186
+        "MP45": "OUT",
187
+        "MP49": "NULL",
188
+        "MI13": "1",
189
+        "TC": "4070207551",
190
+        "MI14": "01",
191
+        "MI15": "23",
192
+        "MI16": "280",
193
+        "MI17": "K+",
194
+        "MI18": "41",
195
+        "MI19": "67",
196
+        "MI20": "0",
197
+        "MI21": "0",
198
+        "MI22": "0",
199
+        "MI23": "0",
200
+        "MI31": "NULL",
201
+        "MI33": "NULL",
202
+        "INSAGM": "NULL",
203
+        "MARAGM": "NULL",
204
+        "MI53": "Q195",
205
+        "MI55": "Q195",
206
+        "MI36": "000000000",
207
+        "MI39": "000",
208
+        "MI24": "0",
209
+        "Ind1": "NULL",
210
+        "Ind2": "NULL",
211
+        "Ind3": "NULL",
212
+        "AGR1": "",
213
+        "AGR2": "",
214
+        "ob_Condition": "RH-60Kg",
215
+        "Japanese_CustomerName": "野口精機",
216
+    },
217
+]
218
+
219
+DATA_MS_SAMPLE_ROWS = [
220
+    {
221
+        "row_no": "1",
222
+        "dsize": "205.76",
223
+        "tsize": "19.12",
224
+        "hsize": "0",
225
+        "created_at": "2019-02-12 14:34:57.680",
226
+        "updated_at": "2019-02-12 14:34:57.680",
227
+        "lot_no": "181-38043F",
228
+        "machine_id": "27",
229
+        "code": "1-3668-4196-6",
230
+        "emp_id": "20191",
231
+        "weight": "0.152",
232
+        "devid": "NULL",
233
+        "tpoint1": "705.29",
234
+        "tpoint2": "20.35",
235
+        "tpoint3": "20.35",
236
+        "tpoint4": "0.25",
237
+        "tpoint1ok": "NG",
238
+        "tpoint2ok": "NG",
239
+        "tpoint3ok": "NG",
240
+        "tpoint4ok": "NG",
241
+        "tdiff": "705.04",
242
+        "tmin": "0.25",
243
+        "tmax": "705.29",
244
+        "hdev": "",
245
+        "hsizeproxy": "+1.07",
246
+        "shift": "NULL",
247
+        "mode": "NULL",
248
+        "cal_mode": "0",
249
+        "dsizeOk": "NG",
250
+        "tsizeOk": "NG",
251
+        "hsizeOk": "NG",
252
+    },
253
+    {
254
+        "row_no": "2",
255
+        "dsize": "5.07",
256
+        "tsize": "0.49",
257
+        "hsize": "38.6",
258
+        "created_at": "2019-02-12 14:45:18.633",
259
+        "updated_at": "2019-02-12 14:45:18.633",
260
+        "lot_no": "181-38043F",
261
+        "machine_id": "26",
262
+        "code": "1-3668-4196-6",
263
+        "emp_id": "20191",
264
+        "weight": "8.16",
265
+        "devid": "NULL",
266
+        "tpoint1": "43.5",
267
+        "tpoint2": "43.5",
268
+        "tpoint3": "43.5",
269
+        "tpoint4": "0.49",
270
+        "tpoint1ok": "NG",
271
+        "tpoint2ok": "NG",
272
+        "tpoint3ok": "NG",
273
+        "tpoint4ok": "NG",
274
+        "tdiff": "43.01",
275
+        "tmin": "0.49",
276
+        "tmax": "43.5",
277
+        "hdev": "",
278
+        "hsizeproxy": "OK",
279
+        "shift": "NULL",
280
+        "mode": "NULL",
281
+        "cal_mode": "0",
282
+        "dsizeOk": "NG",
283
+        "tsizeOk": "NG",
284
+        "hsizeOk": "NG",
285
+    },
286
+    {
287
+        "row_no": "1",
288
+        "dsize": "25.682",
289
+        "tsize": "25.682",
290
+        "hsize": "25.568",
291
+        "created_at": "2019-02-12 16:35:21.570",
292
+        "updated_at": "2019-02-12 16:35:21.570",
293
+        "lot_no": "11808915",
294
+        "machine_id": "25",
295
+        "code": "1-9000-3035-3",
296
+        "emp_id": "20191",
297
+        "weight": "0.368",
298
+        "devid": "NULL",
299
+        "tpoint1": "0",
300
+        "tpoint2": "0",
301
+        "tpoint3": "0",
302
+        "tpoint4": "0",
303
+        "tpoint1ok": "null",
304
+        "tpoint2ok": "null",
305
+        "tpoint3ok": "null",
306
+        "tpoint4ok": "null",
307
+        "tdiff": "0",
308
+        "tmin": "0",
309
+        "tmax": "0",
310
+        "hdev": "NULL",
311
+        "hsizeproxy": "NULL",
312
+        "shift": "NULL",
313
+        "mode": "NULL",
314
+        "cal_mode": "0",
315
+        "dsizeOk": "NG",
316
+        "tsizeOk": "NG",
317
+        "hsizeOk": "NG",
318
+    },
319
+]
320
+
321
+
322
+class Command(BaseCommand):
323
+    help = "Create missing tables for project models and seed mock rows for empty tables."
324
+
325
+    target_app_labels = ("auth", "core", "legacy", "sysadmin")
326
+    excluded_tables = {
327
+        "auth_group",
328
+        "auth_group_permissions",
329
+        "auth_permission",
330
+        "auth_user_groups",
331
+        "auth_user_user_permissions",
332
+        "django_admin_log",
333
+        "django_content_type",
334
+        "django_migrations",
335
+        "django_session",
336
+    }
337
+
338
+    def add_arguments(self, parser):
339
+        parser.add_argument(
340
+            "--target-count",
341
+            type=int,
342
+            default=1,
343
+            help="Minimum number of rows to ensure for each project table.",
344
+        )
345
+
346
+    def handle(self, *args, **options):
347
+        self._seed_index = 1
348
+        self._active_seed_stack = set()
349
+        self._target_count = max(options["target_count"], 1)
350
+
351
+        models_to_process = self.get_target_models()
352
+        self.create_missing_tables(models_to_process)
353
+
354
+        created_rows = 0
355
+        for model in models_to_process:
356
+            if model._meta.db_table in self.excluded_tables:
357
+                continue
358
+            created_rows += self.ensure_target_rows(model, self._target_count)
359
+
360
+        self.stdout.write(
361
+            self.style.SUCCESS(
362
+                f"Seed completed. Ensured tables for {len(models_to_process)} models and created {created_rows} seed rows."
363
+            )
364
+        )
365
+
366
+    def get_target_models(self):
367
+        selected = []
368
+        seen = set()
369
+
370
+        user_model = get_user_model()
371
+        selected.append(user_model)
372
+        seen.add((user_model._meta.app_label, user_model._meta.model_name))
373
+
374
+        for app_label in self.target_app_labels:
375
+            app_config = apps.get_app_config(app_label)
376
+            for model in app_config.get_models():
377
+                key = (model._meta.app_label, model._meta.model_name)
378
+                if key in seen:
379
+                    continue
380
+                selected.append(model)
381
+                seen.add(key)
382
+
383
+        lot_type_key = (LotType._meta.app_label, LotType._meta.model_name)
384
+        if lot_type_key not in seen:
385
+            selected.append(LotType)
386
+
387
+        return selected
388
+
389
+    def get_database_objects(self):
390
+        cache = {}
391
+        for alias in connections:
392
+            connection = connections[alias]
393
+            with connection.cursor() as cursor:
394
+                cache[alias] = {info.name for info in connection.introspection.get_table_list(cursor)}
395
+        return cache
396
+
397
+    def create_missing_tables(self, models_to_process):
398
+        existing = self.get_database_objects()
399
+        pending = []
400
+        for model in models_to_process:
401
+            alias = router.db_for_write(model) or "default"
402
+            if model._meta.db_table in self.excluded_tables:
403
+                continue
404
+            if model._meta.db_table not in existing.get(alias, set()):
405
+                pending.append(model)
406
+
407
+        while pending:
408
+            progress = False
409
+            next_pending = []
410
+
411
+            for model in pending:
412
+                alias = router.db_for_write(model) or "default"
413
+                dependencies_ready = True
414
+                for field in model._meta.local_fields:
415
+                    if not isinstance(field, (ForeignKey, OneToOneField)):
416
+                        continue
417
+                    related_model = field.related_model
418
+                    if not related_model:
419
+                        continue
420
+                    related_table = related_model._meta.db_table
421
+                    related_alias = router.db_for_write(related_model) or "default"
422
+                    if related_table in self.excluded_tables:
423
+                        continue
424
+                    if related_table not in existing.get(related_alias, set()):
425
+                        dependencies_ready = False
426
+                        break
427
+
428
+                if not dependencies_ready:
429
+                    next_pending.append(model)
430
+                    continue
431
+
432
+                connection = connections[alias]
433
+                with connection.schema_editor() as schema_editor:
434
+                    schema_editor.create_model(model)
435
+                existing.setdefault(alias, set()).add(model._meta.db_table)
436
+                progress = True
437
+                self.stdout.write(f"Created table for {model._meta.label} on {alias} -> {model._meta.db_table}")
438
+
439
+            if not progress:
440
+                stalled = ", ".join(model._meta.label for model in next_pending)
441
+                raise RuntimeError(f"Unable to create tables due to unresolved dependencies: {stalled}")
442
+
443
+            pending = next_pending
444
+
445
+    def ensure_target_rows(self, model, target_count):
446
+        if model._meta.db_table in self.excluded_tables:
447
+            return 0
448
+
449
+        alias = router.db_for_write(model) or "default"
450
+        current_count = model._default_manager.using(alias).count()
451
+        rows_to_create = max(target_count - current_count, 0)
452
+
453
+        if rows_to_create == 0:
454
+            return 0
455
+
456
+        label = model._meta.label
457
+        if label in self._active_seed_stack:
458
+            return 0
459
+
460
+        self._active_seed_stack.add(label)
461
+        try:
462
+            created = 0
463
+            for row_offset in range(rows_to_create):
464
+                instance = model()
465
+                value_index = self._seed_index
466
+
467
+                for field in model._meta.local_fields:
468
+                    if field.auto_created and not field.concrete:
469
+                        continue
470
+
471
+                    if getattr(field, "auto_now", False) or getattr(field, "auto_now_add", False):
472
+                        continue
473
+
474
+                    if isinstance(field, (ForeignKey, OneToOneField)):
475
+                        related_value = self.get_related_value(field, row_offset, target_count)
476
+                        setattr(instance, field.attname, related_value)
477
+                        continue
478
+
479
+                    if field.primary_key and isinstance(field, (models.AutoField, models.BigAutoField)):
480
+                        continue
481
+
482
+                    value = self.build_field_value(model, field, value_index)
483
+                    if value is not None or not field.null:
484
+                        setattr(instance, field.attname, value)
485
+
486
+                instance.save(using=alias, force_insert=True)
487
+                self._seed_index += 1
488
+                created += 1
489
+
490
+            if created:
491
+                self.stdout.write(f"Seeded {created} rows for {label} on {alias} -> {model._meta.db_table}")
492
+            return created
493
+        finally:
494
+            self._active_seed_stack.remove(label)
495
+
496
+    def get_related_value(self, field, row_offset, target_count):
497
+        related_model = field.related_model
498
+        if related_model is None:
499
+            return None
500
+
501
+        alias = router.db_for_write(related_model) or "default"
502
+
503
+        if related_model._meta.db_table not in self.excluded_tables:
504
+            self.ensure_target_rows(related_model, target_count)
505
+
506
+        queryset = related_model._default_manager.using(alias).order_by(related_model._meta.pk.attname)
507
+        related_instances = list(queryset)
508
+        if not related_instances:
509
+            return None
510
+
511
+        if isinstance(field, OneToOneField):
512
+            index = row_offset if row_offset < len(related_instances) else len(related_instances) - 1
513
+        else:
514
+            index = row_offset % len(related_instances)
515
+
516
+        related_instance = related_instances[index]
517
+        return getattr(related_instance, related_model._meta.pk.attname)
518
+
519
+    def get_master_sample_row(self, value_index):
520
+        return MASTER_VIEW_SAMPLE_ROWS[(value_index - 1) % len(MASTER_VIEW_SAMPLE_ROWS)]
521
+
522
+    def get_sample_value(self, model, field, value_index):
523
+        model_name = model._meta.model_name
524
+
525
+        if model_name in {"mgmasterview", "vmasterview", "belmasterview", "emasterview"}:
526
+            row = self.get_master_sample_row(value_index)
527
+            if field.name == "PRO0":
528
+                return str(value_index)
529
+            keys = [field.db_column, field.name]
530
+            for key in keys:
531
+                if key and key in row:
532
+                    return self.coerce_sample_value(field, row[key])
533
+
534
+        if model_name in {"datams", "datamslot2210062522"}:
535
+            row = DATA_MS_SAMPLE_ROWS[(value_index - 1) % len(DATA_MS_SAMPLE_ROWS)]
536
+            master_row = self.get_master_sample_row(value_index)
537
+            if field.name == "lot_no":
538
+                return self.coerce_sample_value(field, master_row["PRO2"])
539
+            if field.name == "code":
540
+                return self.coerce_sample_value(field, master_row["PRO1"])
541
+            keys = [field.db_column, field.name]
542
+            for key in keys:
543
+                if not key:
544
+                    continue
545
+                for candidate_key, candidate_value in row.items():
546
+                    if candidate_key.lower() == key.lower():
547
+                        return self.coerce_sample_value(field, candidate_value)
548
+
549
+        if model_name == "data":
550
+            row = DATA_MS_SAMPLE_ROWS[(value_index - 1) % len(DATA_MS_SAMPLE_ROWS)]
551
+            master_row = self.get_master_sample_row(value_index)
552
+            direct_map = {
553
+                "row_no": row.get("row_no"),
554
+                "lot_no": master_row.get("PRO2"),
555
+                "code": master_row.get("PRO1"),
556
+                "created_at": row.get("created_at"),
557
+                "updated_at": row.get("updated_at"),
558
+                "machine_id": row.get("machine_id"),
559
+                "r_type": "CSV",
560
+                "grade": row.get("dsizeOk"),
561
+                "rgrade": row.get("hsizeOk"),
562
+                "header": "CSV",
563
+                "ndata": "1",
564
+                "sub_order": row.get("row_no"),
565
+                "p1": row.get("dsize"),
566
+                "p2": row.get("tsize"),
567
+                "p3": row.get("hsize"),
568
+                "p4": row.get("weight"),
569
+                "p5": row.get("tpoint1"),
570
+                "p6": row.get("tpoint2"),
571
+                "p7": row.get("tpoint3"),
572
+                "p8": row.get("tpoint4"),
573
+                "p9": row.get("tmin"),
574
+                "p10": row.get("tmax"),
575
+            }
576
+            if field.name == "avg":
577
+                try:
578
+                    average = (float(row["dsize"]) + float(row["tsize"]) + float(row["hsize"])) / 3
579
+                    return average
580
+                except Exception:
581
+                    return None
582
+            if field.name in direct_map:
583
+                return self.coerce_sample_value(field, direct_map[field.name])
584
+
585
+        return None
586
+
587
+    def coerce_sample_value(self, field, raw_value):
588
+        if raw_value is None:
589
+            return None
590
+
591
+        if isinstance(raw_value, str):
592
+            value = raw_value.strip()
593
+            if value.lower() in {"null", ""}:
594
+                return None if field.null else ""
595
+        else:
596
+            value = raw_value
597
+
598
+        if isinstance(field, models.DateTimeField):
599
+            return timezone.datetime.fromisoformat(value.replace(" ", "T"))
600
+
601
+        if isinstance(field, models.DateField):
602
+            return timezone.datetime.fromisoformat(value.replace(" ", "T")).date()
603
+
604
+        if isinstance(field, models.DecimalField):
605
+            return Decimal(str(value))
606
+
607
+        if isinstance(field, models.FloatField):
608
+            return float(value)
609
+
610
+        if isinstance(field, (models.IntegerField, models.BigIntegerField, models.SmallIntegerField)):
611
+            return int(float(value))
612
+
613
+        return value
614
+
615
+    def build_field_value(self, model, field, value_index):
616
+        sample_value = self.get_sample_value(model, field, value_index)
617
+        if sample_value is not None:
618
+            return sample_value
619
+
620
+        if field.has_default():
621
+            default = field.get_default()
622
+            return default() if callable(default) else default
623
+
624
+        if getattr(field, "choices", None):
625
+            return field.choices[0][0]
626
+
627
+        model_key = model._meta.model_name
628
+        field_key = field.name.lower()
629
+
630
+        if isinstance(field, models.JSONField):
631
+            if "template" in field_key:
632
+                return ["dimension", "hardness_out", "centering"]
633
+            return {"model": model_key, "field": field.name, "seed": value_index}
634
+
635
+        if isinstance(field, (ImageField, FileField)):
636
+            filename = f"{model_key}-{value_index}.png" if isinstance(field, ImageField) else f"{model_key}-{value_index}.dat"
637
+            return f"mock/{filename}"
638
+
639
+        if isinstance(field, models.EmailField):
640
+            return f"{model_key}{value_index}@example.com"
641
+
642
+        if isinstance(field, models.DateTimeField):
643
+            return timezone.now()
644
+
645
+        if isinstance(field, models.DateField):
646
+            return timezone.now().date()
647
+
648
+        if isinstance(field, models.TimeField):
649
+            return timezone.now().time().replace(microsecond=0)
650
+
651
+        if isinstance(field, models.DecimalField):
652
+            whole = max(field.max_digits - field.decimal_places, 1)
653
+            number = str((value_index % (10 ** min(whole, 4))) + 1)
654
+            decimal_part = ("12" * max(field.decimal_places, 1))[: field.decimal_places]
655
+            return Decimal(f"{number}.{decimal_part}") if field.decimal_places else Decimal(number)
656
+
657
+        if isinstance(field, models.FloatField):
658
+            return float(value_index) + 0.25
659
+
660
+        if isinstance(field, models.BooleanField):
661
+            return True
662
+
663
+        if isinstance(field, (models.IntegerField, models.BigIntegerField, models.SmallIntegerField)):
664
+            return value_index
665
+
666
+        if isinstance(field, models.TextField):
667
+            return f"Mock {model._meta.verbose_name} text {value_index}"
668
+
669
+        if isinstance(field, models.CharField):
670
+            if field.primary_key:
671
+                if field.max_length <= 12:
672
+                    value = str(1000000000 + value_index)[-field.max_length:]
673
+                else:
674
+                    suffix = str(value_index)
675
+                    prefix_length = max(field.max_length - len(suffix) - 1, 1)
676
+                    value = f"{model_key[:prefix_length].upper()}-{suffix}"
677
+            elif "json" in field_key:
678
+                value = json.dumps({"seed": value_index})
679
+            elif "email" in field_key:
680
+                value = f"{model_key}{value_index}@example.com"
681
+            elif "file" in field_key or "picture" in field_key or "drawing" in field_key:
682
+                value = f"mock/{model_key}-{field.name}-{value_index}.dat"
683
+            elif field_key == "password":
684
+                value = "pbkdf2_sha256$600000$Xn2U8rTJlAmDG6TaLgb9WQ$ElMUGivveb2WqmckmheHTb8jaxVuu1NJ2/QAAnpvZ7w="
685
+            elif field_key == "username":
686
+                value = f"{model_key}_{value_index}"
687
+            else:
688
+                value = f"{model_key}_{field.name}_{value_index}"
689
+            return value[: field.max_length]
690
+
691
+        if field.null:
692
+            return None
693
+
694
+        return f"{model_key}_{field.name}_{value_index}"

二进制
app/report/coi_templates.xlsx


+ 1 - 1
app/report/views.py

@@ -1195,7 +1195,7 @@ def create_coi_file(lot_no, sheets, user, md):
1195 1195
     data = {
1196 1196
         # "code": first_result.PRO1 if first_result else "-",
1197 1197
         "code": code,
1198
-        "customer": f"{first_result.Japanese_CustomerName + ' 御中' if first_result and first_result.Japanese_CustomerName != '' else ''}  {first_result.PRO1C if first_result else '-'}",
1198
+        "customer": f"{first_result.Japanese_CustomerName + ' 御中     ' if first_result and first_result.Japanese_CustomerName != '' else ''}  {first_result.PRO1C if first_result else '-'}",
1199 1199
         # "inspect_date": inspect_date.strftime('%Y/%m/%d') if inspect_date else "-",
1200 1200
         "lot_no": lot_no,
1201 1201
         "size": size_str,

文件差异内容过多而无法显示
+ 1001 - 0
data_ms.csv


文件差异内容过多而无法显示
+ 1001 - 0
e_master_view.csv