import time

time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(1347517370))


'Python' 카테고리의 다른 글

Pycharm 에서 무조건 세팅해줘야 할것.  (0) 2017.05.18
[Flask] Flask - wsgi - nginx 연동.  (0) 2017.05.15
[Python] YAPF  (0) 2017.03.11
[Python] python getter setter  (0) 2017.02.16
[Python] 공부해야 할 것.  (0) 2017.02.15
Posted by C마노
,
  • If you want to just remove background, you will have to edit your color scheme at "Settings/Preferences | Editor | Colors & Fonts | General | Injected language fragment" (actual style may be called a bit differently in different IDE version -- just use settings search box (top left corner) to quickly find it)

  • If you want to remove actual injection altogether -- "Settings/Preferences | Editor | Language Injections" -- disable all unwanted rules


'Python' 카테고리의 다른 글

파이썬 epochTime을 원하는 포멧의 Date로  (0) 2017.06.22
[Flask] Flask - wsgi - nginx 연동.  (0) 2017.05.15
[Python] YAPF  (0) 2017.03.11
[Python] python getter setter  (0) 2017.02.16
[Python] 공부해야 할 것.  (0) 2017.02.15
Posted by C마노
,

1. sudo apt-get update

2. sudo apt-get upgrade

3. sudo apt-get install python3-pip python3-dev nginx


4. 가상환경을 원하는 위치 생성


5. 가상환경 active


6. pip install uwsgi flask


7. 프로젝트 붙혀넣고 그 폴더안에

flaskapp.ini 만들고


--아래를 넣는다--

[uwsgi]

module = main:app


master=true

processes=5


socket = flaskapp.sock

chmod-socket = 666

vacuum= true


die-on-term=true


8. vi /etc/nginx/sites-available/flaskapp


[source]


[Unit]

Description=uWSGI instance to serve flaskapp

After=network.target


[Service]

User=root

Group=root

WorkingDirectory=/solution/flask

Environment="PATH=/solution/venv/bin"

ExecStart=/solution/venv/bin/uwsgi --ini flaskapp.ini


[Install]

WantedBy=multi-user.target


9. sudo ln -s /etc/nginx/sites-available/flaskapp /etc/nginx/sites-enabled


10. 문법체크.  sudo nginx -t


11. sudo systemctl restart nginx 또는 service nginx restart


12 .sudo systemctl restart flaskapp 또는 service flaskapp restart

'Python' 카테고리의 다른 글

파이썬 epochTime을 원하는 포멧의 Date로  (0) 2017.06.22
Pycharm 에서 무조건 세팅해줘야 할것.  (0) 2017.05.18
[Python] YAPF  (0) 2017.03.11
[Python] python getter setter  (0) 2017.02.16
[Python] 공부해야 할 것.  (0) 2017.02.15
Posted by C마노
,

Pycharm으로 manage.py startrunserver나


아니면 자체적으로 서버를 런할경우


자꾸 Process Exit (0) 이러면서 꺼지는경우가 있는데;


이것은 마소자체적인 버그라고 한다;


아래처럼 설정해주면 해당 에러가 나지 않는다.



Posted by C마노
,

* Abstract Base Class

   

   - 어떠한 공통적인 필드를 여러 모델에 삽입하려는 경우에 유용

   - 실제로 테이블을 생성하지 않음

   - 기본 클래스를 작성후에 그안에 Meta 클래스 작성후 abstract=True 를 넣어줌

   - 부모필드 ( 즉 여기선 abstract Class Model ) 과 같은 이름을 가지는 자식클래스의 안의 필드를 정의 할 수 없습니다.


from django.db import models

class CommonInfo(models.Model):
    name = models.CharField(max_length=100)
    age = models.PositiveIntegerField()

    class Meta:
        abstract = True

class Student(CommonInfo):
    home_group = models.CharField(max_length=5)

여기서 Student 는 name, age, home_group의 필드를 가집니다.

그리고 Student는 name과 age를 정의할 수 없다는 뜻입니다.


최대의 장점으로는 자식 모델당 하나의 데이터베이스 테이블만 생성하면서 Python 레벨에서 공통적인 정보를 제외시킬수 있다는 점입니다.


자식 클래스가 자신의 Meta 클래스를 선언하지 않으면, 부모클래스의 Meta를 상속 받습니다.  자식이 부모의 Meta 클래스를 확장하려고 하면 아래와 같이합니다.


from django.db import models

