일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- django drf
- test drive development
- pip 오류
- 장고로 ERP
- 장고
- optimization page
- pip 설치
- Python
- django erp
- 재고 관리
- django role based
- orm 최적화
- materialized
- django
- 파이썬
- django rank
- pyside6 ui
- 페이지 최적화
- 중량 관리
- tensorflow
- qpa_plugin
- pyside6
- django test
- channels
- QApplication
- ERP
- Self ERP
- qwindows.dll
- query 최적화
- uiload
- Today
- Total
취미삼아 배우는 프로그래밍
혼자서 만드는 마감정산 시스템(Django) 본문
장고 코딩하다 막혀서 풀어보는
#리뷰
자가 코드 리뷰
(영감을 얻어 가셨으면 합니다.)
1. 모델(전체)
from django.db import models
from jsonfield import JSONField
from django.db.models import F, Sum, Count, Case, When
from django.db.models.signals import pre_save
from django.dispatch import receiver
from .helper import areaHelper
from django.utils import timezone
# Create your models here.
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월'
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,)
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))
return val[field+'__sum']
@property
def all_rows(self):
return ', '.join([x.name for x in self.data_rows.all()])
@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(self.sumHelper('A_Area'), 2)
@property
def B_Area_sum(self):
return round(self.sumHelper('B_Area'), 2)
@property
def C_Area_sum(self):
return round(self.sumHelper('C_Area'), 2)
@property
def AandC_Area_sum(self):
return round(self.sumHelper('A_Area') + self.sumHelper('C_Area'), 2)
class TheOneDistrict(models.Model):
objects = models.Manager()
# basedata = models.ForeignKey(BaseData, on_delete=models.CASCADE, )
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}일'
def get_yearList():
vals = BaseData.objects.all().values('finishing_date')
a_list = [ a.get('finishing_date', None).year for a in list(vals) ]
return list(set(a_list))
# DataOneRow를 저장하기 전 면적을 계산하고 값을 넣음
@receiver(pre_save, sender=DataOneRow)
def post_delete(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
모델은 나름 직관적으로 보이기 위해 위에서부터 아래로 쭉 내려오게끔 했다.(깔끔하진 않은것 같다.)
(Month 클래스는 사실 언제고 쓸 일이 있을까 싶어서 냅뒀다.)
> 코팅업체, 제품 모델이 가장 상위에(가장 독립적이니) 배치했고,
> 이 둘을 통해 제품 데이터의 한 줄을 만든다(DataOneRow).
> 그리고 이 한 줄을 모두 모아서(ManyToMany) DetailedData를 만든다.
> 그리고 이 DetailedData에 이름표인 Company, Location, District 를 붙여서 한 동(TheOneDistrict)를 구성한다.
> 헌데, 이에대한 또다른 꼬리표가 필요했다.
> Queryset을 넘겼을 시, 데이터를 분류해서 템플릿단으로 풀어내기가 빡빡했던 것,
> 그래서 이어 붙이는 김에 BaseData를 만들고 TheOneDistrict와 OneToOne 필드로 구성했다.
> OneToOne필드는 특이하게도 일대일이라는게 명확히 정해진 것이기 때문에, 역으로 돌아가는것도 가능하다.
> TheOneDistrict.objects.basedata.objects.all() 이런식으로,
> 그리고 계산되는 면적은 애초에 사용자가 넣는 값이 아니니, 저장시 post_save를 통해 저장 직전 계산해서 끼워넣는 방식으로 해두었다.(이거 되게 꿀인것 같다.)
> 그치만, 이렇게 저장된 면적들의 합을 구했어야 했다.
> 따로 필드로 만들자니 어차피 한 번 쓰는 값이고 또 빈번히 바뀌는 값들에 대해서 매번 저장을 해주게 될 것 같았다.
> 그래서 property로 구성해서 일회용 값을 불러오게끔 했다.
def sumHelper(self, field):
val = self.data_rows.values(field).aggregate(Sum(field))
return val[field+'__sum']
이 sumHelper는 data_rows라는 ManyToMany 필드 안에서의 명시된 field 값을 모두 더해주는 함수다. 이렇게 되면 example.AandC_Area_Sum 만으로 A와 C의 면적 합들에 대한 값이 상수로 튀어나온다. 이거좀 잘짠거같다.
> 상당히 Property가 편한게, 여러모로 쓰임새가 많다. 예를 들면,
class BaseData(models.Model):
objects = models.Manager()
# ...
finishing_date = models.DateField(verbose_name='작업시기', default=timezone.now)
@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}일'
BaseData 모델 부분에선, 몇 일 작업분인지 뷰단에 표시하려고
@property
def worked_date(self):
return self.finishing_date.day
를 넣었다.
템플릿단에서 막 어렵게 고민할 것 없었다.
어차피 모든 데이터는 모델에서 나오는거다. 그러니 모델에다가 property 를 붙여주고 땡 여깃소 하면 턱하고 나온다.
2. View
뷰쪽에서는 딱히 특별한건 별로 없다.
딱 하나 있는데,
데이터들이 너무 아랫쪽으로 확 하고 모이는 구조이기도 하고,
따로 날자별로 묶자니 그만큼 큰 의미가 있는거는 아니어서 재정렬을 시도했다.
어떻게냐면
이런식으로 나오는건데,
아무래도 일자별로 묶지 않으면, 위와같은 형태로 템플릿단에 넘기기가 쉽지않다.
그래서 아예 틀자체를 새로 재정렬했다.
#쿼리 재정렬
class qs_helper(object):
def __init__(self):
self.values = {}
def add_values(self, dat):
res = self.values.get(dat.finishing_date.day, [])
res.append(dat)
self.values[dat.finishing_date.day] = res
이놈이다.
어떻게 쓴고하면,
query_set = BaseData.objects.filter(
finishing_date__range=[f"{year}-{month}-01",
f"{year}-{month}-{end_day}"])
data_obj = qs_helper()
for qs in query_set:
data_obj.add_values(qs)
context = {
'month':month,
'year':year,
'coated_company':coat_company,
'data_obj':data_obj.values,
}
쿼리셋들을 루프를 돌리면서 넣는데, 이를
data_obj ={
2:[qs1, qs2]
}
위와 같은 형태의 dict형태로 만들어버린다. 그렇게 해서 이걸 템플릿단에서 사용해 루프를 돌린다.
'코드 자가리뷰(장고)' 카테고리의 다른 글
model.py에는 온갖 정성을 쏟아붓자. (0) | 2020.08.20 |
---|---|
장고 테스트 코드 작성기 (0) | 2020.08.08 |
초등학교 게시판 만들기 -3 (0) | 2020.04.23 |
초등학교 학교게시판 만들기. (0) | 2020.04.19 |
초등학교 학교게시판 만들기 (0) | 2020.04.18 |