Django:Tips & Tricksby Renyi Khorrenyi.ace@gmail.com@renyikhorhttps://github.com/renyi/django-tips-and-tricksWednesday, Ju...
DisclaimerWednesday, June 19, 13
Disclaimer• I’m not a super pro pythonista, but I’m avery lazy one.Wednesday, June 19, 13
Disclaimer• I’m not a super pro pythonista, but I’m avery lazy one.• Speed - means programmer’s programmingspeed, unless s...
Disclaimer• I’m not a super pro pythonista, but I’m avery lazy one.• Speed - means programmer’s programmingspeed, unless s...
Disclaimer• I’m not a super pro pythonista, but I’m avery lazy one.• Speed - means programmer’s programmingspeed, unless s...
ACE EdVenture PixelHead of R&D and Lead DeveloperSchoolHubSchool Management SystemWhat we use python for ?SchoolHub is bui...
ACE EdVenture StudioHead of R&DChemQuest: Petticles in PerilChemistry based RPG game.What we use python for ?Most of the w...
#1: Boilerplate Everything(that you can)Wednesday, June 19, 13
settings.pyWednesday, June 19, 13
• use lists[] instead of tuples() in default_settings.py• Use list methods - add(), remove(), +=• Default naming conventio...
1 # default_settings.py23 DEBUG = False4 TEMPLATE_DEBUG = False5 USE_SOUTH = True6 ADMINS = [(Devtune Admin, admin@devtune...
1 # settings.py23 from .default_settings import *45 # Inserts default theme app6 INSTALLED_APPS.insert(1, "my_project.them...
1 # settings.py23 import os4 PROJECT_ROOT = os.path.dirname(os.path.abspath(__file__))5 PROJECT_DIRNAME = PROJECT_ROOT.spl...
1 # settings.py23 import os4 PROJECT_ROOT = os.path.dirname(os.path.abspath(__file__))5 PROJECT_DIRNAME = PROJECT_ROOT.spl...
1 # settings.py23 import os4 PROJECT_ROOT = os.path.dirname(os.path.abspath(__file__))5 PROJECT_DIRNAME = PROJECT_ROOT.spl...
1 # local_settings.py2 # (developers version)34 DEBUG = True5 TEMPLATE_DEBUG = DEBUG6 COMPRESS_ENABLED = False78 DATABASES...
urls.pyWednesday, June 19, 13
• boilerplate default urls (index.html, etc.)• load urls according to settings.INSTALLED_APPSWednesday, June 19, 13
1 # urls.py23 from django.conf.urls import patterns, include, url456 urlpatterns = patterns(,7 (, include("default_app.url...
1 # default_urls.py23 urlpatterns = patterns(,4 # Default index.html5 url(r^$, TemplateView.as_view(template_name=index.ht...
1 # default_urls.py23 urlpatterns = patterns(,4 # Default index.html5 url(r^$, TemplateView.as_view(template_name=index.ht...
1 # urls.py23 # Media and Static files for development4 if settings.DEBUG:5 # Static files6 from django.contrib.staticfile...
#2:‘Dynamic’ App LoadingWednesday, June 19, 13
• Automatically load all apps in a directory.• Useful for plugins*• For more complex usage, .autodiscover()might be a bett...
1 # installed_plugins_list.py23 def installed_plugins_list(plugin_path=None):4 """Function to get a list of plugins from p...
1 ##########################2 # LABS SETTINGS #3 ##########################4 # Developers playground #5 # Play at ur own r...
#3: Django ThemesWednesday, June 19, 13
• Themes are just Django apps.• Actually, themes are Django app with staticfiles and templates.• Themes can be overridden, ...
Typical theme structuremy_awesome_theme/- static/- img/- js/- scripts.js- css/- local.css- templates/- base.html- index.ht...
Where to put the themes ?Wednesday, June 19, 13
1. Use main app as theme# directory structuremy_project/my_app/templatesmy_project/my_app/static# in settings.pyINSTALLED_...
2. Have a dedicated themedirectory# directory structuremy_project/my_app/themes/default/templatesmy_project/my_app/themes/...
#4: Django plugins with{% overextends %}Wednesday, June 19, 13
• {% overextends %} is written by@stephen_mcd for Mezzanine CMS.• Also available as pluggable app.https://github.com/steph...
1 <!-- my_app/templates/index.html -->2 {% extends "base.html" %}345 {% block header %}6 <h1>Hello Title</h1>7 {% endblock...
1 <!-- my_app/templates/base.html -->2 <!DOCTYPE html>3 <head>4 <meta charset="utf-8">5 {% block base_styles %}{% endblock...
1 <!-- my_app/plugins/jquery/templates/base.html -->2 {% overextends "base.html" %}345 {% block js_libs %}6 {{ block.super...
1 <!-- my_app/plugins/bootstrap/templates/base.html -->2 {% overextends "base.html" %}345 {% block base_styles %}6 {{ bloc...
2 <!DOCTYPE html>3 <head>4 <meta charset="utf-8">56 <!-- block base_styles -->7 <link href="//netdna.bootstrapcdn.com/twit...
1 INSTALLED_APPS = [2 "my_app.themes.default",3 "my_app.plugins.jquery",4 "my_app.plugins.bootstrap",5 ...6 ]Inheritance p...
#5: Class based viewsWednesday, June 19, 13
models.pyWednesday, June 19, 13
1 # models.py23 from django.db import models456 class School(models.Model):7 title = models.CharField(_("Title"), max_leng...
36 class Slugged(models.Model):37 title = models.CharField(_("Title"), max_length=500)38 slug = models.CharField(_("URL"),...
1 # models.py23 from django.db import models4 from .base import Slugged567 class School(Slugged):8 passWednesday, June 19,...
1 # models.py23 from django.db import models4 from .base import Slugged56 class School(Slugged):78 @models.permalink9 def ...
1 class CrudUrl(models.Model):2 class Meta:3 abstract = True45 def __init__(self, *args, **kwargs):6 self._objname = self....
1 class CrudUrl(models.Model):2 class Meta:3 abstract = True45 def __init__(self, *args, **kwargs):6 self._objname = self....
1 # models.py23 from django.db import models4 from .base import Slugged, CrudUrl56 class School(Slugged, CrudUrl):7 passWe...
urls.pyWednesday, June 19, 13
1 # urls.py23 from django.conf.urls import patterns, include, url4 from django.views.generic import (ListView, DetailView,...
views.pyWednesday, June 19, 13
1 # views.py23 from django.views.generic import (ListView, DetailView,4 CreateView, UpdateView, DeleteView)5 from .models ...
1 from django.views.generic.base import TemplateResponseMixin23 class AjaxTemplateResponseMixin(TemplateResponseMixin):4 d...
1 from django.views.generic.base import TemplateResponseMixin23 class AjaxTemplateResponseMixin(TemplateResponseMixin):4 d...
1 from django.views.generic.base import TemplateResponseMixin23 class AjaxTemplateResponseMixin(TemplateResponseMixin):4 d...
1 # views.py23 from django.views.generic import (ListView, DetailView,4 CreateView, UpdateView, DeleteView)5 from .models ...
8 class FilterMixin(object):9 allowed_filters = {}1011 def get_queryset_filters(self):12 filters = {}1314 for item in self...
Wednesday, June 19, 13
8 class FilterMixin(object):9 allowed_filters = {}1011 def get_queryset_filters(self):12 filters = {}1314 for item in self...
8 class FilterMixin(object):9 allowed_filters = {}1011 def get_queryset_filters(self):12 filters = {}1314 for item in self...
1 # views.py23 from django.views.generic import (ListView, DetailView,4 CreateView, UpdateView, DeleteView)5 from .models ...
urls.pyWednesday, June 19, 13
1 # urls.py23 from django.conf.urls import patterns, include, url4 from .views import (SchoolListView, SchoolDetailView,5 ...
F.A.Q.Wednesday, June 19, 13
1. Row based permission ?Wednesday, June 19, 13
1. Row based permission ?Django Guardian(https://github.com/lukaszb/django-guardian)Wednesday, June 19, 13
2. Custom User Model ?Wednesday, June 19, 13
2. Custom User Model ?Pros-You don’t need a user profile model- Faster, as you don’t have to refer to profiles as foreignkey...
2. Custom User Model ?Cons- might break contrib.admin- might break old apps- might break stuffs tied to user (like permiss...
2. Custom User Model ?Conclusion-Yes, if you’re just extending the user model. If youinherit from AbstractUser, you should...
2. Custom User Model ?Implementation- Add to settings.py, AUTH_USER_MODEL = myuser.MyModel.Wednesday, June 19, 13
Thank You !by Renyi Khorrenyi.ace@gmail.com@renyikhorhttps://github.com/renyi/django-tips-and-tricksWednesday, June 19, 13
Upcoming SlideShare
Loading in...5
×

Django tips & tricks

3,939

Published on

My presentation for Python User Group Malaysia, June 2013.

Snippets are here, https://github.com/renyi/django-tips-and-tricks.

Published in: Technology, Business
0 Comments
8 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
3,939
On Slideshare
0
From Embeds
0
Number of Embeds
2
Actions
Shares
0
Downloads
60
Comments
0
Likes
8
Embeds 0
No embeds

No notes for slide

Django tips & tricks

  1. 1. Django:Tips & Tricksby Renyi Khorrenyi.ace@gmail.com@renyikhorhttps://github.com/renyi/django-tips-and-tricksWednesday, June 19, 13
  2. 2. DisclaimerWednesday, June 19, 13
  3. 3. Disclaimer• I’m not a super pro pythonista, but I’m avery lazy one.Wednesday, June 19, 13
  4. 4. Disclaimer• I’m not a super pro pythonista, but I’m avery lazy one.• Speed - means programmer’s programmingspeed, unless specified otherwise.Wednesday, June 19, 13
  5. 5. Disclaimer• I’m not a super pro pythonista, but I’m avery lazy one.• Speed - means programmer’s programmingspeed, unless specified otherwise.• I like to do things as short and as easy aspossible.Wednesday, June 19, 13
  6. 6. Disclaimer• I’m not a super pro pythonista, but I’m avery lazy one.• Speed - means programmer’s programmingspeed, unless specified otherwise.• I like to do things as short and as easy aspossible.• DRYKISS =Don’t repeat yourself + Keep it super simpleWednesday, June 19, 13
  7. 7. ACE EdVenture PixelHead of R&D and Lead DeveloperSchoolHubSchool Management SystemWhat we use python for ?SchoolHub is built on top of Django Web FrameworkWednesday, June 19, 13
  8. 8. ACE EdVenture StudioHead of R&DChemQuest: Petticles in PerilChemistry based RPG game.What we use python for ?Most of the web components are built withDjango Web Framework(Web login, Game Achievements, etc.)Wednesday, June 19, 13
  9. 9. #1: Boilerplate Everything(that you can)Wednesday, June 19, 13
  10. 10. settings.pyWednesday, June 19, 13
  11. 11. • use lists[] instead of tuples() in default_settings.py• Use list methods - add(), remove(), +=• Default naming convention to project name• use project as default “theme” app for projectWednesday, June 19, 13
  12. 12. 1 # default_settings.py23 DEBUG = False4 TEMPLATE_DEBUG = False5 USE_SOUTH = True6 ADMINS = [(Devtune Admin, admin@devtune.biz)]7 MANAGERS = ADMINS8 USE_I18N = True9 USE_L10N = True10 LANGUAGE_CODE = "en-gb"11 USE_TZ = True12 TIME_ZONE = Asia/Kuala_Lumpur13 INTERNAL_IPS = ["127.0.0.1"]14 SESSION_ENGINE = django.contrib.sessions.backends.cached_db15 SESSION_EXPIRE_AT_BROWSER_CLOSE = True16 SITE_ID = 117 STATIC_URL = /static/18 MEDIA_URL = /media19 INSTALLED_APPS = [20 "django.contrib.admin",21 "django.contrib.auth",22 "django.contrib.contenttypes",23 "django.contrib.sessions",24 "django.contrib.sites",25 "django.contrib.sitemaps",26 "django.contrib.staticfiles",27 "compressor",28 ]Wednesday, June 19, 13
  13. 13. 1 # settings.py23 from .default_settings import *45 # Inserts default theme app6 INSTALLED_APPS.insert(1, "my_project.themes.default")78 # Removes CSRF checking9 if "django.middleware.csrf.CsrfViewMiddleware" in MIDDLEWARE_CLASSES:10 MIDDLEWARE_CLASSES.remove("django.middleware.csrf.CsrfViewMiddleware")1112 # LOCAL SETTINGS #13 try:14 from local_settings import *15 except ImportError:16 pass1718 # DYNAMIC SETTINGS #19 try:20 from mezzanine.utils.conf import set_dynamic_settings21 except ImportError:22 pass23 else:24 set_dynamic_settings(globals())Wednesday, June 19, 13
  14. 14. 1 # settings.py23 import os4 PROJECT_ROOT = os.path.dirname(os.path.abspath(__file__))5 PROJECT_DIRNAME = PROJECT_ROOT.split(os.sep)[-1]67 # User project directory name as default "theme" app8 INSTALLED_APPS.insert(1, "%s" % PROJECT_DIRNAME)910 ROOT_URLCONF = %s.urls % PROJECT_DIRNAME11 CACHE_MIDDLEWARE_KEY_PREFIX = %s % PROJECT_DIRNAME12 CACHE_MIDDLEWARE_ALIAS = %s % PROJECT_DIRNAME13 CSRF_COOKIE_NAME = %s_csrftoken % PROJECT_DIRNAME14 LANGUAGE_COOKIE_NAME = %s_language % PROJECT_DIRNAME15 SESSION_COOKIE_NAME = %s_session % PROJECT_DIRNAME16 STATIC_ROOT = /static/%s/ % PROJECT_DIRNAME17 MEDIA_ROOT = /media/%s/ % PROJECT_DIRNAME18 WSGI_APPLICATION = %s.wsgi.application % PROJECT_DIRNAME1920 # Celery21 BROKER_VHOST = PROJECT_DIRNAME22 BROKER_URL = %s%s % (BROKER_URL, BROKER_VHOST)2324 DATABASES = {25 "default": {26 "ENGINE": "django.db.backends.postgresql_psycopg2",27 "NAME": "%s" % PROJECT_DIRNAME,28 "HOST": "127.0.0.1",29 }30 }3132 CACHES = {33 default: {34 BACKEND: django.core.cache.backends.memcached.PyLibMCCache,35 LOCATION: [127.0.0.1:11211],36 KEY_PREFIX: %s % PROJECT_DIRNAME,37 }38 }Wednesday, June 19, 13
  15. 15. 1 # settings.py23 import os4 PROJECT_ROOT = os.path.dirname(os.path.abspath(__file__))5 PROJECT_DIRNAME = PROJECT_ROOT.split(os.sep)[-1]67 # User project directory name as default "theme" app8 INSTALLED_APPS.insert(1, "%s" % PROJECT_DIRNAME)910 ROOT_URLCONF = %s.urls % PROJECT_DIRNAME11 CACHE_MIDDLEWARE_KEY_PREFIX = %s % PROJECT_DIRNAME12 CACHE_MIDDLEWARE_ALIAS = %s % PROJECT_DIRNAME13 CSRF_COOKIE_NAME = %s_csrftoken % PROJECT_DIRNAME14 LANGUAGE_COOKIE_NAME = %s_language % PROJECT_DIRNAME15 SESSION_COOKIE_NAME = %s_session % PROJECT_DIRNAME16 STATIC_ROOT = /static/%s/ % PROJECT_DIRNAME17 MEDIA_ROOT = /media/%s/ % PROJECT_DIRNAME18 WSGI_APPLICATION = %s.wsgi.application % PROJECT_DIRNAME1920 # Celery21 BROKER_VHOST = PROJECT_DIRNAME22 BROKER_URL = %s%s % (BROKER_URL, BROKER_VHOST)2324 DATABASES = {25 "default": {26 "ENGINE": "django.db.backends.postgresql_psycopg2",27 "NAME": "%s" % PROJECT_DIRNAME,28 "HOST": "127.0.0.1",29 }30 }3132 CACHES = {33 default: {34 BACKEND: django.core.cache.backends.memcached.PyLibMCCache,35 LOCATION: [127.0.0.1:11211],36 KEY_PREFIX: %s % PROJECT_DIRNAME,37 }38 }Wednesday, June 19, 13
  16. 16. 1 # settings.py23 import os4 PROJECT_ROOT = os.path.dirname(os.path.abspath(__file__))5 PROJECT_DIRNAME = PROJECT_ROOT.split(os.sep)[-1]67 # User project directory name as default "theme" app8 INSTALLED_APPS.insert(1, "%s" % PROJECT_DIRNAME)910 ROOT_URLCONF = %s.urls % PROJECT_DIRNAME11 CACHE_MIDDLEWARE_KEY_PREFIX = %s % PROJECT_DIRNAME12 CACHE_MIDDLEWARE_ALIAS = %s % PROJECT_DIRNAME13 CSRF_COOKIE_NAME = %s_csrftoken % PROJECT_DIRNAME14 LANGUAGE_COOKIE_NAME = %s_language % PROJECT_DIRNAME15 SESSION_COOKIE_NAME = %s_session % PROJECT_DIRNAME16 STATIC_ROOT = /static/%s/ % PROJECT_DIRNAME17 MEDIA_ROOT = /media/%s/ % PROJECT_DIRNAME18 WSGI_APPLICATION = %s.wsgi.application % PROJECT_DIRNAME1920 # Celery21 BROKER_VHOST = PROJECT_DIRNAME22 BROKER_URL = %s%s % (BROKER_URL, BROKER_VHOST)2324 DATABASES = {25 "default": {26 "ENGINE": "django.db.backends.postgresql_psycopg2",27 "NAME": "%s" % PROJECT_DIRNAME,28 "HOST": "127.0.0.1",29 }30 }3132 CACHES = {33 default: {34 BACKEND: django.core.cache.backends.memcached.PyLibMCCache,35 LOCATION: [127.0.0.1:11211],36 KEY_PREFIX: %s % PROJECT_DIRNAME,37 }38 }Wednesday, June 19, 13
  17. 17. 1 # local_settings.py2 # (developers version)34 DEBUG = True5 TEMPLATE_DEBUG = DEBUG6 COMPRESS_ENABLED = False78 DATABASES = {9 "default": {10 "ENGINE": "django.db.backends.sqlite3",11 "NAME": "dev.db",12 }13 }1415 CACHES = {16 default: {17 BACKEND: django.core.cache.backends.dummy.DummyCache,18 }19 }202122 CELERY_CACHE_BACKEND = "dummy"23 EMAIL_BACKEND = kopio.core.mailer.backend.DbBackend24 MAILER_EMAIL_BACKEND = django.core.mail.backends.smtp.EmailBackend25 SESSION_ENGINE = "django.contrib.sessions.backends.signed_cookies"Wednesday, June 19, 13
  18. 18. urls.pyWednesday, June 19, 13
  19. 19. • boilerplate default urls (index.html, etc.)• load urls according to settings.INSTALLED_APPSWednesday, June 19, 13
  20. 20. 1 # urls.py23 from django.conf.urls import patterns, include, url456 urlpatterns = patterns(,7 (, include("default_app.urls")),8 (, include("mezzanine.urls")),9 )Wednesday, June 19, 13
  21. 21. 1 # default_urls.py23 urlpatterns = patterns(,4 # Default index.html5 url(r^$, TemplateView.as_view(template_name=index.html), name="home"),67 # Default favicon8 url(r^favicon.ico/$, RedirectView.as_view(url=/static/img/favicon.9 ico), name="favicon"),10 )1112 # Default robots.txt13 urlpatterns += patterns(,14 url(r^robots.txt/$, TemplateView.as_view(template_name=robots.txt)),15 )1617 # Admin urls18 if "django.contrib.admin" in settings.INSTALLED_APPS:19 from django.contrib import admin20 admin.autodiscover()2122 urlpatterns += patterns("",23 (r"^admin/", include(admin.site.urls)),24 )2526 # Other apps27 if "userena" in settings.INSTALLED_APPS:28 urlpatterns += patterns("",29 (r^users/, include(userena.urls)),30 )3132 if "selectable" in settings.INSTALLED_APPS:33 urlpatterns += patterns("",34 url(r"^selectable/", include("selectable.urls")),35 )3637 if "actstream" in settings.INSTALLED_APPS:38 urlpatterns += patterns("",39 (^activity/, include(actstream.urls)),40 )Wednesday, June 19, 13
  22. 22. 1 # default_urls.py23 urlpatterns = patterns(,4 # Default index.html5 url(r^$, TemplateView.as_view(template_name=index.html), name="home"),67 # Default favicon8 url(r^favicon.ico/$, RedirectView.as_view(url=/static/img/favicon.9 ico), name="favicon"),10 )1112 # Default robots.txt13 urlpatterns += patterns(,14 url(r^robots.txt/$, TemplateView.as_view(template_name=robots.txt)),15 )1617 # Admin urls18 if "django.contrib.admin" in settings.INSTALLED_APPS:19 from django.contrib import admin20 admin.autodiscover()2122 urlpatterns += patterns("",23 (r"^admin/", include(admin.site.urls)),24 )2526 # Other apps27 if "userena" in settings.INSTALLED_APPS:28 urlpatterns += patterns("",29 (r^users/, include(userena.urls)),30 )3132 if "selectable" in settings.INSTALLED_APPS:33 urlpatterns += patterns("",34 url(r"^selectable/", include("selectable.urls")),35 )3637 if "actstream" in settings.INSTALLED_APPS:38 urlpatterns += patterns("",39 (^activity/, include(actstream.urls)),40 )Wednesday, June 19, 13
  23. 23. 1 # urls.py23 # Media and Static files for development4 if settings.DEBUG:5 # Static files6 from django.contrib.staticfiles.urls import staticfiles_urlpatterns7 urlpatterns += staticfiles_urlpatterns()89 # Media files10 from django.conf.urls.static import static11 urlpatterns += static(settings.MEDIA_URL, document_root=settings.12 MEDIA_ROOT)Wednesday, June 19, 13
  24. 24. #2:‘Dynamic’ App LoadingWednesday, June 19, 13
  25. 25. • Automatically load all apps in a directory.• Useful for plugins*• For more complex usage, .autodiscover()might be a better choiceWednesday, June 19, 13
  26. 26. 1 # installed_plugins_list.py23 def installed_plugins_list(plugin_path=None):4 """Function to get a list of plugins from plugin_path5 """6 import os78 path = os.path.dirname(__file__)9 path = os.path.join(path, plugin_path)1011 installed_plugins = []12 for module in os.listdir(path):13 if os.path.isdir(path + / + module) == True:14 installed_plugins.append(module)15 return installed_pluginsWednesday, June 19, 13
  27. 27. 1 ##########################2 # LABS SETTINGS #3 ##########################4 # Developers playground #5 # Play at ur own risk #6 ##########################78 if LABS_ENABLED and not "sis.labs" in INSTALLED_APPS:9 from .installed_plugins_list import installed_plugins_list1011 TEMPLATE_CONTEXT_PROCESSORS += [12 "sis.context_processors.sis_labs"13 ]1415 # Loads all modules from sis.plugins16 for plugin in installed_plugins_list(plugins):17 INSTALLED_APPS.insert(0, "sis.plugins.%s" % plugin)1819 # Loads all modules from sis.labs.ui20 for plugin in installed_plugins_list(labs/ui):21 INSTALLED_APPS.insert(0, "sis.labs.ui.%s" % plugin)2223 # Loads all modules from sis.labs.apps24 INSTALLED_APPS.append(sis.labs)25 for plugin in installed_plugins_list(labs/app):26 INSTALLED_APPS.append(0, "sis.labs.app.%s" % plugin)Wednesday, June 19, 13
  28. 28. #3: Django ThemesWednesday, June 19, 13
  29. 29. • Themes are just Django apps.• Actually, themes are Django app with staticfiles and templates.• Themes can be overridden, just like howwe override templates.• For more information,https://github.com/renyi/mezzanine-themesWednesday, June 19, 13
  30. 30. Typical theme structuremy_awesome_theme/- static/- img/- js/- scripts.js- css/- local.css- templates/- base.html- index.html- includes/main.htmlWednesday, June 19, 13
  31. 31. Where to put the themes ?Wednesday, June 19, 13
  32. 32. 1. Use main app as theme# directory structuremy_project/my_app/templatesmy_project/my_app/static# in settings.pyINSTALLED_APPS.insert(1, "my_app")Wednesday, June 19, 13
  33. 33. 2. Have a dedicated themedirectory# directory structuremy_project/my_app/themes/default/templatesmy_project/my_app/themes/default/static# in settings.pyINSTALLED_APPS.insert(1, "my_app.themes.default")Wednesday, June 19, 13
  34. 34. #4: Django plugins with{% overextends %}Wednesday, June 19, 13
  35. 35. • {% overextends %} is written by@stephen_mcd for Mezzanine CMS.• Also available as pluggable app.https://github.com/stephenmcd/django-overextends• Allows circular template inheritance.(base.html can “extend” base.html)• This allows for simple way of managingplugable apps (javascripts libraries, etc.) orlet’s call it “plugins”.Wednesday, June 19, 13
  36. 36. 1 <!-- my_app/templates/index.html -->2 {% extends "base.html" %}345 {% block header %}6 <h1>Hello Title</h1>7 {% endblock %}8910 {% block main %}11 <p>Hello Body</p>12 {% endblock %}Wednesday, June 19, 13
  37. 37. 1 <!-- my_app/templates/base.html -->2 <!DOCTYPE html>3 <head>4 <meta charset="utf-8">5 {% block base_styles %}{% endblock %}6 </head>7 <body>8 <header id="header">9 {% block header %}{% endblock %}10 </header>1112 <div role="main" id="main">13 {% block main %}{% endblock %}14 </div>1516 <footer id="footer">17 {% block footer %}{% endblock %}18 </footer>1920 {% block js_libs %}{% endblock %}21 </body>22 </html>Wednesday, June 19, 13
  38. 38. 1 <!-- my_app/plugins/jquery/templates/base.html -->2 {% overextends "base.html" %}345 {% block js_libs %}6 {{ block.super }}7 <script src="//code.jquery.com/jquery-1.8.3.min.js"></script>8 {% endblock %}Wednesday, June 19, 13
  39. 39. 1 <!-- my_app/plugins/bootstrap/templates/base.html -->2 {% overextends "base.html" %}345 {% block base_styles %}6 {{ block.super }}7 <link href="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.8 1/css/bootstrap-combined.min.css" rel="stylesheet">9 {% endblock %}101112 {% block js_libs %}13 {{ block.super }}14 <script src="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.15 1/js/bootstrap.min.js"></script>16 {% endblock %}Wednesday, June 19, 13
  40. 40. 2 <!DOCTYPE html>3 <head>4 <meta charset="utf-8">56 <!-- block base_styles -->7 <link href="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.8 1/css/bootstrap-combined.min.css" rel="stylesheet">9 <!-- endblock -->10 </head>11 <body>12 <header id="header">13 <!-- block header_styles -->14 <h1>Hello Title</h1>15 <!-- endblock -->16 </header>1718 <div role="main" id="main">19 <!-- block main_styles -->20 <p>Hello Body</p>21 <!-- endblock -->22 </div>2324 <footer id="footer">25 <!-- block footer_styles -->26 <!-- endblock -->27 </footer>2829 <!-- block js_libs -->30 <script src="//code.jquery.com/jquery-1.8.3.min.js"></script>31 <script src="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.32 1/js/bootstrap.min.js"></script>33 <!-- endblock -->34 </body>35 </html>Wednesday, June 19, 13
  41. 41. 1 INSTALLED_APPS = [2 "my_app.themes.default",3 "my_app.plugins.jquery",4 "my_app.plugins.bootstrap",5 ...6 ]Inheritance priorityWednesday, June 19, 13
  42. 42. #5: Class based viewsWednesday, June 19, 13
  43. 43. models.pyWednesday, June 19, 13
  44. 44. 1 # models.py23 from django.db import models456 class School(models.Model):7 title = models.CharField(_("Title"), max_length=500)8 slug = models.CharField(_("URL"), max_length=2000)910 def __unicode__(self):11 return self.title1213 def save(self, *args, **kwargs):14 """15 Create a unique slug by appending an index.16 """17 pass1819 def get_slug(self):20 """21 Allows subclasses to implement their own slug creation logic.22 """23 return slugify(self.title)Wednesday, June 19, 13
  45. 45. 36 class Slugged(models.Model):37 title = models.CharField(_("Title"), max_length=500)38 slug = models.CharField(_("URL"), max_length=2000)3940 class Meta:41 abstract = True4243 def __unicode__(self):44 return self.title4546 def save(self, *args, **kwargs):47 """48 Create a unique slug by appending an index.49 """50 pass5152 def get_slug(self):53 """54 Allows subclasses to implement their own slug creation logic.55 """56 return slugify(self.title)Wednesday, June 19, 13
  46. 46. 1 # models.py23 from django.db import models4 from .base import Slugged567 class School(Slugged):8 passWednesday, June 19, 13
  47. 47. 1 # models.py23 from django.db import models4 from .base import Slugged56 class School(Slugged):78 @models.permalink9 def get_absolute_url(self):10 return (school_details, None, {slug: self.slug})Wednesday, June 19, 13
  48. 48. 1 class CrudUrl(models.Model):2 class Meta:3 abstract = True45 def __init__(self, *args, **kwargs):6 self._objname = self._meta.object_name.lower()7 super(CrudUrl, self).__init__(*args, **kwargs)89 @models.permalink10 def get_absolute_url(self):11 return (%s_details % self._objname, None, {slug: self.slug})1213 @models.permalink14 def get_list_url(self):15 return (%s_list % self._objname, None, {})1617 @models.permalink18 def get_create_url(self):19 return (%s_create % self._objname, None, {})2021 @models.permalink22 def get_update_url(self):23 return (%s_update % self._objname, None, {slug: self.slug})2425 @models.permalink26 def get_delete_url(self):27 return (%s_delete % self._objname, None, {slug: self.slug})28Wednesday, June 19, 13
  49. 49. 1 class CrudUrl(models.Model):2 class Meta:3 abstract = True45 def __init__(self, *args, **kwargs):6 self._objname = self._meta.object_name.lower()7 super(CrudUrl, self).__init__(*args, **kwargs)89 @models.permalink10 def get_absolute_url(self):11 return (%s_details % self._objname, None, {slug: self.slug})1213 @models.permalink14 def get_list_url(self):15 return (%s_list % self._objname, None, {})1617 @models.permalink18 def get_create_url(self):19 return (%s_create % self._objname, None, {})2021 @models.permalink22 def get_update_url(self):23 return (%s_update % self._objname, None, {slug: self.slug})2425 @models.permalink26 def get_delete_url(self):27 return (%s_delete % self._objname, None, {slug: self.slug})28Wednesday, June 19, 13
  50. 50. 1 # models.py23 from django.db import models4 from .base import Slugged, CrudUrl56 class School(Slugged, CrudUrl):7 passWednesday, June 19, 13
  51. 51. urls.pyWednesday, June 19, 13
  52. 52. 1 # urls.py23 from django.conf.urls import patterns, include, url4 from django.views.generic import (ListView, DetailView,5 CreateView, UpdateView, DeleteView)6 from .models import School789 urlpatterns = patterns(,10 url(r^school/$,11 ListView.as_view(),12 name="school_list"),1314 url(r^school/add/$,15 CreateView.as_view(),16 name="school_create"),1718 url(r^school/update/(?P<slug>.*)/$,19 UpdateView.as_view(),20 name="school_update"),2122 url(r^school/delete/(?P<slug>.*)/$,23 DeleteView.as_view(),24 name="school_delete"),2526 url(r^school/(?P<slug>.*)/$,27 DetailView.as_view(),28 name="school_details"),29 )Wednesday, June 19, 13
  53. 53. views.pyWednesday, June 19, 13
  54. 54. 1 # views.py23 from django.views.generic import (ListView, DetailView,4 CreateView, UpdateView, DeleteView)5 from .models import School678 class SchoolListView(ListView):9 10 Template: school/school_list.html11 12 model = School1314 class SchoolDetailView(DetailView):15 16 Template: school/school_detail.html17 18 model = School1920 class SchoolCreateView(CreateView):21 22 Template: school/school_form.html23 24 model = School2526 class SchoolUpdateView(UpdateView):27 28 Template: school/school_form.html29 30 model = School3132 class SchoolDeleteView(DeleteView):33 34 Template: school/school_confirm_delete.html35 36 model = SchoolWednesday, June 19, 13
  55. 55. 1 from django.views.generic.base import TemplateResponseMixin23 class AjaxTemplateResponseMixin(TemplateResponseMixin):4 def get_template_names(self):5 """6 Return a list of template names to be used for the request.7 """8 try:9 names = super(AjaxTemplateResponseMixin, self).get_template_names()10 except ImproperlyConfigured:11 names = []1213 try:14 opts = self.form_class._meta.model._meta15 except:16 try:17 opts = self.object_list.model._meta18 except:19 try:20 opts = self.object._meta21 except:22 opts = None2324 # Generates template name based on object name24 if opts:25 opts_list = (opts.app_label, opts.object_name.lower(), self.26 template_name_suffix)2728 if self.request.is_ajax():29 name = "%s/includes/%s%s.html" % opts_list3031 else:32 name = "%s/%s%s.html" % opts_list3334 names.append(name)3536 return namesWednesday, June 19, 13
  56. 56. 1 from django.views.generic.base import TemplateResponseMixin23 class AjaxTemplateResponseMixin(TemplateResponseMixin):4 def get_template_names(self):5 """6 Return a list of template names to be used for the request.7 """8 try:9 names = super(AjaxTemplateResponseMixin, self).get_template_names()10 except ImproperlyConfigured:11 names = []1213 try:14 opts = self.form_class._meta.model._meta15 except:16 try:17 opts = self.object_list.model._meta18 except:19 try:20 opts = self.object._meta21 except:22 opts = None2324 # Generates template name based on object name24 if opts:25 opts_list = (opts.app_label, opts.object_name.lower(), self.26 template_name_suffix)2728 if self.request.is_ajax():29 name = "%s/includes/%s%s.html" % opts_list3031 else:32 name = "%s/%s%s.html" % opts_list3334 names.append(name)3536 return namesWednesday, June 19, 13
  57. 57. 1 from django.views.generic.base import TemplateResponseMixin23 class AjaxTemplateResponseMixin(TemplateResponseMixin):4 def get_template_names(self):5 """6 Return a list of template names to be used for the request.7 """8 try:9 names = super(AjaxTemplateResponseMixin, self).get_template_names()10 except ImproperlyConfigured:11 names = []1213 try:14 opts = self.form_class._meta.model._meta15 except:16 try:17 opts = self.object_list.model._meta18 except:19 try:20 opts = self.object._meta21 except:22 opts = None2324 # Generates template name based on object name24 if opts:25 opts_list = (opts.app_label, opts.object_name.lower(), self.26 template_name_suffix)2728 if self.request.is_ajax():29 name = "%s/includes/%s%s.html" % opts_list3031 else:32 name = "%s/%s%s.html" % opts_list3334 names.append(name)3536 return namesWednesday, June 19, 13
  58. 58. 1 # views.py23 from django.views.generic import (ListView, DetailView,4 CreateView, UpdateView, DeleteView)5 from .models import School6 from .mixin import AjaxTemplateResponseMixin789 class SchoolListView(ListView, AjaxTemplateResponseMixin):10 11 Template: school/school_list.html12 AJAX Template: school/includes/school_list.html13 14 model = School1516 class SchoolDetailView(DetailView, AjaxTemplateResponseMixin):17 18 Template: school/school_detail.html19 AJAX Template: school/includes/school_detail.html20 21 model = School2223 class SchoolCreateView(CreateView, AjaxTemplateResponseMixin):24 25 Template: school/school_form.html26 AJAX Template: school/includes/school_form.html27 28 model = School2930 class SchoolUpdateView(UpdateView, AjaxTemplateResponseMixin):31 32 Template: school/school_form.html33 AJAX Template: school/includes/school_form.html34 35 model = School36Wednesday, June 19, 13
  59. 59. 8 class FilterMixin(object):9 allowed_filters = {}1011 def get_queryset_filters(self):12 filters = {}1314 for item in self.request.GET:15 allowed = self.allowed_filters.get(item)16 if allowed:17 keyname = "%s" % allowed18 filter_values = self.request.GET.getlist(item)19 filters[keyname] = filter_values20 return filters2122 def get_queryset(self):23 qs = super(FilterMixin, self).get_queryset()24 return qs.filter(**self.get_queryset_filters())Wednesday, June 19, 13
  60. 60. Wednesday, June 19, 13
  61. 61. 8 class FilterMixin(object):9 allowed_filters = {}1011 def get_queryset_filters(self):12 filters = {}1314 for item in self.request.GET:15 allowed = self.allowed_filters.get(item)16 if allowed:17 keyname = "%s" % allowed18 filter_values = self.request.GET.getlist(item)19 filters[keyname] = filter_values20 return filters2122 def get_queryset(self):23 qs = super(FilterMixin, self).get_queryset()24 return qs.filter(**self.get_queryset_filters())Wednesday, June 19, 13
  62. 62. 8 class FilterMixin(object):9 allowed_filters = {}1011 def get_queryset_filters(self):12 filters = {}1314 for item in self.request.GET:15 allowed = self.allowed_filters.get(item)16 if allowed:17 keyname = "%s" % allowed18 filter_values = self.request.GET.getlist(item)19 filters[keyname] = filter_values20 return filters2122 def get_queryset(self):23 qs = super(FilterMixin, self).get_queryset()24 return qs.filter(**self.get_queryset_filters())Wednesday, June 19, 13
  63. 63. 1 # views.py23 from django.views.generic import (ListView, DetailView,4 CreateView, UpdateView, DeleteView)5 from .models import School6 from .mixin import AjaxTemplateResponseMixin, FilterMixin789 class SchoolListView(ListView, FilterMixin,AjaxTemplateResponseMixin):10 11 Template: school/school_list.html12 AJAX Template: school/includes/school_list.html13 14 model = School15 allowed_filters = {16 title: title__icontains,17 slug: slug__icontains,18 }19Wednesday, June 19, 13
  64. 64. urls.pyWednesday, June 19, 13
  65. 65. 1 # urls.py23 from django.conf.urls import patterns, include, url4 from .views import (SchoolListView, SchoolDetailView,5 SchoolCreateView, SchoolUpdateView,6 SchoolDeleteView)7 from .models import School8910 urlpatterns = patterns(,11 url(r^school/$,12 SchoolListView.as_view(),13 name="school_list"),1415 url(r^school/add/$,16 SchoolCreateView.as_view(),17 name="school_create"),1819 url(r^school/update/(?P<slug>.*)/$,20 SchoolUpdateView.as_view(),21 name="school_update"),2223 url(r^school/delete/(?P<slug>.*)/$,24 SchoolDeleteView.as_view(),25 name="school_delete"),2627 url(r^school/(?P<slug>.*)/$,28 SchoolDetailView.as_view(),29 name="school_details"),30 )Wednesday, June 19, 13
  66. 66. F.A.Q.Wednesday, June 19, 13
  67. 67. 1. Row based permission ?Wednesday, June 19, 13
  68. 68. 1. Row based permission ?Django Guardian(https://github.com/lukaszb/django-guardian)Wednesday, June 19, 13
  69. 69. 2. Custom User Model ?Wednesday, June 19, 13
  70. 70. 2. Custom User Model ?Pros-You don’t need a user profile model- Faster, as you don’t have to refer to profiles as foreignkeys.- More flexibilityWednesday, June 19, 13
  71. 71. 2. Custom User Model ?Cons- might break contrib.admin- might break old apps- might break stuffs tied to user (like permission) ifcustom model is not implemented correctly.Wednesday, June 19, 13
  72. 72. 2. Custom User Model ?Conclusion-Yes, if you’re just extending the user model. If youinherit from AbstractUser, you should be fine.- No, if you want to override existing fields orfunctions. Unless you know what you’re doing, youmight end up breaking compatibility with other apps.Wednesday, June 19, 13
  73. 73. 2. Custom User Model ?Implementation- Add to settings.py, AUTH_USER_MODEL = myuser.MyModel.Wednesday, June 19, 13
  74. 74. Thank You !by Renyi Khorrenyi.ace@gmail.com@renyikhorhttps://github.com/renyi/django-tips-and-tricksWednesday, June 19, 13
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×