Django tips & tricks

  • 3,482 views
Uploaded on

My presentation for Python User Group Malaysia, June 2013. …

My presentation for Python User Group Malaysia, June 2013.

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

More in: Technology , Business
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
No Downloads

Views

Total Views
3,482
On Slideshare
0
From Embeds
0
Number of Embeds
2

Actions

Shares
Downloads
46
Comments
0
Likes
3

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. Django:Tips & Tricksby Renyi Khorrenyi.ace@gmail.com@renyikhorhttps://github.com/renyi/django-tips-and-tricksWednesday, June 19, 13
  • 2. DisclaimerWednesday, June 19, 13
  • 3. Disclaimer• I’m not a super pro pythonista, but I’m avery lazy one.Wednesday, June 19, 13
  • 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. 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. 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. 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. 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. #1: Boilerplate Everything(that you can)Wednesday, June 19, 13
  • 10. settings.pyWednesday, June 19, 13
  • 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. 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. 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. 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. 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. 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. 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. urls.pyWednesday, June 19, 13
  • 19. • boilerplate default urls (index.html, etc.)• load urls according to settings.INSTALLED_APPSWednesday, June 19, 13
  • 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. 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. 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. 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. #2:‘Dynamic’ App LoadingWednesday, June 19, 13
  • 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. 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. 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. #3: Django ThemesWednesday, June 19, 13
  • 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. 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. Where to put the themes ?Wednesday, June 19, 13
  • 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. 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. #4: Django plugins with{% overextends %}Wednesday, June 19, 13
  • 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. 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. 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. 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. 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. 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. 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. #5: Class based viewsWednesday, June 19, 13
  • 43. models.pyWednesday, June 19, 13
  • 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. 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. 1 # models.py23 from django.db import models4 from .base import Slugged567 class School(Slugged):8 passWednesday, June 19, 13
  • 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. 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. 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. 1 # models.py23 from django.db import models4 from .base import Slugged, CrudUrl56 class School(Slugged, CrudUrl):7 passWednesday, June 19, 13
  • 51. urls.pyWednesday, June 19, 13
  • 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. views.pyWednesday, June 19, 13
  • 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. 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. 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. 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. 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. 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. Wednesday, June 19, 13
  • 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. 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. 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. urls.pyWednesday, June 19, 13
  • 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. F.A.Q.Wednesday, June 19, 13
  • 67. 1. Row based permission ?Wednesday, June 19, 13
  • 68. 1. Row based permission ?Django Guardian(https://github.com/lukaszb/django-guardian)Wednesday, June 19, 13
  • 69. 2. Custom User Model ?Wednesday, June 19, 13
  • 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. 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. 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. 2. Custom User Model ?Implementation- Add to settings.py, AUTH_USER_MODEL = myuser.MyModel.Wednesday, June 19, 13
  • 74. Thank You !by Renyi Khorrenyi.ace@gmail.com@renyikhorhttps://github.com/renyi/django-tips-and-tricksWednesday, June 19, 13