django middleware

web/Django 2016.08.15 21:36



https://docs.djangoproject.com/ja/1.10/topics/http/middleware/



django에서의 middleware는 모든 request/response의 프로세싱의 훅에 해당합니다. 즉 모든 요청 이벤트를 통과하는 중간 처리과정입니다. 


그렇다면 middleware가 언제 필요한가?! 라고 한다면 


만일 특정 url이 들어왔을 경우에만 처리해야 하는 로직이 있다거나 뷰를 리턴할때마다 무엇인가를 추가하거나 빼거나를 할수도 있습니다. 


즉 특정한 app단에서의 django가 아닌 전체 권한을 가지고 움직일때 쓰이는것이 middleware입니다. ( 윈도우에서의 hooking를 생각하시면 됩니다.)


간단하게 소스로 구현한다면 



testmiddle.py

from django.conf import settings
from django.db import connection
from django.template import Template, Context


class SimpleMiddleware(object):
def __init__(self):
pass
# One-time configuration and initialization.

def process_request(self, request):
return

def process_view(self, request, view_func, view_args, view_kwargs):

print(request, view_args, view_func, view_kwargs)
respose = None
return respose

def process_template_response(self, request, response):
print(request, response)
return response

def process_response(self, request, response):
print(request, response)
return response


파일을 만들어 주고 


settings.py 에서



MIDDLEWARE_CLASSES = [
..................
'post.testMiddle.SimpleMiddleware'
]

MIDDLEWARE_CLASSES = [] 부분에 추가해주면 동작합니다. 쉽죠?!



위의 소스는 간단하게 어떤 함수(훅)이 언제 동작하는지를 간단하게 볼수 있습니다. (django v1.9)


사진출처 : https://docs.djangoproject.com/ja/1.9/topics/http/middleware/#middleware


위의 이미지에서 보는바와 같이 각 요청시에 꼭 통과하는 미들웨어 들이 있고 해당 요청에 따라 작동하는 middleware의 훅이 달라지게 됩니다. 



각 이벤트에 따라 작동하는 훅은 달라지며 특정 요청시에만 훅을 적용하는게 성능상 좋습니다.



좀더 알아보기 위해서 process_response()부분에 다음과 같이 추가합니다.


def process_response(self, request, response):

if connection.queries:
execution_sql_time = sum([float(q['time']) for q in connection.queries])
t = Template(
"""
{{nb_sql}} requet{{nb_sql|pluralize:"e,es"}} en {{execution_sql_time}} second{{execution_sql_time|pluralize:"e,es"}}:
{% for sql in sql_log %}
[{{forloop.counter}}] {{sql.time}}s: {{sql.sql|safe}}
{% endfor %}
""")
print("---------------")
print(t.render(Context({'sql_log':connection.queries,'nb_sql':len(connection.queries),'execution_sql_time':execution_sql_time})))
print("---------------")
print(request, response)
return response

바로 해당 url요청에 실행되는 모든 쿼리와 쿼리 시간을 가져 옵니다. 



정상적으로 잘 가져 오는군요. 이렇듯 django의 전체적인 로직에 관여하고 싶다면 middleware로 구현하면 됩니다. 


단!! 서비스 전체에 걸리는 부하이기 때문에 서비스에 영향이 갈수 있습니다. 


저작자 표시
신고

'web > Django' 카테고리의 다른 글

django middleware  (0) 2016.08.15
django-summernote 사용하기  (4) 2016.07.23
get 방식의 글자 256자 제한은 잘못된 상식  (0) 2016.05.24
Django South migration error   (0) 2015.09.30
django ajax post data and view.py  (0) 2014.11.08
uwsgi logger disable option  (0) 2014.10.24

WRITTEN BY
No.190
세계정복의 시작점

받은 트랙백이 없고 , 댓글이 없습니다.
secret

제가 가장 많이 사용하는 WYSIWYG는  summernote와 froala입니다. froala의 경우는 심플하고 깔끔하지만 기능성에 있어서 상당히 버그가 많습니다. 커스텀또한 어려운 편입니다. summernote도 깔끔한데다가 딱히 손볼곳이 없이 군더더기 없이 사용할 수 있는 에디터 입니다.


