Coverage for backend/django/Economics/shared/model_base.py: 98%

36 statements  

« prev     ^ index     » next       coverage.py v7.10.7, created at 2026-06-23 21:51 +0000

1from django.core.exceptions import ValidationError 

2from django.db import models 

3 

4from core.managers import AccessControlManager 

5 

6 

7def _validate_same_flowsheet(errors, field_name, value, flowsheet_id): 

8 if value is not None and value.flowsheet_id != flowsheet_id: 

9 errors[field_name] = "Referenced row must belong to the same flowsheet." 

10 

11 

12class FlowsheetScopedEconomicsModel(models.Model): 

13 same_flowsheet_fields: tuple[str, ...] = () 

14 

15 class Meta: 

16 abstract = True 

17 

18 def clean(self): 

19 super().clean() 

20 errors = {} 

21 for field_name in self.same_flowsheet_fields: 

22 field_id_name = f"{field_name}_id" 

23 if getattr(self, field_id_name, None) is None: 

24 continue 

25 _validate_same_flowsheet(errors, field_name, getattr(self, field_name), self.flowsheet_id) 

26 if errors: 

27 raise ValidationError(errors) 

28 

29 def save(self, *args, **kwargs): 

30 self.full_clean() 

31 return super().save(*args, **kwargs) 

32 

33 

34class GlobalReferenceDataManager(AccessControlManager): 

35 """Access-control-compatible manager for global read-only reference data. 

36 

37 Project validation expects models to use ``AccessControlManager`` or 

38 ``SoftDeleteManager``. Stats NZ index rows are intentionally not 

39 flowsheet-owned, so this manager preserves that contract without filtering 

40 reads or pinning writes to a request flowsheet. These models are populated 

41 by developer-run management commands, not ordinary user APIs. 

42 """ 

43 

44 def create(self, **kwargs): 

45 return super(AccessControlManager, self).create(**kwargs) 

46 

47 def bulk_create(self, objs, **kwargs): 

48 return super(AccessControlManager, self).bulk_create(objs, **kwargs) 

49 

50 def get_queryset(self): 

51 return super(AccessControlManager, self).get_queryset() 

52 

53 

54class GlobalReferenceDataModel(models.Model): 

55 """Reference-data base that preserves model validation without flowsheet scoping.""" 

56 

57 class Meta: 

58 abstract = True 

59 

60 def save(self, *args, **kwargs): 

61 self.full_clean() 

62 return super().save(*args, **kwargs)