class CommonInfo(models.Model):
    # ...
    class Meta:
        abstract = True
        ordering = ['name']

class Student(CommonInfo):
    # ...
    class Meta(CommonInfo.Meta):
        db_table = 'student_info'

[Multi table 상속]


Django 가 지원하는 모델 상속의 두번째 유형은 계층 구조의 각 모델이 모두 하나의 모델일때 입니다.

이 방법은 복잡하고, 느리므로 최대한 사용하지 않는 것을 권장합니다.


각 모델은 자체 데이터베이스 테이블에 해당하며 개별적으로 쿼리하고 생성 할 수 있습니다.


from django.db import models

class Place(models.Model):
    name = models.CharField(max_length=50)
    address = models.CharField(max_length=80)

class Restaurant(Place):
    serves_hot_dogs = models.BooleanField(default=False)
    serves_pizza = models.BooleanField(default=False)

Place의 모든 필드는 Restaurant에서 사용 할 수 있고, 데이터는 다른 데이터베이스 테이블에 저장됩니다. 그래서 둘다 가능.


[ Proxy Model ]


다중 테이블 상속을 사용할 때 모델의 각 하위 클래스에 대해서 새로운 데이터 베이스 테이블을 생성하는 방법입니다. 


프록시의 제일큰 특정은 원본을 변경하지 않고 프록시에서 기본 모델 순서 또는 기본 관리자와 같은 것을 변경할 수 있다는 것입니다.


from django.db import models

class Person(models.Model):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)

class MyPerson(Person):
    class Meta:
        proxy = True

    def do_something(self):
        # ...
        pass

여기서 보면 MyPerson 클래스는 상위 Person 클래스와 동일한 데이터 베이스 테이블에서 작동합니다. 특히 Person의 새 인스턴스는 MyPerson을 통해 엑세스 할 수 있으며, 그 반대의 경우도 가능하다는 것입니다.


>>> p = Person.objects.create(first_name="foobar")
>>> MyPerson.objects.get(first_name="foobar")
<MyPerson: foobar>

또한 프록시 모델을 사용해서 모델에서 원본모델에서 사용하는 ordering을 정의할 수도 있습니다. 


class OrderedPerson(Person):
    class Meta:
        ordering = ["last_name"]
        proxy = True


Posted by C마노
,

[파이썬 스타일]


1. 파이썬 파일은 들여쓰기에 space 4칸을 사용하십시오. HTML은 2칸을 사용합니다.


2. 따로 명시가 되어있지 않는 한은 PEP8을 따릅니다.


flake8을 사용해서 문제가 있는 코드를 확인하고, 특히 하나가 PEP8이랑 다른데 바로 79길이제한입니다.


코드줄을 79로 제한할 필요는 없습니다. 79자의 코드 길이는 GitHub 코드를 볼때 최적화된 너비이므로 Django에서는 119자까지 허용합니다. 


3. 들여쓰기에는 4개의 스페이스를 사용하세요


4. 변수, 함수 및 메소드 이름은 camelCase가 아닌 밑줄을 사용하시기 바랍니다.


poll.getUniqueVoters (X)

poll.get_unique_voters 가 맞습니다.


5. 클래스 이름에는 첫글자를 대문자로 사용합니다.


6. DocString은 꼭 사용하는걸로 합시다.


def foo():
    """
    Calculate something and return the result.
    """
    ...


7. testCode에서는 assetRaises() 대신에, assertRaisesMessage()를 사용해서 예외 메세지를 확인할 수 있습니다. 


[임포트]


1. isort를 사용해서 import 정렬을 자동화하시기 바랍니다.


$ pip install isort
$ isort -rc .

만약, 특별한 경우에 import 정렬이 필요없다고 생각되신다면 

아래의 방침을 따라하십시오.


import module  # isort:skip

2. import를 쓰기전에는 항상 from을 사용하시기를 바랍니다.

import module이 아닌 from module import objects가 맞는겁니다.


3. import 시에는 무조건 상대적 가져오기가 맞는겁니다.

import corn from xx 가아닌.

import . from xx 가 맞습니다.


4. 만약 긴줄의 import가 필요하다면 아래와같이 하십시오. 


from django.http.response import (
    Http404, HttpResponse, HttpResponseNotAllowed, StreamingHttpResponse,
    cookie,
)

import 마지막에는 , 를 포함해야 하고, 닫는 괄호는 마지막 줄에 넣습니다.