그런 summernote의 경우엔 django의 app으로도 개발되어 있어서 django로 쉽게 사용이 가능합니다.


이제부터 django-summernote의 설정및 구현 방법입니다.


django-sumernote의 자세한 내용을 원하시면 해당 레파지토리를 활용하세요!

https://github.com/summernote/django-summernote




아래의 진행사항의 전체 소스는 https://github.com/uiandwe/django_summernote_test 입니다. 



1. 설치하기
 $ pip install django-summernote


2. 기본셋팅


settings.py 의 installed_apps 추가


INSTALLED_APPS = [
.........
'django_summernote',
]


urls.py 의 url경로 등록

urlpatterns = [
.........
url(r'^summernote/', include('django_summernote.urls')),

]


post라는 app을 추가하였습니다.

$python manager.py startapp post



3. 모델 및 폼 생성


post/models.py 에 summernote의 모델을 추가해 줍니다.


from django.db import models
from django_summernote import models as summer_model
from django_summernote import fields as summer_fields
# Create your models here.


class summer_note_model(summer_model.Attachment):
summer_field = summer_fields.SummernoteTextField()

form.py form 추가

post/form.py 파일 추가 후 아래의 소스를 넣어줍니다.

해당 form부분에서 summernote의 속성을 지정해 줄수 있습니다.

__author__ = 'uiandwe'

from django import forms
from django_summernote.widgets import SummernoteWidget, SummernoteInplaceWidget
from django_summernote import fields as summer_fields
from .models import summer_note_model


class FormFromSomeModel(forms.ModelForm):

fields = summer_fields.SummernoteTextFormField(error_messages={'required':(u'데이터를 입력해주세요'),})
class Meta:
model = summer_note_model
fields = ('fields',)
widgets= {
'foo' : SummernoteWidget(),
'bar' : SummernoteInplaceWidget(),
}

4. view 추가 / urls.py 생성


post/views.py에 post에 대한 컨트롤러 부분을 추가해줍니다.

post 부분에 전송된 데이터가 넘어오게 됩니다. 

form.is_valid() (데이터 검증) 부분을 통과한 부분에 db를 연동해서 저장하는 로직을 넣어주시면 됩니다.

from django.shortcuts import render
from post.form import FormFromSomeModel as DetailForm
# Create your views here.


def posts(request):
if request.method == "GET":
return render(request, 'post/form.html', {'form': DetailForm})
elif request.method == "POST":
form = DetailForm(request.POST)
if form.is_valid():
print(form)
return render(request, 'post/form.html', {'form': DetailForm})


post/urls.py 를 생성해 줍니다.

url경로를 지정해 주었는데 저의 경우 /post/로 지정하였습니다.



from django.conf.urls import patterns, include, url

urlpatterns = patterns('',
url(r'^$', 'post.views.posts'),
)

5. 템플릿 생성 및 설정


templates 폴더 생성

  |____  post 폴더 생성

               |____ form.html 생성


폴더 및 파일을 생성합니다. 

form.html에 form 태그를 넣어줍니다.


<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<body>
<form action="/post/" method="post">{% csrf_token %}
{{ form|safe }}
<input type="submit" value="Submit" />
</form>
</body>
</html>


settings.py 


위의 설정해준 템플릿 적용을 위해선 경로를 지정해 줘야 합니다. 

settings.py중 templates[]에서 dirs 경로 추가해 줍니다.

TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')],
............... },
]


6. 마이그레이션!

$python manage.py makemigrations

$pip manage.py migrate



7. run!!







마지막으로 파일 업로드를 사용시엔 경로를 설정해 주셔야 합니다.


settings.py 에서 


staticfiles_dirs / media_root / media_url  경로를 설정해 주시면 해당 폴더로 파일이 업로드 됩니다.

STATICFILES_DIRS = [
os.path.join(BASE_DIR, "static"),

]

MEDIA_ROOT = os.path.join(BASE_DIR, 'static/media')
MEDIA_URL = '/static/media/'


끝!

저작자 표시
신고

'web > Django' 카테고리의 다른 글

