django 1.5 における効果的な mtv 設計 & ネイティブapp

Download Django 1.5 における効果的な MTV 設計 & ネイティブApp

If you can't read please download the document

Upload: yikei-lu

Post on 16-Apr-2017

4.359 views

Category:

Technology


0 download

TRANSCRIPT

Django 1.5 MTV & App

@luyikei

@luyikei

Linux Mint, Qt, Django

1, DjangoMTVModel : 1, Model Relationships 2, Mata Options Template : 1, Python Template Engine 2, Custom tags and filters

View : 1, Sessions 2, Cookie 3, Cache

2,API OAuth (PyQt )

MTV

MTV

Django appears to be a MVC framework, but you call the Controller the view, and the View the template. How come you dont use the standard names? (https://docs.djangoproject.com/en/dev/faq/general/ )

MVC MTV

Django

Django URL

( http://www.djangoproject.jp/doc/ja/1.0/faq/general.html )

MVC

Model : 1, Model Relationships

- , -

Model -

Title : Price : 220Vegetable : LettuceMeat : HamOnEgg : True

Model -

Title : Price : 136Guzai : Salmon

class Item(models.Model): title = models.CharField(max_length=200) price = models.IntegerField()

Model

class Sandwich(Item): vegetable = models.CharField(max_length=200) meat = models.CharField(max_length=200) onEgg = models.BooleanField(default=False)

Model

class Onigiri(Item): Guzai = models.CharField(max_length=200)

Item

Onigiri Item.onigiri

Sandwich Item.sandwich

class Item(models.Model): title = models.CharField(max_length=200) price = models.IntegerField() subclass = models.CharField(max_length=200,editable=False) def save(self, *args, **kwargs): # save what kind we are. self.subclass = self.__class__.__name__ super(Item, self).save(*args, **kwargs)

def as_child(self): return getattr(self, self.subclass.lower())

i=Item.objects.get(id=1)child=i.as_child()

Model : 2, Mata Options

Django Meta

Django Models Internals Documentation

https://django-model-_meta-reference.readthedocs.org/en/latest/index.html

get_all_related_objects_with_model

Returns a list of (related-object, model) pairs. Similar to get_fields_with_model().

Related

:[(, None), (, None)]

get_parent_list

Returns a list of all the ancestor of this model as a list. Useful for determining if something is an ancestor, regardless of lineage.

()( list set )

:set([])

get_latest_by

model Manager latest() , earliest()

:get_latest_by = "order_date"

ordering

:ordering = ['-order_date']

db_table

:db_table = 'music_album'

Template : 1, Python Template Engine

Django TemplateJinja2MakoChameleon

Django Template

Django Django HTML Smarty CheetahTemplate Django

PHP HTML Django HTML Python

http://docs.djangoproject.jp/en/latest/topics/templates.html

Test[a] {{ Test.a }}Test[a][b] {{ Test.a.b }}Test[a].b() {{ Test.a.b }}Test.a.b {{ Test.a.b }}

Jinja 2

Django Template

Django Template

Method Calls: a.b() {{ a.b() }} () a[b] {{ a[b] }} ()Conditions: {% ifequal a b %} {% if a == b%} Filter Arguments: {{ items|join:", " }} {{ items|join(', ') }}

Mako

% for row in rows: ${makerow(row)} % endfor

% for name in row: ${name}\ % endfor

Mako =

Django Template

Django

Test[a] ${ Test[a] }Test[a][b] ${ Test[a][b] }Test[a].b() ${ Test[a].b() }Test.a.b ${ Test.a.b }

Chameleon

These are your items:

Chameleon TAL

TAL Zope Chameleon

XML

Django XML

Django XML/HTML

Django World Online email JavaScript CSV

http://docs.djangoproject.jp/ja/latest/topics/templates.html

:polls/ models.py templatetags/ __init__.py poll_extras.py views.py

Django templatetags

https://docs.djangoproject.com/en/dev/howto/custom-template-tags/

Django XML

: XML

http://docs.djangoproject.jp/ja/latest/topics/templates.html

Template : 2, Custom tags and filters

Django Template

django/template/defaultfilters.py

from django.template.base import Libraryregister = Library()

@register.filter(is_safe=True)@stringfilterdef lower(value): """Converts a string into all lowercase.""" return value.lower()

Django

Python

:polls/ models.py templatetags/ __init__.py poll_extras.py views.py

Django templatetags

https://docs.djangoproject.com/en/dev/howto/custom-template-tags/

:from django.template.base import Libraryregister = Library()

@register.filter()def nothing(value): pass

:from django.template.base import Libraryregister = Library()

@register.tagdef nothing(value): pass

View : 1, Sessions

HTTPCookie

http://d.hatena.ne.jp/keyword/%A5%BB%A5%C3%A5%B7%A5%E7%A5%F3

request.session[Height] = 120

:

request.session.get('Height', 0):

get(key, default=None): fav_color = request.session.get('fav_color', 'red')

:

del request.session[Height]

View : 2, Cookie

HttpResponse.set_cookie(key, value='', max_age=None, expires=None, path='/', domain=None, secure=None, httponly=False)

response = render_to_response(template_name, context)

response.set_cookie('Height', ') return response

HttpResponse.set_cookie

request.COOKIES.get('Height')

View : 3, Cache

http://e-words.jp/w/E382ADE383A3E38383E382B7E383A5.html

Memcached ()

:Memcached

settings.py CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache', 'LOCATION': '127.0.0.1:11211', }}

MIDDLEWARE_CLASSES = ( 'django.middleware.cache.UpdateCacheMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.cache.FetchFromCacheMiddleware',)

http://docs.djangoproject.jp/en/latest/topics/cache.html#id10

from django.views.decorators.cache import cache_page

@cache_page(60 * 15)def my_view(request):

from django.views.decorators.cache import cache_page

urlpatterns = ('', (r'^foo/(\d{1,2})/$', cache_page(60 * 15)(my_view)),)

http://docs.djangoproject.jp/en/latest/topics/cache.html#id10


{% load cache %}{% cache 500 sidebar %} .. sidebar ..{% endcache %}

http://docs.djangoproject.jp/en/latest/topics/cache.html#id10

2,

Django

Qt

OAuth

OAuth OAuth ( [1]) WebAPI (authorization) (Wikipedia)

API

http://www.atmarkit.co.jp/fsecurity/rensai/digid01/02.html

Django OAuth2 django-oauth-plus

Django API django-tastypie

INSTALLED_APPS

INSTALLED_APPS = ( 'tastypie', 'oauth_provider',)

API

common/api.py

from tastypie.resources import ModelResourcefrom common.models import Onigiri

class OnigiriResource(ModelResource): class Meta: queryset = Onigiri.objects.all() resource_name = 'onigiri

Urls

ecsite/urls.py

from tastypie.api import Api

from django.contrib import adminadmin.autodiscover()onigiri_resource = OnigiriResource()

v1_api = Api(api_name='v1')v1_api.register(OnigiriResource())

urlpatterns = patterns('', url(r'^api/', include(onigiri_resource.urls)),)

()

$ curl http://127.0.0.1:8000/api/v1/onigiri/?format=json{"meta": {"limit": 20, "next": null, "offset": 0, "previous": null, "total_count": 1}, "objects": [{"guzai": "gre", "id": 1, "price": 436, "resource_uri": "/admin/v1/onigiri/1/", "subclass": "Onigiri", "title": "sdg"}]}

However, if you try sending a POST/PUT/DELETE to the resource, you find yourself getting 401 Unauthorized errors. For safety, Tastypie ships with the authorization class (what are you allowed to do) set to ReadOnlyAuthorization. This makes it safe to expose on the web, but prevents us from doing POST/PUT/DELETE. Lets enable those:

http://django-tastypie.readthedocs.org/en/latest/tutorial.html

POST/PUT/DELETE API

common/api.py

from tastypie.authentication import OAuthAuthenticationfrom tastypie.authorization import DjangoAuthorizationfrom tastypie.resources import ModelResourcefrom common.models import Onigiri

class OnigiriResource(ModelResource): class Meta: queryset = Onigiri.objects.all() resource_name = 'onigiri authentication = OAuthAuthentication() authorization = DjangoAuthorization

$ curl http://127.0.0.1:8000/api/v1/onigiri/?format=jsoInvalid request parameters.

OAuth

: Consumer

$ ./manage.py shell>>> from oauth_provider.models import Consumer, Token>>> c = Consumer()>>> c.generate_random_codes()>>> c

>>> c.keyu'b10945ea448344bb8d2c7f33d38f2f0d'>>> c.secretU'AQsJnvVYn04njIVK'

http://d.hatena.ne.jp/yuheiomori0718/20120924/1348496794

: Token

$ ./manage.py shell>>> from django.contrib.auth.models import User>>> u = User.objects.all()[0]>>> t = Token()>>> t.user = u>>> t.consumer = c>>> t.token_type = 2>>> t.resource_id=0>>> t.generate_random_codes()>>> t.key'bec4fdc33725458ab2894558014844b7'>>> t.secretU'WgKrSb7QMz9CLZyX'http://d.hatena.ne.jp/yuheiomori0718/20120924/1348496794

# coding=utf-8import jsonimport requestsfrom oauth_hook import OAuthHook

consumer_key = 'b10945ea448344bb8d2c7f33d38f2f0d'consumer_secret = 'AQsJnvVYn04njIVK'access_token = 'bec4fdc33725458ab2894558014844b7'access_token_secret = 'WgKrSb7QMz9CLZyX'

oauth_hook = OAuthHook(access_token=access_token, access_token_secret=access_token_secret, consumer_key=consumer_key, consumer_secret=consumer_secret, header_auth=True)

request = requests.Request('GET', "http://127.0.0.1:8000/api/v1/onigiri/?format=json")request = oauth_hook(request)prepared = request.prepare()

session = requests.session()resp = session.send(prepared)

print resp.text

{"meta": {"limit": 20, "next": null, "offset": 0, "previous": null, "total_count": 1}, "objects": [{"guzai": "gre", "id": 1, "price": 436, "resource_uri": "/api/v1/onigiri/1/", "subclass": "Onigiri", "title": "sdg"}]}

PyQt