Upgrade to Pro — share decks privately, control downloads, hide ads and more …

youknowone-2018-pycon-ring

 youknowone-2018-pycon-ring

test :)

Hyesoo Yoo

August 18, 2018
Tweet

Transcript

  1. OOP ੉ঠӝ • userী itemਸ ୶о೧ঠ ೠ׮Ҋ ࢤп೧ ࠇद׮.
 ௿ېझо

    হח ঱যۄݶ ই݃ب user_add_item(user, item) 
 э਷ ௏٘ܳ ॶ Ѫੑפ׮. • ই݃ user_delete_itemب ੓Ҋ user_clear_itemsب ੓ѷ૑ਃ. • ೞ૑݅ ਋ܻח ౵੉ॆ ೐۽Ӓېݠפө ࠁా user.add_item(item) э਷ ௏٘ܳ ॺפ ׮.
  2. நद ੉ঠӝ • userী ࣘೠ itemٜਸ оઉয়ח ೣࣻо ੓Ҋ 


    ੉ ೣࣻח Ѿҗܳ நदೞҊ ੓׮Ҋ ࢤп೧ ࠇद׮.
 user.get_items() э਷ ௏٘ܳ ॶ ࣻب ੓Ҋ 
 user.get_cached_items(storage) э਷ ௏٘ܳ ॶ ࣻب ੓ѷ૑ਃ. • item੄ ݾ۾੉ সؘ੉౟ غ঻णפ׮. ੉ઁ நदܳ ޖബച೧ঠ ೤פ׮.
 ই݃ب user.invalidate_items()ա user.delete_cached_items(storage)
 э਷ ௏٘ܳ ٜ݅যঠ ೞѷ૑ਃ. • Ringীࢲח user.get_items.delete() ܳ ഐ୹೤פ׮.
  3. • Ring਷ ੉ ই੉٣যীࢲࠗఠ ୹ߊ೤פ׮. • ੉ ಕ੉૑ө૑ח ߊ಴ীח ನೣغ૑

    ঋ਷ ղਊੑפ׮.
 ׮਺ಕ੉૑ࠗఠ ౵੉௑ ߊ಴ ղਊ੉ द੘ؾפ׮.
  4. ৵? • झషܻ૑ח ੕যߡܻ੗ • ௏٘ী ૘઺ೞ੗ • ੋр஘ച੸ੋ ੋఠಕ੉झ۽

    ೐۽Ӓې߁ ೞ੗ • ؒ: ੹ ৔৉ী Ѧ୛ ழझఠ݃੉ૉ оמ
  5. ೠٲ ೠٲ ࣚਵ۽ • ੉۠ ױࣽೠ IOܳ ੋр੉ ߈ࠂ೧ࢲ ೞݶ...

    ૑Ҁ׮ ૞ૐդ׮ ইޖ ࢤп੉ হ׮ ࣚоۅب ൨ٜ׮
  6. ೠٲ ೠٲ ࣚਵ۽ • ੉۠ ױࣽೠ IOܳ ੋр੉ ߈ࠂ೧ࢲ ೞݶ...

    ૑Ҁ׮ ૞ૐդ׮ ইޖ ࢤп੉ হ׮ ࣚоۅب ൨ٜ׮ पࣻೠ׮
  7. ࠺Ѿ੿੸ ೣࣻ • ೐۽Ӓې߁ ࣁ҅ח ࠗ੘ਊਵ۽ оٙ ର ੓׮ “ஹೊఠ

    җ೟ীࢲ ೣࣻо Ѿҗч ੉৻ী ׮ܲ ࢚కܳ ߸҃दఆ ٸ ࠗ੘ਊ੉ ੓׮Ҋ
 ݈ೠ׮. (... ઺ۚ ...) ࠗ੘ਊ਷ ೐۽Ӓ۔੄ ز੘ਸ ੉೧ೞӝ য۵ѱ ೠ׮.” ࠗ੘ਊ(ஹೊఠ җ೟) - ਤఃߔҗ ೠҴয౸
  8. ࠺Ѿ੿੸ ೣࣻ • ೐۽Ӓې߁ ࣁ҅ח ࠗ੘ਊਵ۽ оٙ ର ੓׮ “ஹೊఠ

    җ೟ীࢲ ೣࣻо Ѿҗч ੉৻ী ׮ܲ ࢚కܳ ߸҃दఆ ٸ ࠗ੘ਊ੉ ੓׮Ҋ
 ݈ೠ׮. (... ઺ۚ ...) ࠗ੘ਊ਷ ೐۽Ӓ۔੄ ز੘ਸ ੉೧ೞӝ য۵ѱ ೠ׮.” ࠗ੘ਊ(ஹೊఠ җ೟) - ਤఃߔҗ ೠҴয౸
  9. ࠺Ѿ੿੸ ೣࣻ # 60 * 15 ୡ زউ ਬബೠ நद

    ࢤࢿ # cache_page: Djangoীࢲ ౠ੿ HTTP ਃ୒੄ ਽׹ਸ ੌ੿ӝр நद೧ ઱ח decorator
  10. ࠺Ѿ੿੸ ೣࣻ # 60 * 15 ୡ زউ ਬബೠ நद

    ࢤࢿ PyConী য়न Django ࢎਊ੗ ৈ۞࠙, ੉Ѣ ॳࣁਃ? # cache_page: Djangoীࢲ ౠ੿ HTTP ਃ୒੄ ਽׹ਸ ੌ੿ӝр நद೧ ઱ח decorator
  11. ࠺Ѿ੿੸ ೣࣻ # 60 * 15 ୡ زউ ਬബೠ நद

    ࢤࢿ PyConী য়न Django ࢎਊ੗ ৈ۞࠙, ੉Ѣ ॳࣁਃ? நद ޖബച दఃҊ ੤ࢤࢿ ೞ۰ݶ..? # cache_page: Djangoীࢲ ౠ੿ HTTP ਃ୒੄ ਽׹ਸ ੌ੿ӝр நद೧ ઱ח decorator
  12. Ring • Sub-function control • Methods & descriptor support •

    Key Consistency • Backend: memcache, redis, diskcache, shelve, dict • asyncio support • Fully customizable • Django integration
  13. Sub-functions • ӝࠄ ೣࣻ import ring @ring.dict({}) def function(v): return

    ... import functools @functools.lru_cache() def function(v) return ... Ring lru_cache
  14. Sub-functions • ݅ܐо ੓ח ҃਋ from django… \ import cache_page

    @cache_page(60) def view(request): return ... import ring @ring.dict( {}, expire=60) def function(v): return ... Ring Django per-view cache
  15. Sub-functions • ӝࠄ ೣࣻ • ӝࠄ प೯ & நद value

    = function(10) value = function(10) import ring @ring.dict({}) def function(v): return ... import functools @functools.lru_cache() def function(v) return ... Ring lru_cache
  16. Sub-functions • ૊द সؘ੉౟ • ؀਽ೞח python-memcached key = create_key(10)

    value = function(10) client.set(key) value = \ function.update(10)
  17. Sub-functions • ӝࠄ प೯ & நद • ؀਽ೞח python-memcached value

    = function(10)
 
 value = function\ .get_or_update(10) key = create_key(10) value = client.get(key) if value is None: value = function(10) client.set(key)
  18. Sub-functions • ӝࠄ प೯ & நद • ࣻز ࢏ઁ •

    நद݅ оઉয়ӝ • ૊द সؘ੉౟ • प೯݅ • ١١... value = function(10) function.delete(10) value = function.update(10) value = function.execute(10) value = function.get(10)
  19. Sub-functions • get_many • set_many, update_many, get_or_update_many … @ring.memcache(...) def

    f(a, b): ... # getting data for f(1, 2), f(1, 3), f(a=2, b=2) data = f.get_many((1, 2), (1, 3), {'a': 2, 'b': 2}) # dataח ч੄ sequence(list)
  20. Sub-functions • get_many • set_many, update_many, get_or_update_many … @ring.memcache(...) def

    f(a, b): return a * 100 + b # getting data for f(1, 2), f(1, 3), f(a=2, b=2) data = f.get_many((1, 2), (1, 3), {'a': 2, 'b': 2}) assert data == [102, 103, 202]
  21. Sub-functions • get_many • execute_many, set_many, update_many, get_or_update_many …, @ring.memcache(...)

    def f(a, b): return a * 100 + b # getting data for f(1, 2), f(1, 3), f(a=2, b=2) data = f.get_many((1, 2), (1, 3), {'a': 2, 'b': 2}) assert data == [102, 103, 202]
  22. Ring • Sub-function control • Methods & descriptor support •

    Key Consistency • Backend: memcache, redis, diskcache, shelve, dict • asyncio support • Fully customizable • Django integration
  23. Methods & Descriptors class UserAPI(object): url_prefix = 'https://...' secret_key =

    '...' def __init__(self, user_id): self.user_id = user_id # cache? @classmethod def api_status(cls): return request( f'{cls.url_prefix}/status') # cache? def get_user(self, n): return request( f'{cls.url_prefix}/users/{n}')
  24. Methods & Descriptors • ݫࢲ٘ܳ ׮ܖ۰ݶ? • (ࠁా਷) • ৻ࠗী

    ೣࣻ۽ ࡐѢա • In-house۽ ઁಿী ݏѱ ٜ݅য
 ॳѢա class UserAPI(object): url_prefix = 'https://...' secret_key = '...' def __init__(self, user_id): self.user_id = user_id # cache? @classmethod def api_status(cls): return request( f'{cls.url_prefix}/status') # cache? def get_user(self, n): return request( f'{cls.url_prefix}/users/{n}')
  25. Methods & Descriptors • Ring: ੌҙࢿ ੓ח ੋఠಕ੉झ class UserAPI(object):

    url_prefix = 'https://...' secret_key = '...' def __init__(self, user_id): self.user_id = user_id @ring.dict({}, expire=5) @classmethod def api_status(cls): return request( f'{cls.url_prefix}/status') @ring.dict({}, expire=60) def get_user(self, n): return request( f'{cls.url_prefix}/users/{n}')
  26. Methods & Descriptors • Ring: ੌҙࢿ ੓ח ੋఠಕ੉झ • (free)

    function • method • classmethod • staticmethod • property • custom descriptors • hybridmethod? hybridproperty? • ੐੄੄ descriptorী ؀਽ class UserAPI(object): url_prefix = 'https://...' secret_key = '...' def __init__(self, user_id): self.user_id = user_id @ring.dict({}, expire=5) @classmethod def api_status(cls): return request( f'{cls.url_prefix}/status') @ring.dict({}, expire=60) def get_user(self, n): return request( f'{cls.url_prefix}/users/{n}')
  27. Methods & Descriptors • Q: Ringҗ ࠺तೠ method/descriptor ૑ਗਸ ٜ݅۰ݶ

    যڌѱ ೞաਃ? • A: https://github.com/youknowone/wirerope
  28. Ring • Sub-function control • Methods & descriptor support •

    Key Consistency • Backend: memcache, redis, diskcache, shelve, dict • sync/asyncio support • Fully customizable • Django integration
  29. Key consistency • э਷ ੄޷੄ ೣࣻ ੋ੗ী ؀೧ э਷ ఃܳ

    ࢤࢿೞח ޙઁ • ݅ܐ(expire, invalidate) ٸޙী ઺ਃೠ ޙઁ
  30. Key consistency • э਷ ੄޷੄ ೣࣻ ੋ੗ী ؀೧ э਷ ఃܳ

    ࢤࢿೞח ޙઁ • ݅ܐ(expire, invalidate) ٸޙী ઺ਃೠ ޙઁ function(1) function(v=1) э਷ ੄޷ੋؘ ੹׳ػ ੋ੗ ഋधী ٮۄ ׮ܲ ఃܳ ݅ٚ׮ݶ? @functools.lru_cache(
 maxsize=64) def function(v): return ...
  31. Key consistency • э਷ ੄޷੄ ೣࣻ ੋ੗ী ؀೧ э਷ ఃܳ

    ࢤࢿೞח ޙઁ • ݅ܐ(expire, invalidate) ٸޙী ઺ਃೠ ޙઁ function(1) function(v=1) @functools.lru_cache(
 maxsize=64) def function(v): return ... э਷ ੄޷ੋؘ ੹׳ػ ੋ੗ ഋधী ٮۄ ׮ܲ ఃܳ ݅ٚ׮ݶ? ੉ ҃਋ח ࢿמ਷ ખ ڄযઉب ௾ ޙઁח হ૑݅...
  32. Key consistency • э਷ ੄޷੄ ೣࣻ ੋ੗ী ؀೧ э਷ ఃܳ

    ࢤࢿೞח ޙઁ • ݅ܐ(expire, invalidate) ٸޙী ઺ਃೠ ޙઁ function.delete(1) function(v=1) @ring.dict({}) def function(v): return ... э਷ ੄޷ੋؘ ੹׳ػ ੋ੗ ഋधী ٮۄ ׮ܲ ఃܳ ݅ٚ׮ݶ?
  33. Key consistency • э਷ ੄޷੄ ೣࣻ ੋ੗ী ؀೧ э਷ ఃܳ

    ࢤࢿೞח ޙઁ • ݅ܐ(expire, invalidate) ٸޙী ઺ਃೠ ޙઁ function.delete(1) function(v=1) @ring.dict({}) def function(v): return ... э਷ ੄޷ੋؘ ੹׳ػ ੋ੗ ഋधী ٮۄ ׮ܲ ఃܳ ݅ٚ׮ݶ? ੉ ҃਋ח ࢎਊ੗ ੑ੢ীࢲ ঌӝ ൨ٚ ߡӒ ߊࢤ
  34. Key consistency • э਷ ੄޷੄ ೣࣻ ੋ੗ী ؀೧ э਷ ఃܳ

    ࢤࢿೞח ޙઁ • ݅ܐ(expire, invalidate) ٸޙী ઺ਃೠ ޙઁ >>> import sample sample.f:1:2 sample.f:1:2 sample.f:1:2 import ring @ring.dict({}) def f(a, *, b): return ... print(f.key(1, b=2)) print(f.key(a=1, b=2)) print(f.key(**{'a': 1, 'b': 2}))
  35. Key consistency • э਷ ੄޷੄ ೣࣻ ੋ੗ী ؀೧ э਷ ఃܳ

    ࢤࢿೞח ޙઁ • ݅ܐ(expire, invalidate) ٸޙী ઺ਃೠ ޙઁ >>> import sample sample.A.f:A():1 sample.A.g:A:2 sample.A.g:A:3 import ring class A(object): def __ring_key__(self): return 'A()' @ring.dict({}) def f(self, a): pass @ring.dict({}) @classmethod def g(cls, a): pass a = A() print(a.f.key(a=1)) print(a.g.key(a=2)) print(A.g.key(a=3))
  36. Key policy • э਷ ੄޷੄ ഐ୹ ؀೧ ೦࢚ 1ѐ੄ நद(ః)݅

    ઓ੤ೞח Ѫਸ ࠁ੢ • ఃܳ ݅٘ח ೣࣻ݅ ٮ۽ ഐ୹ оמ (౵੉ॆ ೐۽ં౟р ഐജ) • ೧दо ইצ ੄޷੓ח ޙ੗ৌ (࠺ ౵੉ॆ ೐۽ં౟р ഐജ)
  37. Ring • Sub-function control • Methods & descriptor support •

    Key Consistency • Backend: memcache, redis, diskcache, shelve, dict • asyncio support • Fully customizable • Django integration
  38. Backends @ring.dict(s) @ring.shelve(s) @ring.memcache(s) @ring.redis(s) @ring.diskcache(s) @ring.django.cache() dict shelve.Shelf memcache.Client

    (python-memcached) pylibmc.Client pymemcache.client.Client aiomcache.Client redis.Client aioredis.Client diskcache.Cache django.core.cache.caches
  39. Ring • Sub-function control • Methods & descriptor support •

    Key Consistency • Backend: memcache, redis, diskcache, shelve, dict • asyncio support • Fully customizable • Django integration
  40. Backends @ring.dict(s) @ring.shelve(s) @ring.memcache(s) @ring.redis(s) @ring.diskcache(s) dict shelve.Shelf memcache.Client (python-memcached)

    pylibmc.Client pymemcache.client.Client aiomcache.Client redis.Client aioredis.Client diskcache.Cache
  41. Backends • Q: ࢜۽਍ ߔূ٘ܳ ୶оೞ۰ݶ? • A: ௏٘ܳ 30઴

    ૠ׮ class MemcacheStorage( fbase.CommonMixinStorage, fbase.StorageMixin, BulkStorageMixin): def get_value(self, key): value = self.backend.get(key) if value is None: raise fbase.NotFound return value def set_value(self, key, value, expire): self.backend.set(key, value, expire) def delete_value(self, key): self.backend.delete(key) def touch_value(self, key, expire): self.backend.touch(key, expire) def get_many_values(self, keys): values = self.backend.get_multi(keys) return [values.get(k, fbase.NotFound) for k in keys] def set_many_values(self, keys, values, expire): self.backend.set_multi({k: v for k, v in zip(keys, values)}, expire) def delete_many_values(self, keys): return self.backend.delete_multi(keys)
  42. Ring • Sub-function control • Methods & descriptor support •

    Key Consistency • Backend: memcache, redis, diskcache, shelve, dict • asyncio support • Fully customizable • Django integration
  43. Storage Key sample.article:42 new_prefix:42 @ring.memcache(client) def article(id): return ... print(article.key(42))

    @ring.memcache(client, key_prefix='new_prefix') def article(id): return ... print(article.key(42)) case1: prefix config
  44. Storage Key sample.article:42 a42e @ring.memcache(client) def article(id): return ... print(article.key(42))

    @article.ring.key def article_key(id): return f'a{id}e' print(article.key(42)) case2: key function override
  45. Data Encoder dict(id=42, name='Name') dict(id=42, name='Name') @ring.dict({}) def user1(id): return

    { 'id': id, 'name': 'Name'} print(user1(42)) @ring.dict( {}, coder='json') def user2(id): return { 'id': id, 'name': 'Name'} print(user2(42))
  46. Data Encoder dict(id=42, name='Name') # = json.dumps(user1(42)) b'{"id": id, "name":

    "Name"}' d1 = {} @ring.dict(d1) def user1(id): return { 'id': id, 'name': 'Name'} print(d1[42]) d2 = {} @ring.dict(d2, coder='json') def user2(id): return { 'id': id, 'name': 'Name'} print(d2[42])
  47. Data Encoder # = json.dumps(user1(42)) '{"id": id, "name": "Name"}' d1

    = {} @ring.dict(d1) def user1(id): return { 'id': id, 'name': 'Name'} @user1.ring.encode def user_encode(v): return json.dumps(v) @user1.ring.decode def user_decode(v): return json.loads(v) print(d1[42]) case1: single function coder
  48. Data Encoder import json import ring ring.coder.register( 'json', (json.dumps, json.loads))

    import pickle import ring ring.coder.register( 'pickle', (pickle.dumps, pickle.loads)) case2: reusable coder
  49. Strategy • __call__, get, update, delete ١ਸ ੤੿੄ೞ۰ݶ? • ࢜۽਍

    ݫࢲ٘ܳ ୶оೞ۰ݶ? • ex: োҙػ ݽٚ ؘ੉ఠܳ ೠߣী ૑਋ח ݫࢲ٘о ೙ਃೞ׮ • நद ੿଼ਸ ߄Բ۰ݶ? • ex: ࢸ੿࢚ expire غযب நदܳ թѹف঻׮ hitೞѱ ೧ࢲ ࢿמ хࣗܳ ݄ѷ׮ •
  50. Strategy • __call__, get, update, delete ١ਸ ੤੿੄ೞ۰ݶ? • ࢜۽਍

    ݫࢲ٘ܳ ୶оೞ۰ݶ? • ex: োҙػ ݽٚ ؘ੉ఠܳ ೠߣী ૑਋ח ݫࢲ٘о ೙ਃೞ׮ • நद ੿଼ਸ ߄Բ۰ݶ? • ex: ࢸ੿࢚ expire غযب நदܳ թѹف঻׮ hitೞѱ ೧ࢲ ࢿמ хࣗܳ ݄ѷ׮ • UserInterface
  51. Low-level Interface @ring.memcache(client, key_prefix='article') def article(id): return ... key =

    article.key(42) # key݅ ٜ݅ӝ encoded = client.get(key) # memcacheীࢲ get data = article.decode(encoded) # ਗࠄؘ੉ఠ۽
  52. Low-level Interface @ring.memcache(client, key_prefix='article') def article(id): return ... key =

    article.key(42) # key݅ ٜ݅ӝ encoded = client.get(key) # memcacheীࢲ get data = article.decode(encoded) # ਗࠄؘ੉ఠ۽ data = article.get(42) # ਤ 3઴җ э਷ ௏٘
  53. inspect.signature In [1]: def f(a, b, *args, x, y=10, **kw):

    ...: pass ...: In [2]: import inspect In [3]: s = inspect.signature(f) Out[4]: <Signature (a, b, *args, x, y=10, **kw)> In [6]: for name, parameter in s.parameters.items(): ...: print(name, parameter.kind, parameter.default) ...: a POSITIONAL_OR_KEYWORD <class 'inspect._empty'> b POSITIONAL_OR_KEYWORD <class 'inspect._empty'> args VAR_POSITIONAL <class 'inspect._empty'> x KEYWORD_ONLY <class 'inspect._empty'> y KEYWORD_ONLY 10 kw VAR_KEYWORD <class 'inspect._empty'>
  54. qualname • ݽٕ উীࢲ ೞա੄ ௿ېझ/ೣࣻܳ оܻఃח
 Ѣ੄ ਬੌೠ ੉ܴ

    • ࢤࢿ द੼ী ഋࢿ 
 (py2੄ im_classࠁ׮ ࡅܰѱ!) • Python 3.3+ >>> class C: ... def f(): pass ... class D: ... def g(): pass ... >>> C.__qualname__ 'C' >>> C.f.__qualname__ 'C.f' >>> C.D.__qualname__ 'C.D' >>> C.D.g.__qualname__ 'C.D.g'
  55. annotation • def f(a: int, b: int) -> int:
 return

    a + b
 print(f.__annotations__)
 {'a': <class 'int'>, 'b': <class 'int'>, 'return': <class 'int'>} • inspect.signature(f).return_annotation
 int • inspect.signature(f.get).return_annotation
 Optional[int] • inspect.signature(f.key).return_annotation
 str
  56. pickle, shelve • pickle: ౵੉ॆ ё୓ܳ ؘ੉ఠ۽ serialize ೞח ߑߨ

    • shelve: pickleਸ ੉ਊೠ dict ੋఠಕ੉झܳ о૑ח ౵ੌDB • ل ݽف য়ے ౵੉ॆ ಴ળ ۄ੉࠳۞ܻ
  57. Methods & Descriptors • Q: Ringҗ ࠺तೠ method/descriptor ૑ਗਸ ٜ݅۰ݶ

    যڌѱ ೞաਃ? • A: https://github.com/youknowone/wirerope • Rope: ೣࣻ दӒפ୊ী ؀਽೧ ੉ ೣࣻ ੉ܴী ؀਽
 (unbound ೣࣻ ੿੄ܳ Rope ё୓۽ ஖ജ) • Wire: ੋझఢझ੄ ҳ୓ ೣࣻী ؀਽೧ пӝ ׮ܲ ੋझఢझ(method),
 ௿ېझ(classmethod)੄ ೣࣻ ഐ୹ী ؀਽
 (ё୓ী bind ػ ೣࣻܳ Wire ё୓۽ ஖ജ) • hybridmethod, hybridproperty ١੄ ੌ߈੸ੋ ழझథ ҳഅীب ੜ ؀਽
  58. Descriptor analysis • ҙबࢎ೦: • ೣࣻੋо ݫࢲ٘ੋо? • descriptorੋо? •

    methodੋо propertyੋо? • descriptorীࢲ ߄ੋ٘ غח ё୓ח ޖ঺ੋо?
 (= methodੋо classmethodੋо - য૵ݶ hybridੋо) • descriptorо хऱҊ ੓ח पઁ ೣࣻח ޖ঺ੋо? • ৈ۞ ౵੉ॆ ҳഅ୓৬ ߡ੹ীࢲ ഐജغחо?
  59. Descriptor analysis • ҙबࢎ೦: • ೣࣻੋо ݫࢲ٘ੋо? • descriptorੋо? •

    methodੋо propertyੋо? • descriptorীࢲ ߄ੋ٘ غח ё୓ח ޖ঺ੋо?
 (= methodੋо classmethodੋо - য૵ݶ hybridੋо) • descriptorо хऱҊ ੓ח पઁ ೣࣻח ޖ঺ੋо? • ৈ۞ ౵੉ॆ ҳഅ୓৬ ߡ੹ীࢲ ഐജغחо? ߡ੹߹ ߸஗ ࣽഥ 2.7, 3.4-3.7 / PyPy2 PyPy3 def _f(owner): return owner
  60. Django app in single file • Django ഛ੢ਸ ٜ݅঻חؘ పझ౟ܳ

    ೧ঠغחؘ... • ழ׮ۆ জਸ పझ౟ ௏٘ী ׳Ҋ ׮ק ࣻח হਗ਼ই? • 30઴૞ܻ Django appਸ ٜ݅যࢲ పझ౟௏٘ী ղ੢೤פ׮ • https://github.com/youknowone/django-app-in-single-file