django middleware  (0) 2016.08.15
django-summernote 사용하기  (4) 2016.07.23
get 방식의 글자 256자 제한은 잘못된 상식  (0) 2016.05.24
Django South migration error   (0) 2015.09.30
django ajax post data and view.py  (0) 2014.11.08
uwsgi logger disable option  (0) 2014.10.24

WRITTEN BY
No.190
세계정복의 시작점

받은 트랙백이 없고 , 댓글  4개가 달렸습니다.
  1. 너무 힘듭니다..... 2017.02.08 02:02 신고
    다 똑같이 따라했는데,
    Got an error uploading an image: <h1>Server Error (500)</h1>
    이런 메세지가 나옵니다...
    media url도 넣었고,
    debug도 false로도 바꿔보고 다 했는데도요....
    원인이 무엇일까요?ㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠ
  2. 이미지 업로드시에 발생한 오류예요.ㅠㅠㅠㅠ
  3. Last, please don't forget to use safe templatetag while displaying in templates.
    {{ foobar|safe }}

    요료코롬 쓰여있잖아요.
    그런데 전 makedown을 뷰에서 사용해서, safe를 지우고 사용하거든요.
    {{ foobar|safe|linebracks }}에서 다빼고, {{foobar}} 만 사용하면,
    html도 되고, markdown도 해서 좋기는 좋은데,
    don't forget to use safe , 이 단어가 뒤끝을 안좋게 만들어요.
    safe 안쓰면 보안에 안좋은지 궁금해요.
    • 방금댓글쓴사람 2017.03.19 08:27 신고
      form 뷰에서 summernote 뷰가 너무 커서 그런데, 뷰 사이즈를 조절 할 수 있는 방법이 있는지 알고싶습니다.
secret


사실 아는 사람들은 알겠지만 get방식의 글자수 제한이 256자 라는것은 거짓말이다. 


http 1 버전 시대에서 잘못 내려온 일종의 속설이다. (http 1이 96년도 발표이다. 현재 많은 브라우저가 http 2.0을 지원 중이다;;)


https://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.2.1

3.2.1 General Syntax 부분을 보면  get 요청에 의해 URI가 너무 길다고 서버단에서 판단하면 414 오류를 보내도록 프로토콜이 지정되어 있다. 그렇다. 길이에 대한 명확한 부분은 없다 단지 Note 부분에 " 서버는 255바이트 이상의 URI길이는 주의" 라고 쓰여져 있다. 



왜 이렇게 많은 책과 인터넷 정보에서 " get 방식은 길이 제한이 있어!!!"  라고 하길래 정말 지금도 그럴까? 해서 테스트 해보았다. 


서버 단은 간단하니 플라스크로.. get 길이를 화면에 표기하게 했습니다.


from flask import Flask
from flask import request
app = Flask(__name__)

@app.route("/")
def hello():
args = request.args.get('key', '')
print(len(args))
return str(len(args))


if __name__ == "__main__":
app.run(host='127.0.0.1', port=8009)


1. 크롬(메모리 처묵처묵)

당혹스럽게도 이상한 숫자에서 끝이 났다. 37748.



2. 모질라 파이폭스!!


무려 100만자리가 넘어갔는데도 1초내로 화면이 뜨는 속도!! 더 하고 싶어도 언제 끝날지 몰라서 100만자리로 스톱



3. 애플의 사파리

사실 위의 숫자가 끝이 아닙니다. 더 할수 있었겠지만 로딩이 느려져서 스톱. (대략 15초 정도가 걸렸습니다. )


4. 오페라

오페라도 더 할수 있었겠지만 너무 느려져서 스톱(30만 길이 화면 뜨는데 1분 넘게 걸렸습니다.)



- 번외 익스/엣지는 패스~(난 맥 사용자라서...)



검색 해본 결과 익스 9의 경우 2083자 / 최대 5120자를 지원한단다..(뭐이리 짧어?)

사파리는 40만자를 넘기면 브라우저가 크러쉬되고 (난 넘겼는데?!)

파이어폭스/오페라는 길이 제한이 없고 50만자를 넘겨도 별다른 이상이 없고(하지만 오페라는 죽도록 느리다.)

크롬의 경우 4만자를 기준으로 한다니 대략 맞는거 같다. 