5. 마지막 import와 module 코드 사이에는 빈줄 하나를 사용하고 첫번째 함수 또는 클래스위에 빈줄 2개를 사용하시기 바랍니다.


전체적인 예입니다.


# future
from __future__ import unicode_literals

# standard library
import json
from itertools import chain

# third-party
import bcrypt

# Django
from django.http import Http404
from django.http.response import (
    Http404, HttpResponse, HttpResponseNotAllowed, StreamingHttpResponse,
    cookie,
)

# local Django
from .models import LogEntry

# try/except
try:
    import pytz
except ImportError:
    pytz = None

CONSTANT = 'foo'


class Example(object):
    # ...

6. 가능한 한, 편리한 임포트 방식을 사용하십시오.


from django.views.generic.base import View

위의 방법 대신


from django.views import View

위의방법이 더 좋습니다.


[템플릿 스타일]


{{foo}}

위의 방법은 안되고,

{{ foo }}

위의 방법을 사용하십시오.


[뷰 스타일]


1. 항상 첫번째 파라미터는 request입니다. 명심하세요.


def my_view(request, foo):
    # ...

맞는방식이고


def my_view(req, foo):
    # ...

잘못된 방식입니다.


[모델 스타일]


1. 필드 이름은 모두 소문자 이어야만 하고, camelCase 대신에 밑줄을 사용해야합니다.


class Person(models.Model):
    first_name = models.CharField(max_length=20)
    last_name = models.CharField(max_length=40)

아래는 잘못된 예입니다.

class Person(models.Model):
    FirstName = models.CharField(max_length=20)
    Last_Name = models.CharField(max_length=40)


2. 메타 클래스는 필드가 다 정의 되고 난다음에 작성되어야 하고, 필드와 클래스를 정의를 구분하는 하나의 빈줄이 필요합니다.


아래는 정상적인방식


class Person(models.Model):
    first_name = models.CharField(max_length=20)
    last_name = models.CharField(max_length=40)

    class Meta:
        verbose_name_plural = 'people'

아래는 안됩니다.


class Person(models.Model):
    first_name = models.CharField(max_length=20)
    last_name = models.CharField(max_length=40)
    class Meta:
        verbose_name_plural = 'people'

아래도 안됩니다.


class Person(models.Model):
    class Meta:
        verbose_name_plural = 'people'

    first_name = models.CharField(max_length=20)
    last_name = models.CharField(max_length=40)


3. [이거는 꼭 해야되는지 모르겠는데 사실 PYTHON3 만 쓰겟다! 하면 안해도됩니다.]

__str__ method를 사용했다면

python_2_unicode_compatible() 을 사용해서 모델을 꾸미세요.


4. 모델의 내부 클래스와 표준 메소드의 순서는 다음과 같아야 합니다. 


[1] 모든 db 필드

[2] 커스텀 매니저 속성들

[3] 메타클래스

[4] def __str__()

[5] def save()

[6] def get_absolute_url()

[7] 다른 커스텀 메소드들


5. 만약 choice 필드를 사용한다면, 모델의 클래스 속성으로 대문자 이름을 가진 튜플의 튜플로 각 선택사항을 정의해야합니다.


아래의 예를보세요


class MyModel(models.Model):
    DIRECTION_UP = 'U'
    DIRECTION_DOWN = 'D'
    DIRECTION_CHOICES = (
        (DIRECTION_UP, 'Up'),
        (DIRECTION_DOWN, 'Down'),
    )

[django.conf.settings]


모듈은 일반적으로 django.conf.settings에 저장된 설정을 최상위 레벨에서 사용하지 말아야 합니다.


[기타 잡다한것]


1. 국제화를 위해서 모든 국제 문자를 지원하십시오.i18n 설명서를 참조하세요


2. 사용하지 않는 import 는 제거하십시오.


3. 제발 코드에 이름을 넣지마십시오 이것은 굉장히 멍청한 짓입니다. 

Posted by C마노
,

Manager는 Django 모델에 데이터베이스 쿼리작업을 제공하는 인터페이스입니다.

Django 응용프로그램의 모든 모델에는 최소 하나 이상의 Manager가 있습니다.


기본적으로 Django는 모든 Django 모델 클래스에 objects 라는 이름의 Manager를 추가합니다.


그러나, 객체 필드를 이름으로 사용하거나 Manager용 객체 이외의 이름을 사용하려는 경우에는 모델별로 이름을 변경할 수 있습니다.


