일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
- Self ERP
- pip 설치
- django rank
- ERP
- pyside6
- optimization page
- 중량 관리
- Python
- tensorflow
- django role based
- 장고로 ERP
- django drf
- 파이썬
- django erp
- channels
- query 최적화
- 재고 관리
- materialized
- test drive development
- django test
- uiload
- orm 최적화
- django
- pyside6 ui
- QApplication
- 장고
- qpa_plugin
- qwindows.dll
- 페이지 최적화
- pip 오류
- Today
- Total
취미삼아 배우는 프로그래밍
model.py에는 온갖 정성을 쏟아붓자. 본문
혼자서 만드는 마감정산 시스템(Django)
장고 코딩하다 막혀서 풀어보는 #리뷰 자가 코드 리뷰 (영감을 얻어 가셨으면 합니다.) 1. 모델(전체) from django.db import models from jsonfield import JSONField from django.db.models import F, Sum, Coun..
nadure.tistory.com
위의 개인 프로젝트를 아직도 진행하고 있다.
확실히 장고를 근 1년간 다뤄서 그런지, 시간이 많이 들 뿐 딱히 막히진 않는다. ㅎㅎ 그래도 잘 하는거 같은 느낌은 안든다. 잘 되는거 같은 느낌뿐.
코드를 깨끗하게 작성못하는건 어쩔 수 없는것 같다.
이제 아주 메인 기능들은 거진 다 된 것 같아서
잠시 중간 정리를 하려한다.
자 리뷰 시작.
1. 전체코드
# modesls.py
from django.db import models
from django.db.models import F, Sum, Count, Case, When
from django.db.models.signals import pre_save, post_delete, pre_delete
from django.dispatch import receiver
from django.utils import timezone
import os
import shutil
import datetime
import math
from decimal import Decimal
from django.db.models import Q
# ------- helper functions
def round_half_up(n, decimals=0):
multiplier = Decimal(10) ** decimals
return math.floor(n*multiplier + Decimal(0.5)) / multiplier
# 면적 계산 헬퍼 함수
def areaHelper(instance):
return round_half_up( ((instance.w1_value + instance.w2_value + instance.w3_value) * instance.h_value / Decimal(1000000)),2)
def file_move(source, destination):
"""
Copy file from source to dest. dest can include an absolute or relative path
If the path doesn't exist, it gets created
"""
dest_dir = os.path.dirname(destination)
try:
os.makedirs(dest_dir)
except os.error as e:
pass #Assume it exists. This could fail if you don't have permissions, etc...
shutil.move(source, destination)
def get_completed_excel_upload_path(instance, filename):
return os.path.join(
'completed_file',
str(instance.target_coat_company.coated_company),
str(instance.target_date.year),
str(instance.target_date.month),
str(instance.target_date.day),
f'{instance.target_coat_company.coated_company}_{instance.target_date.year}년_{instance.target_date.month}월.xlsx'
)
def get_excel_upload_path(instance, filename):
# instance.coated_company.coated_company
# instance.finishing_date.year
return os.path.join(
str(instance.coated_company.coated_company),
str(instance.worked_date.year),
str(instance.worked_date.month),
str(instance.worked_date.day),
str(filename)
)
class Month(models.TextChoices):
january = '1월'
febuary = '2월'
march = '3월'
april = '4월'
may = '5월'
june = '6월'
july = '7월'
augus = '8월'
september = '9월'
october = ' 10월'
november = ' 11월'
december = ' 12월'
# ----- Model Classes
class CoatCompanyModel(models.Model):
objects = models.Manager()
coated_company = models.CharField(max_length=25, verbose_name='코팅업체')
def __str__(self):
return self.coated_company
class ProductList(models.Model):
objects = models.Manager()
product = models.CharField(max_length=30, verbose_name='품명')
def __str__(self):
return self.product
class DataOneRow(models.Model):
# TODO > Validation 추가해야함
objects = models.Manager()
product_name = models.ForeignKey(ProductList, on_delete=models.CASCADE,)
product_category = models.CharField(max_length=20, null=True,
blank=True, default=None, verbose_name='품목구분')
w1_value = models.IntegerField(default=0, verbose_name='w1')
w2_value = models.IntegerField(default=0, verbose_name='w2')
w3_value = models.IntegerField(default=0, verbose_name='w3')
h_value = models.IntegerField(default=0, verbose_name='h')
A_value_quantity = models.IntegerField(default=0, verbose_name='A 수량')
B_value_quantity = models.IntegerField(default=0, verbose_name='B 수량')
C_value_quantity = models.IntegerField(default=0, verbose_name='C 수량')
A_Area = models.DecimalField(verbose_name='A 면적', max_digits=6, decimal_places=2, default=0)
B_Area = models.DecimalField(verbose_name='B 면적', max_digits=6, decimal_places=2, default=0)
C_Area = models.DecimalField(verbose_name='C 면적', max_digits=6, decimal_places=2, default=0)
def __str__(self):
return f'{self.product_name}/ {self.w1_value}+{self.w2_value}+{self.w3_value} x {self.h_value}'
class DetailedData(models.Model):
objects = models.Manager()
data_rows = models.ManyToManyField(DataOneRow)
first_writed = models.DateTimeField(verbose_name='최초작성시간', auto_now_add=True)
last_modified = models.DateTimeField(verbose_name='마지막변경시간', auto_now=True)
changes_log = models.CharField(verbose_name='변경내역', max_length=50)
def __str__(self):
return str(self.last_modified) + ' / ' + self.changes_log
def sumHelper(self, field):
val = self.data_rows.values(field).aggregate(Sum(field))
val = val.get(field+'__sum')
if not val:
val = Decimal(0)
return val
# if(val[field+'__sum'] == None):
# return Decimal(0)
# return Decimal(val[field+'__sum'])
@property
def a_value_quantity_sum(self):
return self.sumHelper('A_value_quantity')
@property
def b_value_quantity_sum(self):
return self.sumHelper('B_value_quantity')
@property
def c_value_quantity_sum(self):
return self.sumHelper('C_value_quantity')
@property
def A_Area_sum(self):
return round_half_up(self.sumHelper('A_Area'), 2)
@property
def B_Area_sum(self):
return round_half_up(self.sumHelper('B_Area'), 2)
@property
def C_Area_sum(self):
return round_half_up(self.sumHelper('C_Area'), 2)
@property
def AandC_Area_sum(self):
return round_half_up(self.sumHelper('A_Area') + self.sumHelper('C_Area'), 2)
@property
def total_sum(self):
return round_half_up(self.sumHelper('A_Area') + self.sumHelper('B_Area') + self.sumHelper('C_Area'), 2)
class TheOneDistrict(models.Model):
objects = models.Manager()
category = models.CharField(max_length=20, verbose_name="카테고리", default="기본값")
company = models.CharField(max_length=20, verbose_name="업체명")
location_name = models.CharField(max_length=40, verbose_name="현장명")
district = models.CharField(max_length=20, verbose_name="동")
detailData = models.ForeignKey(DetailedData, on_delete=models.CASCADE, null=True, blank=True)
def __str__(self):
return f'({self.company} . {self.location_name} . {self.district})'
class BaseData(models.Model):
objects = models.Manager()
coated_company = models.ForeignKey(CoatCompanyModel, on_delete=models.CASCADE)
one_district = models.OneToOneField(TheOneDistrict, on_delete=models.CASCADE, )
finishing_date = models.DateField(verbose_name='작업시기', default=timezone.now)
def __str__(self):
return (self.coated_company.coated_company + '/'
+ str(self.finishing_date.year) + '년/' + str(self.finishing_date.month) + '월' + ' '
+ str(self.finishing_date.day)+ '일/' + str(self.one_district))
@property
def worked_date(self):
return self.finishing_date.day
@property
def date_strftime(self):
return f'{self.finishing_date.year}년 {self.finishing_date.month}월 {self.finishing_date.day}일'
class UploadedExcelFiles(models.Model):
excel_file = models.FileField(verbose_name='업로드 파일 보관',
upload_to=get_excel_upload_path, default=None, null=True, blank=True)
worked_date = models.DateField(verbose_name='작업일', default=timezone.now)
base_data = models.ManyToManyField(BaseData)
coated_company = models.ForeignKey(CoatCompanyModel, on_delete=models.CASCADE, blank=True, null=True)
# val = self.data_rows.values(field).aggregate(Sum(field))
class CollectedFilesModel(models.Model):
# The day is set to be only 1 day.
objects = models.Manager()
target_date = models.DateField(verbose_name='통합파일 보관',)
target_coat_company = models.ForeignKey(CoatCompanyModel,
null=True, blank=True, on_delete=models.CASCADE)
completed_file = models.FileField(verbose_name='완료 파일 보관',
upload_to=get_completed_excel_upload_path, default=None, null=True, blank=True)
target_files = models.ManyToManyField(UploadedExcelFiles)
def move_file(self, source, destination):
file_move(source, destination)
def get_destination_path(self):
return get_completed_excel_upload_path(self, None)
def sumHelper(self, field):
query_string = 'base_data__one_district__detailData__data_rows__' + field
angle_list = ['ANGLE', 'ANGLE ', 'angle', 'Angle']
Q1 = Q(base_data__one_district__detailData__data_rows__product_name__product__in=angle_list)
val = self.target_files.all().aggregate(Sum(query_string))
# val1 = val[query_string+'__sum']
# val2 = self.target_files.filter(Q1).aggregate(Sum(query_string))[query_string+'__sum']
val1 = val.get(query_string+'__sum', Decimal(0))
val2 = self.target_files.filter(Q1).aggregate(Sum(query_string)).get(query_string+'__sum', Decimal(0))
if not val1:
val1 = Decimal(0)
if not val2:
val2 = Decimal(0)
return val1-val2
@property
def A_Area_sum(self):
return round_half_up(self.sumHelper('A_Area'), 2)
@property
def B_Area_sum(self):
return round_half_up(self.sumHelper('B_Area'), 2)
@property
def C_Area_sum(self):
return round_half_up(self.sumHelper('C_Area'), 2)
@property
def AandC_Area_sum(self):
return round_half_up(self.sumHelper('A_Area') + self.sumHelper('C_Area'), 2)
def _get_category_list(self):
all_list = self.target_files.all().values_list('base_data__one_district__category', flat=True)
return list(dict.fromkeys(all_list))
@property
def totalAngleSum(self):
query_string = 'base_data__one_district__detailData__data_rows__A_Area'
angle_list = ['ANGLE', 'ANGLE ', 'angle', 'Angle']
val = self.target_files.all()\
.filter(base_data__one_district__detailData__data_rows__product_name__product__in=angle_list) \
.aggregate(Sum(query_string))
if not val:
val = Decimal(0)
return round_half_up(val.get(query_string+'__sum', Decimal(0)),2)
@property
def sum_with_category_all(self):
category_list = self._get_category_list()
res = {}
for category in category_list:
res[category] = {
"A_Area":round_half_up(self._sum_with_category("A_Area", category),2),
"B_Area":round_half_up(self._sum_with_category("B_Area", category),2),
"C_Area":round_half_up(self._sum_with_category("C_Area", category),2),
"new":round_half_up(
self._sum_with_category("A_Area", category) +
self._sum_with_category("C_Area", category) , 2 ),
"total":round_half_up(
self._sum_with_category("A_Area", category) +
self._sum_with_category("B_Area", category) +
self._sum_with_category("C_Area", category) , 2 ),
"angle":round_half_up(
self._sum_with_angle_area_with_category(category), 2
)
}
return res
def _sum_with_category(self, field, category):
query_string = 'base_data__one_district__detailData__data_rows__' + field
angle_list = ['ANGLE', 'ANGLE ', 'angle', 'Angle']
Q1 = Q(base_data__one_district__category=category)
Q2 = Q(base_data__one_district__detailData__data_rows__product_name__product__in=angle_list)
val1 = self.target_files.filter(Q1).aggregate(Sum(query_string)).get(query_string+'__sum')
val2 = self.target_files.filter(Q1 & Q2).aggregate(Sum(query_string)).get(query_string+'__sum')
if not val1:
val1 = Decimal(0)
if not val2:
val2 = Decimal(0)
# val1 = self.target_files.filter(Q1).aggregate(Sum(query_string))[query_string+'__sum']
# val2 = self.target_files.filter(Q1 & Q2).aggregate(Sum(query_string))[query_string+'__sum']
return val1-val2
def _sum_with_angle_area_with_category(self, category):
query_string = 'base_data__one_district__detailData__data_rows__A_Area'
category_query_string = 'base_data__one_district__category'
angle_list = ['ANGLE', 'ANGLE ', 'angle', 'Angle']
Q1 = Q(base_data__one_district__category=category)
Q2 = Q(base_data__one_district__detailData__data_rows__product_name__product__in=angle_list)
val = self.target_files.all().filter(Q2 & Q1)\
.aggregate(Sum(query_string))
val = self.target_files.all().filter(Q2 & Q1).aggregate(Sum(query_string)).get(query_string+'__sum', Decimal(0))
if not val:
val = Decimal(0)
return val
@property
def total_sum(self):
return round_half_up(
self.sumHelper('A_Area') +
self.sumHelper('B_Area') +
self.sumHelper('C_Area') , 2)
# ----------------- Signals below
@receiver(pre_save, sender=CollectedFilesModel)
def auto_adjust_day(sender, instance, **kwargs):
if instance.target_date.day != 1:
year = instance.target_date.year
month = instance.target_date.month
instance.target_date = datetime.date(year, month, 1)
# DataOneRow를 저장하기 전 면적을 계산하고 값을 넣음
@receiver(pre_save, sender=DataOneRow)
def auto_calculate_area(sender, instance, **kwargs):
instance.A_Area = areaHelper(instance) * instance.A_value_quantity
instance.B_Area = areaHelper(instance) * instance.B_value_quantity
instance.C_Area = areaHelper(instance) * instance.C_value_quantity
@receiver(pre_delete, sender=CollectedFilesModel)
def auto_delete_file_on_delete_collected_file(sender, instance, **kwargs):
"""
Deletes file from filesystem
when corresponding `MediaFile` object is deleted.
"""
if instance.completed_file:
if os.path.isfile(instance.completed_file.path):
os.remove(instance.completed_file.path)
@receiver(pre_delete, sender=UploadedExcelFiles)
def auto_delete_file_on_delete(sender, instance, **kwargs):
"""
Deletes file from filesystem
when corresponding `MediaFile` object is deleted.
"""
if instance.excel_file:
if os.path.isfile(instance.excel_file.path):
os.remove(instance.excel_file.path)
전체코드는 그냥 훑어보는 용으로 올렸다
코드 부분부분 뜯어보기
1. 헬퍼 함수
# ------- helper functions
def round_half_up(n, decimals=0):
multiplier = Decimal(10) ** decimals
return math.floor(n*multiplier + Decimal(0.5)) / multiplier
# 면적 계산 헬퍼 함수
def areaHelper(instance):
return round_half_up( ((instance.w1_value + instance.w2_value + instance.w3_value) * instance.h_value / Decimal(1000000)),2)
def file_move(source, destination):
"""
Copy file from source to dest. dest can include an absolute or relative path
If the path doesn't exist, it gets created
"""
dest_dir = os.path.dirname(destination)
try:
os.makedirs(dest_dir)
except os.error as e:
pass #Assume it exists. This could fail if you don't have permissions, etc...
shutil.move(source, destination)
def get_completed_excel_upload_path(instance, filename):
return os.path.join(
'completed_file',
str(instance.target_coat_company.coated_company),
str(instance.target_date.year),
str(instance.target_date.month),
str(instance.target_date.day),
f'{instance.target_coat_company.coated_company}_{instance.target_date.year}년_{instance.target_date.month}월.xlsx'
)
def get_excel_upload_path(instance, filename):
# instance.coated_company.coated_company
# instance.finishing_date.year
return os.path.join(
str(instance.coated_company.coated_company),
str(instance.worked_date.year),
str(instance.worked_date.month),
str(instance.worked_date.day),
str(filename)
)
모델 가장 상단에는 헬퍼함수를 배치했다. 모 글에서는 헬퍼함수를 따로 빼서 모아다가 관리하라고 하는데, 이미 하고있는 부분도 있어서 그건 일단 나중에 정리한다 치고 위에 올렸다. 깔끔하게 코딩하는거보다 깔끔하게 돌아가는게 우선이었다. ㅠㅠ
자세히 보면 주로 들어가는 인자명이 instance인데, 해당 모델을 바로 집어넣어서 함수를 실행시키기 위해서이다.
area_helper는 말그대로 면적을 계산해서 해당 계산값을 만들어 내기 위해서 있는 함수다. 추후에 pre_save 시그널에서 이걸 써서 다른 결과 계산값을 집어넣는다.
file_move는 말그대로 파일을 옮기는 함수다. 그리고 get_excel_upload_path랑 get_excel_upload_path는 completed_file 폴더 차이인데, 뭐를 하나 안 쓰는것 같던데 혹시 몰라서 일단 남겨놨다.
진짜 할 말이 많은 부분은 round_half_up 함수다. 파이썬에는 반올림을 하는데 round라는 함수를 사용한다. 막상 문제점을 깨달았을 때는, 엑셀파일을 통째로 업로드해 데이터베이스에 적용시키고 이를 실제 엑셀 값과 비교할 때였다.
이를 해결코자, 이사이트를 참고해 위의 함수를 작성했다.(나의 경우엔 Decimal Format이어서 그렇다.)
엑셀에서의 반올림과 파이썬에서의 반올림 방식은 같지 않다. 오히려 엑셀에서의 반올림이 퇴보된 느낌.
엑셀에서의 반올림은 우리가 흔히 아는 그 반만 넘어가면 올라가는 그 방식이고,
파이썬에서의 반올림은 ROUND HALF EVEN이라고, 앞의 숫자에 따라서 결과 값이 달라지는 골 때리는 부분이 있다. 틀린 방식은 아닌것 같다만, 엑셀 돈 등의 데이터를 만지는 부분에 있어서는 가히 치명적이지 않은가 싶다.
![](https://blog.kakaocdn.net/dn/IJb4E/btqGXnIeNDK/qydQu0osMq5K4kPbnJxJ8K/img.png)
2. 모델함수
class CollectedFilesModel(models.Model):
# The day is set to be only 1 day.
objects = models.Manager()
target_date = models.DateField(verbose_name='통합파일 보관',)
target_coat_company = models.ForeignKey(CoatCompanyModel,
null=True, blank=True, on_delete=models.CASCADE)
completed_file = models.FileField(verbose_name='완료 파일 보관',
upload_to=get_completed_excel_upload_path, default=None, null=True, blank=True)
target_files = models.ManyToManyField(UploadedExcelFiles)
def move_file(self, source, destination):
file_move(source, destination)
def get_destination_path(self):
return get_completed_excel_upload_path(self, None)
def sumHelper(self, field):
query_string = 'base_data__one_district__detailData__data_rows__' + field
angle_list = ['ANGLE', 'ANGLE ', 'angle', 'Angle']
Q1 = Q(base_data__one_district__detailData__data_rows__product_name__product__in=angle_list)
val = self.target_files.all().aggregate(Sum(query_string))
# val1 = val[query_string+'__sum']
# val2 = self.target_files.filter(Q1).aggregate(Sum(query_string))[query_string+'__sum']
val1 = val.get(query_string+'__sum', Decimal(0))
val2 = self.target_files.filter(Q1).aggregate(Sum(query_string)).get(query_string+'__sum', Decimal(0))
if not val1:
val1 = Decimal(0)
if not val2:
val2 = Decimal(0)
return val1-val2
@property
def A_Area_sum(self):
return round_half_up(self.sumHelper('A_Area'), 2)
@property
def B_Area_sum(self):
return round_half_up(self.sumHelper('B_Area'), 2)
@property
def C_Area_sum(self):
return round_half_up(self.sumHelper('C_Area'), 2)
@property
def AandC_Area_sum(self):
return round_half_up(self.sumHelper('A_Area') + self.sumHelper('C_Area'), 2)
def _get_category_list(self):
all_list = self.target_files.all().values_list('base_data__one_district__category', flat=True)
return list(dict.fromkeys(all_list))
@property
def totalAngleSum(self):
query_string = 'base_data__one_district__detailData__data_rows__A_Area'
angle_list = ['ANGLE', 'ANGLE ', 'angle', 'Angle']
val = self.target_files.all()\
.filter(base_data__one_district__detailData__data_rows__product_name__product__in=angle_list) \
.aggregate(Sum(query_string))
if not val:
val = Decimal(0)
return round_half_up(val.get(query_string+'__sum', Decimal(0)),2)
@property
def sum_with_category_all(self):
category_list = self._get_category_list()
res = {}
for category in category_list:
res[category] = {
"A_Area":round_half_up(self._sum_with_category("A_Area", category),2),
"B_Area":round_half_up(self._sum_with_category("B_Area", category),2),
"C_Area":round_half_up(self._sum_with_category("C_Area", category),2),
"new":round_half_up(
self._sum_with_category("A_Area", category) +
self._sum_with_category("C_Area", category) , 2 ),
"total":round_half_up(
self._sum_with_category("A_Area", category) +
self._sum_with_category("B_Area", category) +
self._sum_with_category("C_Area", category) , 2 ),
"angle":round_half_up(
self._sum_with_angle_area_with_category(category), 2
)
}
return res
def _sum_with_category(self, field, category):
query_string = 'base_data__one_district__detailData__data_rows__' + field
angle_list = ['ANGLE', 'ANGLE ', 'angle', 'Angle']
Q1 = Q(base_data__one_district__category=category)
Q2 = Q(base_data__one_district__detailData__data_rows__product_name__product__in=angle_list)
val1 = self.target_files.filter(Q1).aggregate(Sum(query_string)).get(query_string+'__sum')
val2 = self.target_files.filter(Q1 & Q2).aggregate(Sum(query_string)).get(query_string+'__sum')
if not val1:
val1 = Decimal(0)
if not val2:
val2 = Decimal(0)
# val1 = self.target_files.filter(Q1).aggregate(Sum(query_string))[query_string+'__sum']
# val2 = self.target_files.filter(Q1 & Q2).aggregate(Sum(query_string))[query_string+'__sum']
return val1-val2
def _sum_with_angle_area_with_category(self, category):
query_string = 'base_data__one_district__detailData__data_rows__A_Area'
category_query_string = 'base_data__one_district__category'
angle_list = ['ANGLE', 'ANGLE ', 'angle', 'Angle']
Q1 = Q(base_data__one_district__category=category)
Q2 = Q(base_data__one_district__detailData__data_rows__product_name__product__in=angle_list)
val = self.target_files.all().filter(Q2 & Q1)\
.aggregate(Sum(query_string))
val = self.target_files.all().filter(Q2 & Q1).aggregate(Sum(query_string)).get(query_string+'__sum', Decimal(0))
if not val:
val = Decimal(0)
return val
@property
def total_sum(self):
return round_half_up(
self.sumHelper('A_Area') +
self.sumHelper('B_Area') +
self.sumHelper('C_Area') , 2)
아무래도 템플릿쪽에서 사용하기 위해선 여러 모델함수들로 무장해야했다.
다 원리는 같으니, 하나만 뜯어보자면, _sum_with_angle_area_with_category 함수를 예로 들 수있다.
Q를 이용해 쿼리식을 만드는 부분인 아래의 부분은
Q2 = Q(base_data__one_district__detailData__data_rows__product_name__product__in=angle_list)
내 장고인생 최고로 긴 쿼리였다. 근데 이거도 좀 비하인드 스토리가 있는게, 다 만들고 보여줬더니,
아 우리 앵글면적은 안 받아. 제외하고 나와야해.
아 대리님 진짜,, 홀리, 몰리
그래서 오타까지 생각해서 angle_list 를 만들어 이 안에 있는거는 빼고 하게끔 했다. (처음에는 Angle로 했다가 안되길래 고장난줄 알고 엑셀파일을 봤더니 안에는 Angle(공백) 으로 데이터가 돼있어서 우리는 모두 인간이다 생각하면서 만들었다.
엑셀 파일로 묶여진 모든 데이터부분들을 취합해 보여주는 과정이어서 그런지, 뭐가 많이 복잡하다.
그렇게 데이터들을 하나의 property형태로 카테고리별 묶어서 나타낸게 sum_with_category_all이다. ㅎㅎ, 코드가 더럽긴 하지만 구조 자체는 마음에 든다. 직관적인듯.
3. 시그널
@receiver(pre_save, sender=CollectedFilesModel)
def auto_adjust_day(sender, instance, **kwargs):
if instance.target_date.day != 1:
year = instance.target_date.year
month = instance.target_date.month
instance.target_date = datetime.date(year, month, 1)
# DataOneRow를 저장하기 전 면적을 계산하고 값을 넣음
@receiver(pre_save, sender=DataOneRow)
def auto_calculate_area(sender, instance, **kwargs):
instance.A_Area = areaHelper(instance) * instance.A_value_quantity
instance.B_Area = areaHelper(instance) * instance.B_value_quantity
instance.C_Area = areaHelper(instance) * instance.C_value_quantity
@receiver(pre_delete, sender=CollectedFilesModel)
def auto_delete_file_on_delete_collected_file(sender, instance, **kwargs):
"""
Deletes file from filesystem
when corresponding `MediaFile` object is deleted.
"""
if instance.completed_file:
if os.path.isfile(instance.completed_file.path):
os.remove(instance.completed_file.path)
@receiver(pre_delete, sender=UploadedExcelFiles)
def auto_delete_file_on_delete(sender, instance, **kwargs):
"""
Deletes file from filesystem
when corresponding `MediaFile` object is deleted.
"""
if instance.excel_file:
if os.path.isfile(instance.excel_file.path):
os.remove(instance.excel_file.path)
시그널은 별게 없다.
데이터 저장시 target_date 를 무조건 1일로 잡는 것과
저장하기 전에 areaHelper를 통해 면적을 계산하는 함수
파일을 삭제할 때 db만 삭제되고 실제 파일이 삭제되지 않는데, 이를 삭제하기위한 장치다.
사실 completed_file과 excel_file을 변수만 맞춰주면 하나만 있어도 된다 ㅎㅎ
그 밖에,
그나마 코드를 좀 깔끔하게 짠 부분인거 같은게 데코레이터 부분이다.
def role_check(function):
def _function(request,*args, **kwargs):
coating_company_id = kwargs.get('coating_company_id', None)
if coating_company_id:
try:
user_roles = request.user.useradditionalinformation.has_roles.all()
coat_company = CoatCompanyModel.objects.get(id=coating_company_id)
if request.user.is_superuser or request.user.is_staff:
return function(request, *args, **kwargs)
if coat_company not in user_roles:
raise Exception('해당 페이지에 들어갈 권한이 없습니다.')
except Exception as e:
messages.add_message(request, messages.WARNING, e)
return redirect('select_view')
return function(request, *args, **kwargs)
return _function
def admin_or_staff_check(function):
def _function(request,*args, **kwargs):
if request.user.is_superuser or request.user.is_staff:
return function(request, *args, **kwargs)
else :
messages.add_message(request, messages.WARNING, '해당 페이지에 들어갈 권한이 없습니다.')
return redirect('select_view')
return function(request, *args, **kwargs)
return _function
나는 페이지를 역할중심의 페이지를 할 예정이었다. 읽기/쓰기 권한 중심으로 가자니 뭔가 권한할당이 되게 복잡해질 듯 했다.
그래서 role_check 데코레이터를 작성해서 리다이렉트까지 깔끔하게 처리하게 했다.
코드정리는 안하고 올렸지만 생각보다 구조자체는 마음에 든다.
'코드 자가리뷰(장고)' 카테고리의 다른 글
페이지 최적화 예제(django queryset optimization example) (0) | 2020.08.27 |
---|---|
ORM코드 최적화가 필요하다. (0) | 2020.08.23 |
장고 테스트 코드 작성기 (0) | 2020.08.08 |
혼자서 만드는 마감정산 시스템(Django) (0) | 2020.08.07 |
초등학교 게시판 만들기 -3 (0) | 2020.04.23 |