그래서!!!! 현재는 서버의 기준이 아닌 브라우저의 기준에 따라서 get방식의 글자수 제한이 있으며 최소한 256자 는 아니란 말씀!! 하지만 익스가 대략 2천자까지이니 맘대로 써도 된다는것!!



- 그래서 파이어폭스 쓰세요!! 100만자를 넘겨도 1초대를 달리는 스피드!

- 크롬은 날이 갈수록 메모리만 먹고 느려지는듯한다.

- 참고 https://docs.google.com/document/d/1G_VSSmud0zzxpVajOAtWPXbnsp1T3CZd5kU5nWotSrQ/edit



저작자 표시
신고

'web > Django' 카테고리의 다른 글

django middleware  (0) 2016.08.15
django-summernote 사용하기  (4) 2016.07.23
get 방식의 글자 256자 제한은 잘못된 상식  (0) 2016.05.24
Django South migration error   (0) 2015.09.30
django ajax post data and view.py  (0) 2014.11.08
uwsgi logger disable option  (0) 2014.10.24

WRITTEN BY
No.190
세계정복의 시작점

받은 트랙백이 없고 , 댓글이 없습니다.
secret

Backwards migration with Django South

$ python ./manage.py migrate your_app 0002


error

south.exceptions.GhostMigrations: 

! These migrations are in the database but not on disk:


$ python manage.py migrate  your_app  --ignore-ghost-migrations

저작자 표시
신고

WRITTEN BY
No.190
세계정복의 시작점

받은 트랙백이 없고 , 댓글이 없습니다.
secret



ajax (javascirpt)


var SendInfo= [];

var data = {

    date:$("#datetimepicker").val(),

    time:$("#time").val(),

    people:$("#people").val()

}

SendInfo.push(data);


$.ajax({

    url: YOUR_URL,

    dataType: "json",

    data: JSON.stringify(SendInfo),

    type: 'POST',

    success: function(data){

        console.log(data.data)


    }

});



view.py


data = json.loads(request.body)

print data[0]["date"]

print data[0]["time"]

print data[0]["people"]

저작자 표시
신고

WRITTEN BY
No.190
세계정복의 시작점

받은 트랙백이 없고 , 댓글이 없습니다.
secret


Add uwsgi.ini or uwsgi setting file option


disable-logging = true


It's worked!



저작자 표시
신고

WRITTEN BY
No.190
세계정복의 시작점

받은 트랙백이 없고 , 댓글이 없습니다.
secret



if you see the to error that 'django.db.utils.IntegrityError: Can't DROP 'XXXX'; check that column/key exists'


you must migrate that colum to remove.

and one more migrate that colum to insert than have migrate option to '--fake'

$ python ./manage.py migrate YOUR_APP --fake


than table is worked to normal behavior.




저작자 표시
신고

WRITTEN BY
No.190
세계정복의 시작점

받은 트랙백이 없고 , 댓글이 없습니다.
secret



if you have error message to 'django.db.utils.IntegrityError: Unknown table  '


than remove the your table to already.


so you can option --fake


$ python ./manage.py  migrate YOUR_APP --fake


then ended migrate and it worded!


저작자 표시
신고

WRITTEN BY
No.190
세계정복의 시작점

받은 트랙백이 없고 , 댓글이 없습니다.
secret




django 에서 HttpResponse 리턴을 json으로 하면서 content_type을 제대로 지정을 하지 않는다면 ie8/9 에서 save as 가 발생합니다. 참고로 저의 경우 application/text 으로 지정을 했더군요.






단순히 리턴하는 content_type : text/plain 으로 바꿔주면 끝. 


 - 참고로 json 으로 content_type 일땐 크롬에서 에러가 발생합니다.



저작자 표시
신고

WRITTEN BY
No.190
세계정복의 시작점

받은 트랙백이 없고 , 댓글이 없습니다.
secret


 If it does not work if the door is an integer

flowing change code:


{% if  codeInt1|add:0 == codeInt2|add:0 %}


The default settings is a string. so This conversion is necessary to int.

저작자 표시
신고

WRITTEN BY
No.190
세계정복의 시작점

받은 트랙백이 없고 , 댓글이 없습니다.
secret