주어진 클래스에 대해 Manager의 이름을 바꾸려면, 해당 모델에서 models.Manager() 유형을 클래스 속성을 정의하십시오.


from django.db import models

class Person(models.Model):
    #...
    people = models.Manager()


기본 Manager 클래스를 확장하고 모델에서 사용자 정의 Manager를 인스턴스화 하여 특정 모델에서 사용자 정의 Manager를 사용 할 수 있습니다.


사용자 정의 Manager를 사용하는 이유는 2가지가 있습니다.


Manager 메소드를 추가하거나 Manager가 반환하는 초기 QuerySet을 수정하는 이유입니다.


[대표적인 예]


class PostManager(models.Manager):
def active(self, *args, **kwargs):
# Post.objects.all() = super(PostManager, self).all()
return super(PostManager, self).filter(draft=False).filter(publish__lte=timezone.now())


추가 관리자에 메서드 추가하기


우선은 모델에 "테이블 수준"의 기능을 추가하고 싶을 때 사용할 수 있습니다.


행 수준의 기능을 추가할때는 Model 메소드를 사용하십시오 여기서는 컬럼기준일떄 이야기합니다.


사용자 정의 관리자 메소드는 원하는 모든 것을 리턴 할 수 있습니다. QuerySet을 리턴할 필요는 없습니다.


예를 들어, 사용자 정의 관리자는 모든 OpinionPoll 객체의 목록을 반환하는 with_counts() 메서드를 제공합니다.


그런데 각 쿼리에는 집계 쿼리의 결과인 num_responses 속성이 추가로 있습니다.


from django.db import models

class PollManager(models.Manager):
    def with_counts(self):
        from django.db import connection
        with connection.cursor() as cursor:
            cursor.execute("""
                SELECT p.id, p.question, p.poll_date, COUNT(*)
                FROM polls_opinionpoll p, polls_response r
                WHERE p.id = r.poll_id
                GROUP BY p.id, p.question, p.poll_date
                ORDER BY p.poll_date DESC""")
            result_list = []
            for row in cursor.fetchall():
                p = self.model(id=row[0], question=row[1], poll_date=row[2])
                p.num_responses = row[3]
                result_list.append(p)
        return result_list

class OpinionPoll(models.Model):
    question = models.CharField(max_length=200)
    poll_date = models.DateField()
    objects = PollManager()

class Response(models.Model):
    poll = models.ForeignKey(OpinionPoll, on_delete=models.CASCADE)
    person_name = models.CharField(max_length=50)
    response = models.TextField()


이 예제에서는 OpinionPool.objects.with_counts() 를 사용해서 num_responses 속성을 가지는 OpinionPoll 객체의 목록을 반환합니다.


관리자의 기본 QuerySet은 시스템의 모든 객체를 반환합니다.


예를들어 이런 모델이 있다고 가정합시다.


from django.db import models

class Book(models.Model):
    title = models.CharField(max_length=100)
    author = models.CharField(max_length=50)

Book.objects.all() 문은 데이터베이스의 모든 책을 반환합니다.


Manager.get_queryset() 메서드를 재정의 해서 Manager의 기본 QuerySet을 재정의 할 수 있습니다.


get_queryset()은 QuerySet을 반환해야만 합니다.


예를들어 다음 모델에는 두개의 관리자가 있고, 하나는 모든 객체를 반환하고 하나는 Roald Dahl책만 반환합니다.


# First, define the Manager subclass.
class DahlBookManager(models.Manager):
    def get_queryset(self):
        return super(DahlBookManager, self).get_queryset().filter(author='Roald Dahl')

# Then hook it into the Book model explicitly.
class Book(models.Model):
    title = models.CharField(max_length=100)
    author = models.CharField(max_length=50)

    objects = models.Manager() # The default manager.
    dahl_objects = DahlBookManager() # The Dahl-specific manager.

이 샘플 모델을 사용하면 Book.objects.all()은 데이터베이스의 모든책을 반환하지만, Book.dahl_objects.all()은 Roald Dahl이 작성한 책만 반환합니다.


물론 get_queryset()은 QuerySet 객체를 반환하기 때문에 filter(), exclude() 및 기타 모든 QuerySet 메서드를 사용 할 수 있습니다. 


Book.dahl_objects.all()
Book.dahl_objects.filter(title='Matilda')
Book.dahl_objects.count()

그리고 하나의 모델에서 여러관리자를 사용 할 수 있다에 주목해주세요


