일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- channels
- pip 오류
- 장고
- optimization page
- qpa_plugin
- django erp
- uiload
- test drive development
- 파이썬
- Python
- pyside6 ui
- materialized
- ERP
- django
- tensorflow
- django rank
- orm 최적화
- 장고로 ERP
- qwindows.dll
- pip 설치
- QApplication
- django drf
- 재고 관리
- Self ERP
- 페이지 최적화
- django role based
- pyside6
- 중량 관리
- query 최적화
- django test
- Today
- Total
취미삼아 배우는 프로그래밍
Django로 개인 업무(ERP) 홈페이지 만들기-3 본문
진행상황
저번에 만들었었던 pdf_view를 iframe에 담기로 했다. 그치만, iframe에는 same_origin 등의 클릭재킹 공격에 대한 공격대비가 들어있기 때문에 이에대한 방비를 풀어줘야한다.
@xframe_options_exempt
def pdf_view(request, id):
file_obj = UploadedFiles.objects.get(id=id)
file_path = os.path.join(settings.MEDIA_ROOT, str(file_obj.uploaded_file))
try:
return FileResponse(open(file_path, 'rb'), content_type='application/pdf')
except FileNotFoundError:
raise Http404()
@xframe_options_sameorigin
def pdf_view_test(request):
try:
return FileResponse(open('test.pdf', 'rb'), content_type='application/pdf')
except FileNotFoundError:
raise Http404()
# xframe_options_exempt : 무차별 허락
# xframe_options_sameorigin : sameorigin일시 허락
그리고 materialize를 깔끔하게 쓰기 위해서 modal페이지를 많이 사용했다.
이와 같은 형태인데, 여러 개를 사용했다.
<div class="container">
<div class="row">
<div class="col s12">
<h4 class="header center-align">미분류 도면</h2>
<div class="row">
{% for component in page_obj %}
<div class="card horizontal col s12 m6">
<div class="card-stacked">
<div class="card-content">
<p>{{ component.extract_filename }}</p>
</div>
<div class="card-action center-align">
<button
data-target="pdf_view_modal"
class="btn modal-trigger"
onclick="load_pdf(this)"
data-id="{{ component.id }}">
상세
</button>
<a
class="btn modal-trigger"
href="{% url 'pdf_delete' id=component.id %}">
삭제
</a>
</div>
</div>
</div>
{% empty %}
<h3>아무 파일이 없습니다.</h3>
{% endfor %}
</div>
</div>
</div>
{% include "modals/search_location_modal.html" %}
{% include "modals/pdf_view_modal.html" %}
{% include "modals/create_order_modal.html" %}
</div>
아무래도 모달페이지가 너무 길면, 코드를 보는데 너무 힘들기 때문에 조금 만들어졌다 싶으면 바로 옮기면서 작업했다.
스크립트
그리고 생각보다 자바스크립트를 많이 사용했다.
<script>
// console.log('%c Oh my heavens! ', 'background: #222; color: #bada55; font-size:40px;')
document.addEventListener('DOMContentLoaded', function() {
var options = {};
var elems = document.querySelectorAll('.modal');
var instances = M.Modal.init(elems, options);
});
function load_pdf(e) {
var base_url = "{% url 'pdf_view' id=0 %}";
var url_arr = base_url.split('/');
url_arr[url_arr.length-2] = e.dataset.id;
var url = url_arr.join('/');
modal_pdf_iframe.dataset.pdf_id = e.dataset.id;
modal_pdf_iframe.src = url;
modal_header.innerText = e.parentElement.parentElement.childNodes[1].innerText;
}
function delete_pdf_file(id) {
// 삭제시 메세지 후 삭제
}
function calculate_sum(){
// 값 입력 시 자동 합계 산출
}
function createCell(cell, i) {
if(i==0) {
cell.outerHTML = "<th contenteditable='true'>세대</th>";
return
}
var txt = document.createTextNode("");
cell.setAttribute('contenteditable', true);
cell.appendChild(txt);
}
function delete_order_table_column() {
var i, j,
lastCol = order_table.rows[0].cells.length - 2;
for (i = 0; i < order_table.rows.length; i++) {
order_table.rows[i].deleteCell(lastCol);
}
}
function append_order_table_column(){
var i;
for (i = 0; i < order_table.rows.length; i++) {
console.log(order_table.rows[i]);
createCell(order_table.rows[i].insertCell(order_table.rows[i].cells.length-1), i);
}
}
function delete_order_table_row() {
var len = document.getElementsByClassName("order_row").length;
var last_elem = document.getElementsByClassName("order_row")[len-1];
if(len != 1){
last_elem.remove();
}
}
function append_order_table_row() {
var cln = document.getElementsByClassName("order_row")[0].cloneNode(true);
var new_elem = order_table.appendChild(cln);
// init values
var i;
var tds = new_elem.getElementsByTagName("td");
var len = tds.length;
for(i=0; i<len; i++) {
if(i==0){
var input = tds[i].getElementsByTagName("input");
input[0].value = "";
input[1].value = 2400;
input[2].value = "";
continue
}
else if(i==len-1) {
continue
}
else {
tds[i].innerText ="";
}
}
}
function init_wall_ordertable() {
$.ajax({
url:"{% url 'ajax_ordering_table_component' %}",
method:"POST",
type:"json",
data:null,
}).done(function(data){
location_searcher_btn.outerHTML = '<button data-target="location_searcher" class="btn waves-effect waves-green modal-trigger" id="location_searcher_btn">현장검색</button>';
order_table.outerHTML = data;
}).fail(function(xhr,data){
console.log(xhr, data);
alert('초기화 실패. 새로고침 해주세요.');
})
}
function gather_data() {
// 데이터 취합
/*
datastructure:
{
'fk_id':1,
'pages':[List],
'gens':[List],
0:[[10,20,30,0,0,0,22], {
'filar':200,
'panel':2400,
'rocker':50,
}]
}
*/
var i, j, data, temp;
var cell_length = order_table.rows[0].cells.length;
if(location_searcher_btn.getAttribute("data-id") === null) {
toast_msg('현장 선택 안됨.');
return
}
var pdf_id = modal_pdf_iframe.dataset.pdf_id;
var fk_id = location_searcher_btn.dataset.id;
data = {};
data['pdf_id'] = pdf_id;
data['fk_id'] = fk_id;
data['pages'] = [];
data['gens'] = [];
for (i = 0; i < order_table.rows.length; i++) {
temp = [{}, []];
for (j=0; j < cell_length-1; j++) {
var cell = order_table.rows[i].cells[j];
var txt = cell.textContent;
if(i == 0) {
if(j==0 || j==cell_length-1){
continue
}
if(j==0){
// blah blah .. 필라데이터 입력
}
data['gens'].push(txt);
}
else if(j==0) {
var panel = cell.getElementsByTagName("input")
temp[0]['filar'] = panel[0].value || 0
temp[0]['panel'] = panel[1].value || 0
temp[0]['rocker'] = panel[2].value ||0
}
else if(txt == "") {
temp[1].push(0);
}
else {
temp[1].push(txt);
}
if( i!=0 ) {
data[i] = temp;
}
}
}
return data
}
function ajax_data_send() {
// ajax 요청 보냄
if (confirm('저장하시겠습니까?')) {
// Save it!
} else {
// Do nothing!
console.log('Not Save.');
return
}
var send_data = gather_data();
if(send_data === undefined){
return
}
$.ajax({
url:"{% url 'ajax_standardwall_register' %}",
method:"POST",
type:"json",
data:JSON.stringify(send_data),
}).done(function(data){
// console.log('success:', data);
init_wall_ordertable(); // 오더 적는 곳 초기화
ajax_search_location(); // 현장검색도 초기화
alert('저장완료');
}).fail(function(xhr,data){
console.log(xhr, data);
alert('저장 실패. 새로고침 해주세요.');
})
}
function ajax_search_location() {
var send_data = {
'company_name':search_company_name.value,
'location_name':search_location_name.value,
'distrcit_name':search_district_name.value,
};
$.ajax({
url:"{% url 'ajax_search_location_data_response' %}",
method:"POST",
type:"json",
data:JSON.stringify(send_data),
}).done(function(data){
result_for_location.outerHTML = data;
}).fail(function(xhr,data){
console.log(xhr, data);
alert('저장 실패. 새로고침 해주세요.');
})
}
function location_selected(e) {
location_searcher_btn.innerText = e.dataset.string;
location_searcher_btn.dataset.id = e.dataset.id;
var elem = location_searcher;
var instance = M.Modal.getInstance(elem);
instance.close();
toast_msg('현장 선택됨');
}
/*
데이터를 전송하는 페이지(HTML), 데이터를 전송받는 페이지(django view)
HTML - 회원가입, 좋아요 데이터 전송
-> 장고측 뷰가 데이터를 받아 모델 처리, 로직 처리
-> 모델처리가 완료되면 메시지, 혹은 처리 결과 데이터를 다시 HTML로 전송
-> HTML은 응답받은 데이터를 가지고 화면에 정보 출력
$.ajax({
url: "클라이언트가 요청 보낼 서버의 URL 주소",
method:"POST", // HTTP 요청 방식(GET, POST)
type: "json", // 서버에서 보내줄 데이터의 타입(default값으로 json으로 되어있다.)
data: {name: "홍길동"} // HTTP 요청과 함께 서버로 보낼 데이터
}).done(function(data) { // HTTP 요청 성공 시, 요청한 데이터가 done() 메소드로 전달
}).fail(function(xhr, data) { // HTTP 요청 실패 시, 오류와 상태에 관한 정보가 fail() 메소드로 전달
}).always(function(xhr, data) { // HTTP 요청의 성공여부와는 상관없이 언제나 always()메소드 실행
});
*/
function toast_msg(msg) {
M.toast({html: msg})
}
</script>
위에서 보는것 처럼 생각보다 아약스요청을 많이넣었다. 어떻게든 빨리 하고싶어서 이렇게 했다. 근데 생각보다 건들게 없어서 놀랐다.
def wall_ordering_table_response(request):
template_name = 'wall_ordering.html'
return HttpResponse(render(request,template_name,{}))
위처럼 render된 template파일을 HttpResponse로 보낼 때 render된 것을 주게 되면 텍스트로 날아가게 되는데, 자바스크립트를 통해 outerHTML 속성으로 아예 통째로 HTML 자체를 교체해서 시간을 많이 절약했다. 무식한 방법 같지만 생각보다 유지보수가 더 쉬운 느낌이다.
그렇게 해서 얼추 윤곽은 나왔다.
나오진 않았지만, DB에 저장하는 부분까지 모두 완료됐다.(그러고보니 수정, 삭제는 없다. 아..)
어느정도 잘 진행되고 있는것 같지만, 가장 큰 문제는 순서를 수정하는 문제가 남아있다. 매번 순서를 재조정하는걸로 해야할까.. 근데 이거도 가장 마지막 오더의 40개 ~ 60개 정도가 왔다갔다 하길래 괜찮은 방법 같기도 하다.
그리고 저기 위에서 오더작성 모달 페이지를 드래그로 아래위 움직였으면 좋겠는데, 이건 조금 나중에 다시 도전해봐야겠다.
'파이썬(장고)' 카테고리의 다른 글
Django로 개인 업무(ERP) 홈페이지 만들기-5 (0) | 2020.11.14 |
---|---|
Django로 개인 업무(ERP) 홈페이지 만들기-4 (0) | 2020.11.13 |
Django로 개인 업무(ERP) 홈페이지 만들기-2 (0) | 2020.11.03 |
Django로 개인 업무(ERP) 홈페이지 만들기-1 (0) | 2020.11.02 |
Django로 ERP 근황 (1) | 2020.10.31 |