모델에 원하는 만큼의 Manager() 인스턴스를 첨부할 수 있습니다. 이렇게하면 모델에 대한 일반적인 "필터"를 쉽게 정의 할 수 있습니다.


예제입니다.


class AuthorManager(models.Manager):
    def get_queryset(self):
        return super(AuthorManager, self).get_queryset().filter(role='A')

class EditorManager(models.Manager):
    def get_queryset(self):
        return super(EditorManager, self).get_queryset().filter(role='E')

class Person(models.Model):
    first_name = models.CharField(max_length=50)
    last_name = models.CharField(max_length=50)
    role = models.CharField(max_length=1, choices=(('A', _('Author')), ('E', _('Editor'))))
    people = models.Manager()
    authors = AuthorManager()
    editors = EditorManager()

이 예제에서는 Person.authors.all(), Person.editors.all() 및 Person.people.all()을 요청하여 예측 가능한 결과를 얻을 수 있습니다.




Posted by C마노
,

Restful 공부중. permission에 대해선 확실히 알고 가야 할것같아. 따로 포스팅한다.


[Permission]


Permission 체크는 항상 view 의 시작에 하게 되는데. ( 다른코드의 진행 전에 실행된단 이야기다 )

기본적으로 Permission Check는 request.user 와 reuqest.auth 의 정보를 사용해서 인증을 처리한다.


Permission은 사용자가 정해진 클래스 이외의 클래스의 접근을 거부하거나 허용하는데 사용한다.


가장 간단하게 사용하는 방법은 인증된 사용자에게는 Access를 허용하고 인증되지 않은 모든 사용자는 Access를 거부하는방법이다.


이것은 REST 프레임 워크의 IsAuthenticated  에 해당합니다.


IsAuthenticated  보다 조금 덜 엄격한 스타일은 권한 없는(인증 되지 않은)사용자에게 읽기 전용 액세스를 허용하는 IsAuthenticatedOrReadOnly  가 있겠다.


[어떻게 권한을 결정하나?]


REST Framework의 권한은 항상 권한 클래스의 목록으로 정의되는데,

View의 본문이 실행되기 전에 목록의 각 권한이 검사된다.


만약 권한통과에 실패하게 되면 exceptions.PermissionDenied 나 exceptions.NotAuthenticated 의 Exception이 raise 하게되고, View의 본문은 실행되지 않는다.


권한 검사가 실패하면, 403 Forbidden또는 401 Unauthorized 응답이 반환되게 된다.


* 요청이 성공적으로 인증되었지만, 권한이 거부되었습니다. - 403에러가 리턴된다.

* 요청이 성공적으로 인증되지 않고 헤더가 WWW-Authenticate 헤더를 사용하지 않았다. - 403에러가 리턴된다.

* 요청이 성공적으로 인증되지않고 헤더가  WWW-Authenticate 를 사용했다 - 401에러가 리턴된다.


[객체레벨 권한]


Object-level-permission은 사용자가 특정한 객체에 대한 작업을 허용해야 하는지 (일반적으로 model 인스턴스입니다) 에 대한 결정을 하는데 사용되어 진다. 


객체 레벨 권한은 .get_object()가 호출 될때, REST 프레임워크의 일반 뷰에 의해 실행됩니다.


사용자가 만약 해당 객체에 권한이 없으면 exceptions.PermissionDenied 가 리턴됩니다.


자신의 View를 작성하고 있고, 오브젝트 레벨 권한을 적용하려는 경우나 일반 View에서 get_object를 오버라이드 하는 경우 오브젝트를 검사한 시점에서 뷰에서 .check_object_permissions(request, obj) 를 호출해야 합니다.


[예제]


def get_object(self):
    obj = get_object_or_404(self.get_queryset())
    self.check_object_permissions(self.request, obj)
    return obj

[권한 정책 설정]


기본 권한 정책을 설정할 수 있는데 DEFAULT_PERMISSION_CLASSES 를 사용해서 기본 권한 정책을 사용 할 수 있습니다.


REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.IsAuthenticated',
    )
}

지정하지 않으면 설정은 기본적으로 제한없는 엑세스를 허용합니다.


'DEFAULT_PERMISSION_CLASSES': (
   'rest_framework.permissions.AllowAny',
)

또한 클래스 기반 APIView 를 사용해서 VIew마다 또는 viewSet마다 인증 정책을 설정할 수 있습니다.


from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView

class ExampleView(APIView):
    permission_classes = (IsAuthenticated,)

    def get(self, request, format=None):
        content = {
            'status': 'request was permitted'
        }
        return Response(content)

데코레이터를 사용 할 수도 있습니다.


from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response

@api_view(['GET'])
@permission_classes((IsAuthenticated, ))
def example_view(request, format=None):
    content = {
        'status': 'request was permitted'
    }
    return Response(content)

[API 레퍼런스]


AllowAny


제한되지 않은 엑세스를 허용합니다.

IsAuthenticated


인증되지 않은 사용자에게 권한을 거부하고 그렇지 않으면 허용합니다.

IsAdminUser


IsAdminUser 권한 클래스는 user.is_staff가 True인 경우를 제외하고 모든 사용자의 권한을 거부합니다.

IsAuthenticatedOrReadOnly


이 권한은 API에서 익명 사용자에게 읽기 권한만 허용하고, 인증된 사용자에게는 쓰기 읽기권한을 허용하려는 경우에 적합합니다.



[커스텀퍼미션]


BasePermission을 상속받고,


  • .has_permission(self, request, view)
  • .has_object_permission(self, request, view, obj)

해당 2가지 함수를 오버라이딩 해야합니다.

요청에 대한 엑세스 권한이 부여되면 메서드는 True를 반환, 그렇지 않으면 False를 반환해야만 합니다.


요청이 읽기 작업인지, 아니면 쓰기 작업인지 알아야 하는경우 SAFE_METHODS 상수와 비교해서 요청방법을 확인해합니다.


if request.method in permissions.SAFE_METHODS:
    # Check permissions for read-only request
else:
    # Check permissions for write request

검사 방법은 has_permission 검사가 통과 되어야지만, has_object_permission이 호출 된다는것을 명심하시기 바랍니다.

테스트가 실패 할 경우 사용자 지정 권한은 PermissionDenied 예외를 발생시킵니다.


예외와 관련된 오류 메세지를 변경하려면 message = '에러메세지' 를 사용하십시오.


from rest_framework import permissions

class CustomerAccessPermission(permissions.BasePermission):
    message = 'Adding customers not allowed.'

    def has_permission(self, request, view):

[예제]


다음은 들어오는 요청의 IP 주소를 블랙리스트와 대조해서 IP가 블랙리스트에 올랐으면 요청을 거부하는 권한클래스의 예입니다.


from rest_framework import permissions

class BlacklistPermission(permissions.BasePermission):
    """
    Global permission check for blacklisted IPs.
    """

    def has_permission(self, request, view):
        ip_addr = request.META['REMOTE_ADDR']
        blacklisted = Blacklist.objects.filter(ip_addr=ip_addr).exists()
        return not blacklisted

들어오는 모든 요청 (POST,GET,PUT...) 에 대해 실행되는 전역 권한 뿐만 아니라 특정 개체 인스턴스에 영향을 주는 작업에 대해서만 실행되는 개체수준 사용권한을 만들 수도 있습니다.


class IsOwnerOrReadOnly(permissions.BasePermission):
    """
    Object-level permission to only allow owners of an object to edit it.
    Assumes the model instance has an `owner` attribute.
    """

    def has_object_permission(self, request, view, obj):
        # Read permissions are allowed to any request,
        # so we'll always allow GET, HEAD or OPTIONS requests.
        if request.method in permissions.SAFE_METHODS:
            return True

        # Instance must have an attribute named `owner`.
        return obj.owner == request.user


Posted by C마노
,

[Python] YAPF

Python 2017. 3. 11. 14:59

YAPF

구글에서 제공하는 python Formatter


원래는 기존에 제공하는 autopep8을 사용하려고 했지만, 좀더 효율적인 포멧터를 찾아보려고 찾는 중에, 구글에서 제공하는 yapf 라는 포맷터를 찾았다.


이 포맷터에 대해서 포스팅 해보려고 한다.


지금 현재 잘 알려진 포맷터는 autopep8이랑, pep8ify가 있는데, 기본적으로 lint에서 나오는 Error을 해결하려고 만들어 졌다.


그런데 해당 포맷터들은 제한적일 수 밖에없는데, 어떤 것이냐면, PEP 8의 가이드를 정확히 따르고 있는 코드라면, 해당 코드들은 포맷팅을 하지 않는다.


pep8의 가이드만 준수한다고 해당 코드가 좋다고 볼수 없다.


YAPF는 다른방법으로 포맷팅을 하는데, Daniel Jasper가 개발한 'clang-format'을 기반으로 한다.


이 알고리즘은 코드를 가지고 와서 스타일 가이드를 준수하는 최상의 포맷으로 다시 포맷한다.

즉, PEP8의 가이드를 정확히 따르고 있는 코드더라도 다시 Reformatting 을 할 수 있다는 뜻이다.


Installation


설치방법은 간단하다.


$ pip install yapf

해당 방법으로 설치하면 되지만 YAPF는 계속적으로 바뀔수 있으므로, 가장 최신 버전을 유지하는 가장 좋은 방법은 저장소를 복제하는 방법이다.


Usage

옵션은 아래와 같다.


usage: yapf [-h] [-v] [-d | -i] [-r | -l START-END] [-e PATTERN]
            [--style STYLE] [--style-help] [--no-local-style] [-p]
            [files [files ...]]

Formatter for Python code.

positional arguments:
  files

optional arguments:
  -h, --help            show this help message and exit
  -v, --version         show version number and exit
  -d, --diff            print the diff for the fixed source
  -i, --in-place        make changes to files in place
  -r, --recursive       run recursively over directories
  -l START-END, --lines START-END
                        range of lines to reformat, one-based
  -e PATTERN, --exclude PATTERN
                        patterns for files to exclude from formatting
  --style STYLE         specify formatting style: either a style name (for
                        example "pep8" or "google"), or the name of a file
                        with style settings. The default is pep8 unless a
                        .style.yapf or setup.cfg file located in one of the
                        parent directories of the source file (or current
                        directory for stdin)
  --style-help          show style settings and exit
  --no-local-style      don't search for local style definition (.style.yapf)
  -p, --parallel        Run yapf in parallel when formatting multiple files.
                        Requires concurrent.futures in Python 2.X

Formatting style

YAPF에서 사용하는 STYLE은 얼마든지 설정을 구성할 수 있고, 서식을 지정하는 여러가지 방법들이 있습니다.

코드안에 style.py을 참조하면 전체리스트를 볼수 있습니다.


스타일을 제어하려면 --style 아규먼트를 사용하면 됩니다. 이미 구성되어진 사전 정의된 스타일 ( EX : pep8 또는 google )중 하나를 선택하거나 원하는 구성파일을 직접 지정해도 됩니다.


설정 파일은 [스타일] 표제가 있는 key = value 쌍의 간단한 목록입니다 . 아래를 보시죠.


[style]
based_on_style = pep8
spaces_before_comment = 4
split_before_logical_operator = true

아래와 같은 방법으로 사용가능합니다.


--style='{based_on_style: chromium, indent_width: 4}'

YAPF는 다음과 같은 방식으로 서식 스타일을 검색합니다.


1. 커맨드라인 

2. 현재나, 상위 디렉토리중 하나에 있는 .stype.yapf파일.


2개 찾는법이 있으나 생략 (보통 위2가지를 지정해서 사용할거 같으므로) 없으면


기본적으로 PEP8 방식을 사용함.


Example

어떤식으로 포맷팅 되는지 봅시다.


x = {  'a':37,'b':42,

'c':927}

y = 'hello ''world'
z = 'hello '+'world'
a = 'hello {}'.format('world')
class foo  (     object  ):
  def f    (self   ):
    return       37*-+2
  def g(self, x,y=42):
      return y
def f  (   a ) :
  return      37+-+a[42-x :  y**3]


포멧팅!


x = {'a': 37, 'b': 42, 'c': 927}

y = 'hello ' 'world'
z = 'hello ' + 'world'
a = 'hello {}'.format('world')


class foo(object):
    def f(self):
        return 37 * -+2

    def g(self, x, y=42):
        return y


def f(a):
    return 37 + -+a[42 - x:y**3]


'Python' 카테고리의 다른 글

Pycharm 에서 무조건 세팅해줘야 할것.  (0) 2017.05.18
[Flask] Flask - wsgi - nginx 연동.  (0) 2017.05.15
[Python] python getter setter  (0) 2017.02.16
[Python] 공부해야 할 것.  (0) 2017.02.15
[Python]pywin32 설치기.  (0) 2016.12.15
Posted by C마노
,

함수 기반 View 가아닌 Class 기반 View를 사용해서 API View를 작성할 수도 있습니다.

여러분도 잘 알듯이 클래스기반 View는 일반적인 기능을 재사용 할수있는 강력한 패턴입니다. 그리고 코드의 유지를 훨씬 효율적으로 할수 있습니다.


[ 클래스 기반 View를 사용해서 다시 API를 작성해봅시다.]


먼저 Root View를 클래스 기반 View로 다시 작성해봅시다. views.py를 열어주세요.


from snippets.models import Snippet
from snippets.serializers import SnippetSerializer
from django.http import Http404
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status


class SnippetList(APIView):
    """
    List all snippets, or create a new snippet.
    """
    def get(self, request, format=None):
        snippets = Snippet.objects.all()
        serializer = SnippetSerializer(snippets, many=True)
        return Response(serializer.data)

    def post(self, request, format=None):
        serializer = SnippetSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

이전의 경우와 매우 비슷하게 보이지만 Http메소드를 구분하기에 훨씬 쉽습니다. 


class SnippetDetail(APIView):
    """
    Retrieve, update or delete a snippet instance.
    """
    def get_object(self, pk):
        try:
            return Snippet.objects.get(pk=pk)
        except Snippet.DoesNotExist:
            raise Http404

    def get(self, request, pk, format=None):
        snippet = self.get_object(pk)
        serializer = SnippetSerializer(snippet)
        return Response(serializer.data)

    def put(self, request, pk, format=None):
        snippet = self.get_object(pk)
        serializer = SnippetSerializer(snippet, data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    def delete(self, request, pk, format=None):
        snippet = self.get_object(pk)
        snippet.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)

Detail도 마찬가지로 함수뷰와 비슷하지만 보기에 훨씬 이뻐보입니다. 

클래스 기반 View를 사용하기 때문에 url.py를 살짝 리팩토링해야합니다.


from django.conf.urls import url
from rest_framework.urlpatterns import format_suffix_patterns
from snippets import views

urlpatterns = [
    url(r'^snippets/$', views.SnippetList.as_view()),
    url(r'^snippets/(?P<pk>[0-9]+)/$', views.SnippetDetail.as_view()),
]

urlpatterns = format_suffix_patterns(urlpatterns)

이제, 개발서버를 실행하면 모든 것이 이전과 같이 작동해야 합니다.


[ mixins 사용 ]


클래스 기반 뷰를 사용하면서 얻은 가장 큰 장점 중 하나는 재사용을 쉽게 구성할 수 있다는 것입니다.

지금까지 구현되어온것을 보면 create/retrieve/update/delete 는 공통적으로 사용되는데요.

이러한 공통된 동작은 REST FRAMEWORK의 mixin 클래스에서 구현가능합니다.


mixin 클래스를 사용해서 뷰를 구성하는 방법을 살펴보겠습니다. 여기에 views.py 모듈이 있습니다.


from snippets.models import Snippet
from snippets.serializers import SnippetSerializer
from rest_framework import mixins
from rest_framework import generics

class SnippetList(mixins.ListModelMixin,
                  mixins.CreateModelMixin,
                  generics.GenericAPIView):
    queryset = Snippet.objects.all()
    serializer_class = SnippetSerializer

    def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        return self.create(request, *args, **kwargs)

GenericAPIView를 사용하고 ListModelMixin 및 CreateModelMixin 을 추가해서 뷰를 작성합니다.


베이스클래스는 핵심기능을 제공하고 mixin 클래스는 .list() 및 .create() 를 제공합니다.

그런다음 get및 post 메소드를 명시적으로 적절한 액션에 바인딩합니다. 


이전과 거의 비슷하지만. GenericAPIView 클래스를 사용해서 핵심 기능을 제공하고 .retrieve(), .update(), 및 .destroy() 액션을 제공하기 위해서 mixin 을 추가합니다.


[ 제네릭 클래스 기반 뷰 사용 ]


mixin 클래스를 사용해서 이전보다 적은 코드를 사용하기 위해 뷰를 새로작성했지만 좀더 나아가봅시다.


from snippets.models import Snippet
from snippets.serializers import SnippetSerializer
from rest_framework import generics


class SnippetList(generics.ListCreateAPIView):
    queryset = Snippet.objects.all()
    serializer_class = SnippetSerializer


class SnippetDetail(generics.RetrieveUpdateDestroyAPIView):
    queryset = Snippet.objects.all()
    serializer_class = SnippetSerializer

와.. 이번엔 진짜 간결합니다. 굉장히 코드는 훌륭하고 깨끗하며 관용적인 장고처럼 보입니다.



Posted by C마노
,