SlideShare uma empresa Scribd logo
1 de 74
Baixar para ler offline
Django:
Tips & Tricks
by Renyi Khor
renyi.ace@gmail.com
@renyikhor
https://github.com/renyi/django-tips-and-tricks
Wednesday, June 19, 13
Disclaimer
Wednesday, June 19, 13
Disclaimer
• I’m not a super pro pythonista, but I’m a
very lazy one.
Wednesday, June 19, 13
Disclaimer
• I’m not a super pro pythonista, but I’m a
very lazy one.
• Speed - means programmer’s programming
speed, unless specified otherwise.
Wednesday, June 19, 13
Disclaimer
• I’m not a super pro pythonista, but I’m a
very lazy one.
• Speed - means programmer’s programming
speed, unless specified otherwise.
• I like to do things as short and as easy as
possible.
Wednesday, June 19, 13
Disclaimer
• I’m not a super pro pythonista, but I’m a
very lazy one.
• Speed - means programmer’s programming
speed, unless specified otherwise.
• I like to do things as short and as easy as
possible.
• DRYKISS =
Don’t repeat yourself + Keep it super simple
Wednesday, June 19, 13
ACE EdVenture Pixel
Head of R&D and Lead Developer
SchoolHub
School Management System
What we use python for ?
SchoolHub is built on top of Django Web Framework
Wednesday, June 19, 13
ACE EdVenture Studio
Head of R&D
ChemQuest: Petticles in Peril
Chemistry based RPG game.
What we use python for ?
Most of the web components are built with
Django Web Framework
(Web login, Game Achievements, etc.)
Wednesday, June 19, 13
#1: Boilerplate Everything
(that you can)
Wednesday, June 19, 13
settings.py
Wednesday, June 19, 13
• 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 project
Wednesday, June 19, 13
1 # default_settings.py
2
3 DEBUG = False
4 TEMPLATE_DEBUG = False
5 USE_SOUTH = True
6 ADMINS = [('Devtune Admin', 'admin@devtune.biz')]
7 MANAGERS = ADMINS
8 USE_I18N = True
9 USE_L10N = True
10 LANGUAGE_CODE = "en-gb"
11 USE_TZ = True
12 TIME_ZONE = 'Asia/Kuala_Lumpur'
13 INTERNAL_IPS = ["127.0.0.1"]
14 SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db'
15 SESSION_EXPIRE_AT_BROWSER_CLOSE = True
16 SITE_ID = 1
17 STATIC_URL = '/static/'
18 MEDIA_URL = '/media'
19 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
1 # settings.py
2
3 from .default_settings import *
4
5 # Inserts default theme app
6 INSTALLED_APPS.insert(1, "my_project.themes.default")
7
8 # Removes CSRF checking
9 if "django.middleware.csrf.CsrfViewMiddleware" in MIDDLEWARE_CLASSES:
10 MIDDLEWARE_CLASSES.remove("django.middleware.csrf.CsrfViewMiddleware")
11
12 # LOCAL SETTINGS #
13 try:
14 from local_settings import *
15 except ImportError:
16 pass
17
18 # DYNAMIC SETTINGS #
19 try:
20 from mezzanine.utils.conf import set_dynamic_settings
21 except ImportError:
22 pass
23 else:
24 set_dynamic_settings(globals())
Wednesday, June 19, 13
1 # settings.py
2
3 import os
4 PROJECT_ROOT = os.path.dirname(os.path.abspath(__file__))
5 PROJECT_DIRNAME = PROJECT_ROOT.split(os.sep)[-1]
6
7 # User project directory name as default "theme" app
8 INSTALLED_APPS.insert(1, "%s" % PROJECT_DIRNAME)
9
10 ROOT_URLCONF = '%s.urls' % PROJECT_DIRNAME
11 CACHE_MIDDLEWARE_KEY_PREFIX = '%s' % PROJECT_DIRNAME
12 CACHE_MIDDLEWARE_ALIAS = '%s' % PROJECT_DIRNAME
13 CSRF_COOKIE_NAME = '%s_csrftoken' % PROJECT_DIRNAME
14 LANGUAGE_COOKIE_NAME = '%s_language' % PROJECT_DIRNAME
15 SESSION_COOKIE_NAME = '%s_session' % PROJECT_DIRNAME
16 STATIC_ROOT = '/static/%s/' % PROJECT_DIRNAME
17 MEDIA_ROOT = '/media/%s/' % PROJECT_DIRNAME
18 WSGI_APPLICATION = '%s.wsgi.application' % PROJECT_DIRNAME
19
20 # Celery
21 BROKER_VHOST = PROJECT_DIRNAME
22 BROKER_URL = '%s%s' % (BROKER_URL, BROKER_VHOST)
23
24 DATABASES = {
25 "default": {
26 "ENGINE": "django.db.backends.postgresql_psycopg2",
27 "NAME": "%s" % PROJECT_DIRNAME,
28 "HOST": "127.0.0.1",
29 }
30 }
31
32 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
1 # settings.py
2
3 import os
4 PROJECT_ROOT = os.path.dirname(os.path.abspath(__file__))
5 PROJECT_DIRNAME = PROJECT_ROOT.split(os.sep)[-1]
6
7 # User project directory name as default "theme" app
8 INSTALLED_APPS.insert(1, "%s" % PROJECT_DIRNAME)
9
10 ROOT_URLCONF = '%s.urls' % PROJECT_DIRNAME
11 CACHE_MIDDLEWARE_KEY_PREFIX = '%s' % PROJECT_DIRNAME
12 CACHE_MIDDLEWARE_ALIAS = '%s' % PROJECT_DIRNAME
13 CSRF_COOKIE_NAME = '%s_csrftoken' % PROJECT_DIRNAME
14 LANGUAGE_COOKIE_NAME = '%s_language' % PROJECT_DIRNAME
15 SESSION_COOKIE_NAME = '%s_session' % PROJECT_DIRNAME
16 STATIC_ROOT = '/static/%s/' % PROJECT_DIRNAME
17 MEDIA_ROOT = '/media/%s/' % PROJECT_DIRNAME
18 WSGI_APPLICATION = '%s.wsgi.application' % PROJECT_DIRNAME
19
20 # Celery
21 BROKER_VHOST = PROJECT_DIRNAME
22 BROKER_URL = '%s%s' % (BROKER_URL, BROKER_VHOST)
23
24 DATABASES = {
25 "default": {
26 "ENGINE": "django.db.backends.postgresql_psycopg2",
27 "NAME": "%s" % PROJECT_DIRNAME,
28 "HOST": "127.0.0.1",
29 }
30 }
31
32 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
1 # settings.py
2
3 import os
4 PROJECT_ROOT = os.path.dirname(os.path.abspath(__file__))
5 PROJECT_DIRNAME = PROJECT_ROOT.split(os.sep)[-1]
6
7 # User project directory name as default "theme" app
8 INSTALLED_APPS.insert(1, "%s" % PROJECT_DIRNAME)
9
10 ROOT_URLCONF = '%s.urls' % PROJECT_DIRNAME
11 CACHE_MIDDLEWARE_KEY_PREFIX = '%s' % PROJECT_DIRNAME
12 CACHE_MIDDLEWARE_ALIAS = '%s' % PROJECT_DIRNAME
13 CSRF_COOKIE_NAME = '%s_csrftoken' % PROJECT_DIRNAME
14 LANGUAGE_COOKIE_NAME = '%s_language' % PROJECT_DIRNAME
15 SESSION_COOKIE_NAME = '%s_session' % PROJECT_DIRNAME
16 STATIC_ROOT = '/static/%s/' % PROJECT_DIRNAME
17 MEDIA_ROOT = '/media/%s/' % PROJECT_DIRNAME
18 WSGI_APPLICATION = '%s.wsgi.application' % PROJECT_DIRNAME
19
20 # Celery
21 BROKER_VHOST = PROJECT_DIRNAME
22 BROKER_URL = '%s%s' % (BROKER_URL, BROKER_VHOST)
23
24 DATABASES = {
25 "default": {
26 "ENGINE": "django.db.backends.postgresql_psycopg2",
27 "NAME": "%s" % PROJECT_DIRNAME,
28 "HOST": "127.0.0.1",
29 }
30 }
31
32 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
1 # local_settings.py
2 # (developer's version)
3
4 DEBUG = True
5 TEMPLATE_DEBUG = DEBUG
6 COMPRESS_ENABLED = False
7
8 DATABASES = {
9 "default": {
10 "ENGINE": "django.db.backends.sqlite3",
11 "NAME": "dev.db",
12 }
13 }
14
15 CACHES = {
16 'default': {
17 'BACKEND': 'django.core.cache.backends.dummy.DummyCache',
18 }
19 }
20
21
22 CELERY_CACHE_BACKEND = "dummy"
23 EMAIL_BACKEND = 'kopio.core.mailer.backend.DbBackend'
24 MAILER_EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
25 SESSION_ENGINE = "django.contrib.sessions.backends.signed_cookies"
Wednesday, June 19, 13
urls.py
Wednesday, June 19, 13
• boilerplate default urls (index.html, etc.)
• load urls according to settings.INSTALLED_APPS
Wednesday, June 19, 13
1 # urls.py
2
3 from django.conf.urls import patterns, include, url
4
5
6 urlpatterns = patterns('',
7 ('', include("default_app.urls")),
8 ('', include("mezzanine.urls")),
9 )
Wednesday, June 19, 13
1 # default_urls.py
2
3 urlpatterns = patterns('',
4 # Default index.html
5 url(r'^$', TemplateView.as_view(template_name='index.html'), name="home"),
6
7 # Default favicon
8 url(r'^favicon.ico/$', RedirectView.as_view(url='/static/img/favicon.
9 ico'), name="favicon"),
10 )
11
12 # Default robots.txt
13 urlpatterns += patterns('',
14 url(r'^robots.txt/$', TemplateView.as_view(template_name='robots.txt')),
15 )
16
17 # Admin urls
18 if "django.contrib.admin" in settings.INSTALLED_APPS:
19 from django.contrib import admin
20 admin.autodiscover()
21
22 urlpatterns += patterns("",
23 (r"^admin/", include(admin.site.urls)),
24 )
25
26 # Other apps
27 if "userena" in settings.INSTALLED_APPS:
28 urlpatterns += patterns("",
29 (r'^users/', include('userena.urls')),
30 )
31
32 if "selectable" in settings.INSTALLED_APPS:
33 urlpatterns += patterns("",
34 url(r"^selectable/", include("selectable.urls")),
35 )
36
37 if "actstream" in settings.INSTALLED_APPS:
38 urlpatterns += patterns("",
39 ('^activity/', include('actstream.urls')),
40 )
Wednesday, June 19, 13
1 # default_urls.py
2
3 urlpatterns = patterns('',
4 # Default index.html
5 url(r'^$', TemplateView.as_view(template_name='index.html'), name="home"),
6
7 # Default favicon
8 url(r'^favicon.ico/$', RedirectView.as_view(url='/static/img/favicon.
9 ico'), name="favicon"),
10 )
11
12 # Default robots.txt
13 urlpatterns += patterns('',
14 url(r'^robots.txt/$', TemplateView.as_view(template_name='robots.txt')),
15 )
16
17 # Admin urls
18 if "django.contrib.admin" in settings.INSTALLED_APPS:
19 from django.contrib import admin
20 admin.autodiscover()
21
22 urlpatterns += patterns("",
23 (r"^admin/", include(admin.site.urls)),
24 )
25
26 # Other apps
27 if "userena" in settings.INSTALLED_APPS:
28 urlpatterns += patterns("",
29 (r'^users/', include('userena.urls')),
30 )
31
32 if "selectable" in settings.INSTALLED_APPS:
33 urlpatterns += patterns("",
34 url(r"^selectable/", include("selectable.urls")),
35 )
36
37 if "actstream" in settings.INSTALLED_APPS:
38 urlpatterns += patterns("",
39 ('^activity/', include('actstream.urls')),
40 )
Wednesday, June 19, 13
1 # urls.py
2
3 # Media and Static files for development
4 if settings.DEBUG:
5 # Static files
6 from django.contrib.staticfiles.urls import staticfiles_urlpatterns
7 urlpatterns += staticfiles_urlpatterns()
8
9 # Media files
10 from django.conf.urls.static import static
11 urlpatterns += static(settings.MEDIA_URL, document_root=settings.
12 MEDIA_ROOT)
Wednesday, June 19, 13
#2:‘Dynamic’ App Loading
Wednesday, June 19, 13
• Automatically load all apps in a directory.
• Useful for plugins*
• For more complex usage, .autodiscover()
might be a better choice
Wednesday, June 19, 13
1 # installed_plugins_list.py
2
3 def installed_plugins_list(plugin_path=None):
4 """Function to get a list of plugins from plugin_path
5 """
6 import os
7
8 path = os.path.dirname(__file__)
9 path = os.path.join(path, plugin_path)
10
11 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_plugins
Wednesday, June 19, 13
1 ##########################
2 # LABS SETTINGS #
3 ##########################
4 # Developer's playground #
5 # Play at ur own risk #
6 ##########################
7
8 if LABS_ENABLED and not "sis.labs" in INSTALLED_APPS:
9 from .installed_plugins_list import installed_plugins_list
10
11 TEMPLATE_CONTEXT_PROCESSORS += [
12 "sis.context_processors.sis_labs"
13 ]
14
15 # Loads all modules from sis.plugins
16 for plugin in installed_plugins_list('plugins'):
17 INSTALLED_APPS.insert(0, "sis.plugins.%s" % plugin)
18
19 # Loads all modules from sis.labs.ui
20 for plugin in installed_plugins_list('labs/ui'):
21 INSTALLED_APPS.insert(0, "sis.labs.ui.%s" % plugin)
22
23 # Loads all modules from sis.labs.apps
24 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
#3: Django Themes
Wednesday, June 19, 13
• Themes are just Django apps.
• Actually, themes are Django app with static
files and templates.
• Themes can be overridden, just like how
we override templates.
• For more information,
https://github.com/renyi/mezzanine-themes
Wednesday, June 19, 13
Typical theme structure
my_awesome_theme/
- static/
- img/
- js/
- scripts.js
- css/
- local.css
- templates/
- base.html
- index.html
- includes/main.html
Wednesday, June 19, 13
Where to put the themes ?
Wednesday, June 19, 13
1. Use main app as theme
# directory structure
my_project/my_app/templates
my_project/my_app/static
# in settings.py
INSTALLED_APPS.insert(1, "my_app")
Wednesday, June 19, 13
2. Have a dedicated theme
directory
# directory structure
my_project/my_app/themes/default/templates
my_project/my_app/themes/default/static
# in settings.py
INSTALLED_APPS.insert(1, "my_app.themes.default")
Wednesday, June 19, 13
#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/stephenmcd/django-
overextends
• Allows circular template inheritance.
(base.html can “extend” base.html)
• This allows for simple way of managing
plugable apps (javascripts libraries, etc.) or
let’s call it “plugins”.
Wednesday, June 19, 13
1 <!-- my_app/templates/index.html -->
2 {% extends "base.html" %}
3
4
5 {% block header %}
6 <h1>Hello Title</h1>
7 {% endblock %}
8
9
10 {% block main %}
11 <p>Hello Body</p>
12 {% endblock %}
Wednesday, June 19, 13
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>
11
12 <div role="main" id="main">
13 {% block main %}{% endblock %}
14 </div>
15
16 <footer id="footer">
17 {% block footer %}{% endblock %}
18 </footer>
19
20 {% block js_libs %}{% endblock %}
21 </body>
22 </html>
Wednesday, June 19, 13
1 <!-- my_app/plugins/jquery/templates/base.html -->
2 {% overextends "base.html" %}
3
4
5 {% 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
1 <!-- my_app/plugins/bootstrap/templates/base.html -->
2 {% overextends "base.html" %}
3
4
5 {% 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 %}
10
11
12 {% 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
2 <!DOCTYPE html>
3 <head>
4 <meta charset="utf-8">
5
6 <!-- 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>
17
18 <div role="main" id="main">
19 <!-- block main_styles -->
20 <p>Hello Body</p>
21 <!-- endblock -->
22 </div>
23
24 <footer id="footer">
25 <!-- block footer_styles -->
26 <!-- endblock -->
27 </footer>
28
29 <!-- 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
1 INSTALLED_APPS = [
2 "my_app.themes.default",
3 "my_app.plugins.jquery",
4 "my_app.plugins.bootstrap",
5 ...
6 ]
Inheritance priority
Wednesday, June 19, 13
#5: Class based views
Wednesday, June 19, 13
models.py
Wednesday, June 19, 13
1 # models.py
2
3 from django.db import models
4
5
6 class School(models.Model):
7 title = models.CharField(_("Title"), max_length=500)
8 slug = models.CharField(_("URL"), max_length=2000)
9
10 def __unicode__(self):
11 return self.title
12
13 def save(self, *args, **kwargs):
14 """
15 Create a unique slug by appending an index.
16 """
17 pass
18
19 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
36 class Slugged(models.Model):
37 title = models.CharField(_("Title"), max_length=500)
38 slug = models.CharField(_("URL"), max_length=2000)
39
40 class Meta:
41 abstract = True
42
43 def __unicode__(self):
44 return self.title
45
46 def save(self, *args, **kwargs):
47 """
48 Create a unique slug by appending an index.
49 """
50 pass
51
52 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
1 # models.py
2
3 from django.db import models
4 from .base import Slugged
5
6
7 class School(Slugged):
8 pass
Wednesday, June 19, 13
1 # models.py
2
3 from django.db import models
4 from .base import Slugged
5
6 class School(Slugged):
7
8 @models.permalink
9 def get_absolute_url(self):
10 return ('school_details', None, {'slug': self.slug})
Wednesday, June 19, 13
1 class CrudUrl(models.Model):
2 class Meta:
3 abstract = True
4
5 def __init__(self, *args, **kwargs):
6 self._objname = self._meta.object_name.lower()
7 super(CrudUrl, self).__init__(*args, **kwargs)
8
9 @models.permalink
10 def get_absolute_url(self):
11 return ('%s_details' % self._objname, None, {'slug': self.slug})
12
13 @models.permalink
14 def get_list_url(self):
15 return ('%s_list' % self._objname, None, {})
16
17 @models.permalink
18 def get_create_url(self):
19 return ('%s_create' % self._objname, None, {})
20
21 @models.permalink
22 def get_update_url(self):
23 return ('%s_update' % self._objname, None, {'slug': self.slug})
24
25 @models.permalink
26 def get_delete_url(self):
27 return ('%s_delete' % self._objname, None, {'slug': self.slug})
28
Wednesday, June 19, 13
1 class CrudUrl(models.Model):
2 class Meta:
3 abstract = True
4
5 def __init__(self, *args, **kwargs):
6 self._objname = self._meta.object_name.lower()
7 super(CrudUrl, self).__init__(*args, **kwargs)
8
9 @models.permalink
10 def get_absolute_url(self):
11 return ('%s_details' % self._objname, None, {'slug': self.slug})
12
13 @models.permalink
14 def get_list_url(self):
15 return ('%s_list' % self._objname, None, {})
16
17 @models.permalink
18 def get_create_url(self):
19 return ('%s_create' % self._objname, None, {})
20
21 @models.permalink
22 def get_update_url(self):
23 return ('%s_update' % self._objname, None, {'slug': self.slug})
24
25 @models.permalink
26 def get_delete_url(self):
27 return ('%s_delete' % self._objname, None, {'slug': self.slug})
28
Wednesday, June 19, 13
1 # models.py
2
3 from django.db import models
4 from .base import Slugged, CrudUrl
5
6 class School(Slugged, CrudUrl):
7 pass
Wednesday, June 19, 13
urls.py
Wednesday, June 19, 13
1 # urls.py
2
3 from django.conf.urls import patterns, include, url
4 from django.views.generic import (ListView, DetailView,
5 CreateView, UpdateView, DeleteView)
6 from .models import School
7
8
9 urlpatterns = patterns('',
10 url(r'^school/$',
11 ListView.as_view(),
12 name="school_list"),
13
14 url(r'^school/add/$',
15 CreateView.as_view(),
16 name="school_create"),
17
18 url(r'^school/update/(?P<slug>.*)/$',
19 UpdateView.as_view(),
20 name="school_update"),
21
22 url(r'^school/delete/(?P<slug>.*)/$',
23 DeleteView.as_view(),
24 name="school_delete"),
25
26 url(r'^school/(?P<slug>.*)/$',
27 DetailView.as_view(),
28 name="school_details"),
29 )
Wednesday, June 19, 13
views.py
Wednesday, June 19, 13
1 # views.py
2
3 from django.views.generic import (ListView, DetailView,
4 CreateView, UpdateView, DeleteView)
5 from .models import School
6
7
8 class SchoolListView(ListView):
9 '''
10 Template: school/school_list.html
11 '''
12 model = School
13
14 class SchoolDetailView(DetailView):
15 '''
16 Template: school/school_detail.html
17 '''
18 model = School
19
20 class SchoolCreateView(CreateView):
21 '''
22 Template: school/school_form.html
23 '''
24 model = School
25
26 class SchoolUpdateView(UpdateView):
27 '''
28 Template: school/school_form.html
29 '''
30 model = School
31
32 class SchoolDeleteView(DeleteView):
33 '''
34 Template: school/school_confirm_delete.html
35 '''
36 model = School
Wednesday, June 19, 13
1 from django.views.generic.base import TemplateResponseMixin
2
3 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 = []
12
13 try:
14 opts = self.form_class._meta.model._meta
15 except:
16 try:
17 opts = self.object_list.model._meta
18 except:
19 try:
20 opts = self.object._meta
21 except:
22 opts = None
23
24 # Generates template name based on object name
24 if opts:
25 opts_list = (opts.app_label, opts.object_name.lower(), self.
26 template_name_suffix)
27
28 if self.request.is_ajax():
29 name = "%s/includes/%s%s.html" % opts_list
30
31 else:
32 name = "%s/%s%s.html" % opts_list
33
34 names.append(name)
35
36 return names
Wednesday, June 19, 13
1 from django.views.generic.base import TemplateResponseMixin
2
3 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 = []
12
13 try:
14 opts = self.form_class._meta.model._meta
15 except:
16 try:
17 opts = self.object_list.model._meta
18 except:
19 try:
20 opts = self.object._meta
21 except:
22 opts = None
23
24 # Generates template name based on object name
24 if opts:
25 opts_list = (opts.app_label, opts.object_name.lower(), self.
26 template_name_suffix)
27
28 if self.request.is_ajax():
29 name = "%s/includes/%s%s.html" % opts_list
30
31 else:
32 name = "%s/%s%s.html" % opts_list
33
34 names.append(name)
35
36 return names
Wednesday, June 19, 13
1 from django.views.generic.base import TemplateResponseMixin
2
3 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 = []
12
13 try:
14 opts = self.form_class._meta.model._meta
15 except:
16 try:
17 opts = self.object_list.model._meta
18 except:
19 try:
20 opts = self.object._meta
21 except:
22 opts = None
23
24 # Generates template name based on object name
24 if opts:
25 opts_list = (opts.app_label, opts.object_name.lower(), self.
26 template_name_suffix)
27
28 if self.request.is_ajax():
29 name = "%s/includes/%s%s.html" % opts_list
30
31 else:
32 name = "%s/%s%s.html" % opts_list
33
34 names.append(name)
35
36 return names
Wednesday, June 19, 13
1 # views.py
2
3 from django.views.generic import (ListView, DetailView,
4 CreateView, UpdateView, DeleteView)
5 from .models import School
6 from .mixin import AjaxTemplateResponseMixin
7
8
9 class SchoolListView(ListView, AjaxTemplateResponseMixin):
10 '''
11 Template: school/school_list.html
12 AJAX Template: school/includes/school_list.html
13 '''
14 model = School
15
16 class SchoolDetailView(DetailView, AjaxTemplateResponseMixin):
17 '''
18 Template: school/school_detail.html
19 AJAX Template: school/includes/school_detail.html
20 '''
21 model = School
22
23 class SchoolCreateView(CreateView, AjaxTemplateResponseMixin):
24 '''
25 Template: school/school_form.html
26 AJAX Template: school/includes/school_form.html
27 '''
28 model = School
29
30 class SchoolUpdateView(UpdateView, AjaxTemplateResponseMixin):
31 '''
32 Template: school/school_form.html
33 AJAX Template: school/includes/school_form.html
34 '''
35 model = School
36
Wednesday, June 19, 13
8 class FilterMixin(object):
9 allowed_filters = {}
10
11 def get_queryset_filters(self):
12 filters = {}
13
14 for item in self.request.GET:
15 allowed = self.allowed_filters.get(item)
16 if allowed:
17 keyname = "%s" % allowed
18 filter_values = self.request.GET.getlist(item)
19 filters[keyname] = filter_values
20 return filters
21
22 def get_queryset(self):
23 qs = super(FilterMixin, self).get_queryset()
24 return qs.filter(**self.get_queryset_filters())
Wednesday, June 19, 13
Wednesday, June 19, 13
8 class FilterMixin(object):
9 allowed_filters = {}
10
11 def get_queryset_filters(self):
12 filters = {}
13
14 for item in self.request.GET:
15 allowed = self.allowed_filters.get(item)
16 if allowed:
17 keyname = "%s" % allowed
18 filter_values = self.request.GET.getlist(item)
19 filters[keyname] = filter_values
20 return filters
21
22 def get_queryset(self):
23 qs = super(FilterMixin, self).get_queryset()
24 return qs.filter(**self.get_queryset_filters())
Wednesday, June 19, 13
8 class FilterMixin(object):
9 allowed_filters = {}
10
11 def get_queryset_filters(self):
12 filters = {}
13
14 for item in self.request.GET:
15 allowed = self.allowed_filters.get(item)
16 if allowed:
17 keyname = "%s" % allowed
18 filter_values = self.request.GET.getlist(item)
19 filters[keyname] = filter_values
20 return filters
21
22 def get_queryset(self):
23 qs = super(FilterMixin, self).get_queryset()
24 return qs.filter(**self.get_queryset_filters())
Wednesday, June 19, 13
1 # views.py
2
3 from django.views.generic import (ListView, DetailView,
4 CreateView, UpdateView, DeleteView)
5 from .models import School
6 from .mixin import AjaxTemplateResponseMixin, FilterMixin
7
8
9 class SchoolListView(ListView, FilterMixin,
AjaxTemplateResponseMixin):
10 '''
11 Template: school/school_list.html
12 AJAX Template: school/includes/school_list.html
13 '''
14 model = School
15 allowed_filters = {
16 'title': 'title__icontains',
17 'slug': 'slug__icontains',
18 }
19
Wednesday, June 19, 13
urls.py
Wednesday, June 19, 13
1 # urls.py
2
3 from django.conf.urls import patterns, include, url
4 from .views import (SchoolListView, SchoolDetailView,
5 SchoolCreateView, SchoolUpdateView,
6 SchoolDeleteView)
7 from .models import School
8
9
10 urlpatterns = patterns('',
11 url(r'^school/$',
12 SchoolListView.as_view(),
13 name="school_list"),
14
15 url(r'^school/add/$',
16 SchoolCreateView.as_view(),
17 name="school_create"),
18
19 url(r'^school/update/(?P<slug>.*)/$',
20 SchoolUpdateView.as_view(),
21 name="school_update"),
22
23 url(r'^school/delete/(?P<slug>.*)/$',
24 SchoolDeleteView.as_view(),
25 name="school_delete"),
26
27 url(r'^school/(?P<slug>.*)/$',
28 SchoolDetailView.as_view(),
29 name="school_details"),
30 )
Wednesday, June 19, 13
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 foreign
keys.
- More flexibility
Wednesday, June 19, 13
2. Custom User Model ?
Cons
- might break contrib.admin
- might break old apps
- might break stuffs tied to user (like permission) if
custom model is not implemented correctly.
Wednesday, June 19, 13
2. Custom User Model ?
Conclusion
-Yes, if you’re just extending the user model. If you
inherit from AbstractUser, you should be fine.
- No, if you want to override existing fields or
functions. Unless you know what you’re doing, you
might end up breaking compatibility with other apps.
Wednesday, June 19, 13
2. Custom User Model ?
Implementation
- Add to settings.py, AUTH_USER_MODEL = 'myuser.MyModel'.
Wednesday, June 19, 13
Thank You !
by Renyi Khor
renyi.ace@gmail.com
@renyikhor
https://github.com/renyi/django-tips-and-tricks
Wednesday, June 19, 13

Mais conteúdo relacionado

Semelhante a Django tips & tricks

The Best (and Worst) of Django
The Best (and Worst) of DjangoThe Best (and Worst) of Django
The Best (and Worst) of DjangoJacob Kaplan-Moss
 
Let Grunt do the work, focus on the fun! [Open Web Camp 2013]
Let Grunt do the work, focus on the fun! [Open Web Camp 2013]Let Grunt do the work, focus on the fun! [Open Web Camp 2013]
Let Grunt do the work, focus on the fun! [Open Web Camp 2013]Dirk Ginader
 
Prototyping in the cloud
Prototyping in the cloudPrototyping in the cloud
Prototyping in the cloudKirsten Hunter
 
Pyramid Lighter/Faster/Better web apps
Pyramid Lighter/Faster/Better web appsPyramid Lighter/Faster/Better web apps
Pyramid Lighter/Faster/Better web appsDylan Jay
 
Denver emberjs-sept-2015
Denver emberjs-sept-2015Denver emberjs-sept-2015
Denver emberjs-sept-2015Ron White
 
Introduction to Django
Introduction to DjangoIntroduction to Django
Introduction to DjangoJames Casey
 
Google I/O 2021 Recap
Google I/O 2021 RecapGoogle I/O 2021 Recap
Google I/O 2021 Recapfurusin
 
How to build an AngularJS backend-ready app WITHOUT BACKEND
How to build an AngularJS backend-ready app WITHOUT BACKEND How to build an AngularJS backend-ready app WITHOUT BACKEND
How to build an AngularJS backend-ready app WITHOUT BACKEND Enrique Oriol Bermúdez
 
Desenvolvendo uma aplicação híbrida para Android e IOs utilizando Ionic, aces...
Desenvolvendo uma aplicação híbrida para Android e IOs utilizando Ionic, aces...Desenvolvendo uma aplicação híbrida para Android e IOs utilizando Ionic, aces...
Desenvolvendo uma aplicação híbrida para Android e IOs utilizando Ionic, aces...Juliano Martins
 
Tek 2013 - Building Web Apps from a New Angle with AngularJS
Tek 2013 - Building Web Apps from a New Angle with AngularJSTek 2013 - Building Web Apps from a New Angle with AngularJS
Tek 2013 - Building Web Apps from a New Angle with AngularJSPablo Godel
 
Let Grunt do the work, focus on the fun!
Let Grunt do the work, focus on the fun!Let Grunt do the work, focus on the fun!
Let Grunt do the work, focus on the fun!Dirk Ginader
 
Webapplikationen mit Backbone.js
Webapplikationen mit Backbone.jsWebapplikationen mit Backbone.js
Webapplikationen mit Backbone.jsSebastian Springer
 
Using Buildout, GenericSetup and a Policy Package to Rule the World
Using Buildout, GenericSetup and a Policy Package to Rule the WorldUsing Buildout, GenericSetup and a Policy Package to Rule the World
Using Buildout, GenericSetup and a Policy Package to Rule the WorldClayton Parker
 
Deploying a Pylons app to Google App Engine
Deploying a Pylons app to Google App EngineDeploying a Pylons app to Google App Engine
Deploying a Pylons app to Google App EngineJazkarta, Inc.
 
How to Webpack your Django!
How to Webpack your Django!How to Webpack your Django!
How to Webpack your Django!David Gibbons
 

Semelhante a Django tips & tricks (20)

The Best (and Worst) of Django
The Best (and Worst) of DjangoThe Best (and Worst) of Django
The Best (and Worst) of Django
 
Let Grunt do the work, focus on the fun! [Open Web Camp 2013]
Let Grunt do the work, focus on the fun! [Open Web Camp 2013]Let Grunt do the work, focus on the fun! [Open Web Camp 2013]
Let Grunt do the work, focus on the fun! [Open Web Camp 2013]
 
Prototyping in the cloud
Prototyping in the cloudPrototyping in the cloud
Prototyping in the cloud
 
Pyramid Lighter/Faster/Better web apps
Pyramid Lighter/Faster/Better web appsPyramid Lighter/Faster/Better web apps
Pyramid Lighter/Faster/Better web apps
 
Denver emberjs-sept-2015
Denver emberjs-sept-2015Denver emberjs-sept-2015
Denver emberjs-sept-2015
 
Introduction to Django
Introduction to DjangoIntroduction to Django
Introduction to Django
 
Seti 09
Seti 09Seti 09
Seti 09
 
Google I/O 2021 Recap
Google I/O 2021 RecapGoogle I/O 2021 Recap
Google I/O 2021 Recap
 
How to build an AngularJS backend-ready app WITHOUT BACKEND
How to build an AngularJS backend-ready app WITHOUT BACKEND How to build an AngularJS backend-ready app WITHOUT BACKEND
How to build an AngularJS backend-ready app WITHOUT BACKEND
 
Desenvolvendo uma aplicação híbrida para Android e IOs utilizando Ionic, aces...
Desenvolvendo uma aplicação híbrida para Android e IOs utilizando Ionic, aces...Desenvolvendo uma aplicação híbrida para Android e IOs utilizando Ionic, aces...
Desenvolvendo uma aplicação híbrida para Android e IOs utilizando Ionic, aces...
 
pyscript_django.pdf
pyscript_django.pdfpyscript_django.pdf
pyscript_django.pdf
 
Tek 2013 - Building Web Apps from a New Angle with AngularJS
Tek 2013 - Building Web Apps from a New Angle with AngularJSTek 2013 - Building Web Apps from a New Angle with AngularJS
Tek 2013 - Building Web Apps from a New Angle with AngularJS
 
Django
DjangoDjango
Django
 
Let Grunt do the work, focus on the fun!
Let Grunt do the work, focus on the fun!Let Grunt do the work, focus on the fun!
Let Grunt do the work, focus on the fun!
 
Django
DjangoDjango
Django
 
Webapplikationen mit Backbone.js
Webapplikationen mit Backbone.jsWebapplikationen mit Backbone.js
Webapplikationen mit Backbone.js
 
Using Buildout, GenericSetup and a Policy Package to Rule the World
Using Buildout, GenericSetup and a Policy Package to Rule the WorldUsing Buildout, GenericSetup and a Policy Package to Rule the World
Using Buildout, GenericSetup and a Policy Package to Rule the World
 
Deploying a Pylons app to Google App Engine
Deploying a Pylons app to Google App EngineDeploying a Pylons app to Google App Engine
Deploying a Pylons app to Google App Engine
 
Agile and rails
Agile and railsAgile and rails
Agile and rails
 
How to Webpack your Django!
How to Webpack your Django!How to Webpack your Django!
How to Webpack your Django!
 

Último

Vertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsVertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsMiki Katsuragi
 
Powerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time ClashPowerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time Clashcharlottematthew16
 
What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024Stephanie Beckett
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Commit University
 
The Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsThe Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsPixlogix Infotech
 
H2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo Day
H2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo DayH2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo Day
H2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo DaySri Ambati
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii SoldatenkoFwdays
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr BaganFwdays
 
SAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxSAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxNavinnSomaal
 
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek SchlawackFwdays
 
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024BookNet Canada
 
Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Mattias Andersson
 
Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 3652toLead Limited
 
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc
 
Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Manik S Magar
 
Scanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsScanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsRizwan Syed
 
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage CostLeverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage CostZilliz
 
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdfHyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdfPrecisely
 
Artificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxArtificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxhariprasad279825
 

Último (20)

Vertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsVertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering Tips
 
Powerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time ClashPowerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time Clash
 
What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!
 
The Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsThe Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and Cons
 
H2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo Day
H2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo DayH2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo Day
H2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo Day
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan
 
SAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxSAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptx
 
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
 
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
 
Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?
 
Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365
 
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
 
Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!
 
Scanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsScanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL Certs
 
DMCC Future of Trade Web3 - Special Edition
DMCC Future of Trade Web3 - Special EditionDMCC Future of Trade Web3 - Special Edition
DMCC Future of Trade Web3 - Special Edition
 
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage CostLeverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
 
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdfHyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
 
Artificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxArtificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptx
 

Django tips & tricks

  • 1. Django: Tips & Tricks by Renyi Khor renyi.ace@gmail.com @renyikhor https://github.com/renyi/django-tips-and-tricks Wednesday, June 19, 13
  • 3. Disclaimer • I’m not a super pro pythonista, but I’m a very lazy one. Wednesday, June 19, 13
  • 4. Disclaimer • I’m not a super pro pythonista, but I’m a very lazy one. • Speed - means programmer’s programming speed, unless specified otherwise. Wednesday, June 19, 13
  • 5. Disclaimer • I’m not a super pro pythonista, but I’m a very lazy one. • Speed - means programmer’s programming speed, unless specified otherwise. • I like to do things as short and as easy as possible. Wednesday, June 19, 13
  • 6. Disclaimer • I’m not a super pro pythonista, but I’m a very lazy one. • Speed - means programmer’s programming speed, unless specified otherwise. • I like to do things as short and as easy as possible. • DRYKISS = Don’t repeat yourself + Keep it super simple Wednesday, June 19, 13
  • 7. ACE EdVenture Pixel Head of R&D and Lead Developer SchoolHub School Management System What we use python for ? SchoolHub is built on top of Django Web Framework Wednesday, June 19, 13
  • 8. ACE EdVenture Studio Head of R&D ChemQuest: Petticles in Peril Chemistry based RPG game. What we use python for ? Most of the web components are built with Django Web Framework (Web login, Game Achievements, etc.) Wednesday, June 19, 13
  • 9. #1: Boilerplate Everything (that you can) Wednesday, 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 project Wednesday, June 19, 13
  • 12. 1 # default_settings.py 2 3 DEBUG = False 4 TEMPLATE_DEBUG = False 5 USE_SOUTH = True 6 ADMINS = [('Devtune Admin', 'admin@devtune.biz')] 7 MANAGERS = ADMINS 8 USE_I18N = True 9 USE_L10N = True 10 LANGUAGE_CODE = "en-gb" 11 USE_TZ = True 12 TIME_ZONE = 'Asia/Kuala_Lumpur' 13 INTERNAL_IPS = ["127.0.0.1"] 14 SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db' 15 SESSION_EXPIRE_AT_BROWSER_CLOSE = True 16 SITE_ID = 1 17 STATIC_URL = '/static/' 18 MEDIA_URL = '/media' 19 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.py 2 3 from .default_settings import * 4 5 # Inserts default theme app 6 INSTALLED_APPS.insert(1, "my_project.themes.default") 7 8 # Removes CSRF checking 9 if "django.middleware.csrf.CsrfViewMiddleware" in MIDDLEWARE_CLASSES: 10 MIDDLEWARE_CLASSES.remove("django.middleware.csrf.CsrfViewMiddleware") 11 12 # LOCAL SETTINGS # 13 try: 14 from local_settings import * 15 except ImportError: 16 pass 17 18 # DYNAMIC SETTINGS # 19 try: 20 from mezzanine.utils.conf import set_dynamic_settings 21 except ImportError: 22 pass 23 else: 24 set_dynamic_settings(globals()) Wednesday, June 19, 13
  • 14. 1 # settings.py 2 3 import os 4 PROJECT_ROOT = os.path.dirname(os.path.abspath(__file__)) 5 PROJECT_DIRNAME = PROJECT_ROOT.split(os.sep)[-1] 6 7 # User project directory name as default "theme" app 8 INSTALLED_APPS.insert(1, "%s" % PROJECT_DIRNAME) 9 10 ROOT_URLCONF = '%s.urls' % PROJECT_DIRNAME 11 CACHE_MIDDLEWARE_KEY_PREFIX = '%s' % PROJECT_DIRNAME 12 CACHE_MIDDLEWARE_ALIAS = '%s' % PROJECT_DIRNAME 13 CSRF_COOKIE_NAME = '%s_csrftoken' % PROJECT_DIRNAME 14 LANGUAGE_COOKIE_NAME = '%s_language' % PROJECT_DIRNAME 15 SESSION_COOKIE_NAME = '%s_session' % PROJECT_DIRNAME 16 STATIC_ROOT = '/static/%s/' % PROJECT_DIRNAME 17 MEDIA_ROOT = '/media/%s/' % PROJECT_DIRNAME 18 WSGI_APPLICATION = '%s.wsgi.application' % PROJECT_DIRNAME 19 20 # Celery 21 BROKER_VHOST = PROJECT_DIRNAME 22 BROKER_URL = '%s%s' % (BROKER_URL, BROKER_VHOST) 23 24 DATABASES = { 25 "default": { 26 "ENGINE": "django.db.backends.postgresql_psycopg2", 27 "NAME": "%s" % PROJECT_DIRNAME, 28 "HOST": "127.0.0.1", 29 } 30 } 31 32 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.py 2 3 import os 4 PROJECT_ROOT = os.path.dirname(os.path.abspath(__file__)) 5 PROJECT_DIRNAME = PROJECT_ROOT.split(os.sep)[-1] 6 7 # User project directory name as default "theme" app 8 INSTALLED_APPS.insert(1, "%s" % PROJECT_DIRNAME) 9 10 ROOT_URLCONF = '%s.urls' % PROJECT_DIRNAME 11 CACHE_MIDDLEWARE_KEY_PREFIX = '%s' % PROJECT_DIRNAME 12 CACHE_MIDDLEWARE_ALIAS = '%s' % PROJECT_DIRNAME 13 CSRF_COOKIE_NAME = '%s_csrftoken' % PROJECT_DIRNAME 14 LANGUAGE_COOKIE_NAME = '%s_language' % PROJECT_DIRNAME 15 SESSION_COOKIE_NAME = '%s_session' % PROJECT_DIRNAME 16 STATIC_ROOT = '/static/%s/' % PROJECT_DIRNAME 17 MEDIA_ROOT = '/media/%s/' % PROJECT_DIRNAME 18 WSGI_APPLICATION = '%s.wsgi.application' % PROJECT_DIRNAME 19 20 # Celery 21 BROKER_VHOST = PROJECT_DIRNAME 22 BROKER_URL = '%s%s' % (BROKER_URL, BROKER_VHOST) 23 24 DATABASES = { 25 "default": { 26 "ENGINE": "django.db.backends.postgresql_psycopg2", 27 "NAME": "%s" % PROJECT_DIRNAME, 28 "HOST": "127.0.0.1", 29 } 30 } 31 32 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.py 2 3 import os 4 PROJECT_ROOT = os.path.dirname(os.path.abspath(__file__)) 5 PROJECT_DIRNAME = PROJECT_ROOT.split(os.sep)[-1] 6 7 # User project directory name as default "theme" app 8 INSTALLED_APPS.insert(1, "%s" % PROJECT_DIRNAME) 9 10 ROOT_URLCONF = '%s.urls' % PROJECT_DIRNAME 11 CACHE_MIDDLEWARE_KEY_PREFIX = '%s' % PROJECT_DIRNAME 12 CACHE_MIDDLEWARE_ALIAS = '%s' % PROJECT_DIRNAME 13 CSRF_COOKIE_NAME = '%s_csrftoken' % PROJECT_DIRNAME 14 LANGUAGE_COOKIE_NAME = '%s_language' % PROJECT_DIRNAME 15 SESSION_COOKIE_NAME = '%s_session' % PROJECT_DIRNAME 16 STATIC_ROOT = '/static/%s/' % PROJECT_DIRNAME 17 MEDIA_ROOT = '/media/%s/' % PROJECT_DIRNAME 18 WSGI_APPLICATION = '%s.wsgi.application' % PROJECT_DIRNAME 19 20 # Celery 21 BROKER_VHOST = PROJECT_DIRNAME 22 BROKER_URL = '%s%s' % (BROKER_URL, BROKER_VHOST) 23 24 DATABASES = { 25 "default": { 26 "ENGINE": "django.db.backends.postgresql_psycopg2", 27 "NAME": "%s" % PROJECT_DIRNAME, 28 "HOST": "127.0.0.1", 29 } 30 } 31 32 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.py 2 # (developer's version) 3 4 DEBUG = True 5 TEMPLATE_DEBUG = DEBUG 6 COMPRESS_ENABLED = False 7 8 DATABASES = { 9 "default": { 10 "ENGINE": "django.db.backends.sqlite3", 11 "NAME": "dev.db", 12 } 13 } 14 15 CACHES = { 16 'default': { 17 'BACKEND': 'django.core.cache.backends.dummy.DummyCache', 18 } 19 } 20 21 22 CELERY_CACHE_BACKEND = "dummy" 23 EMAIL_BACKEND = 'kopio.core.mailer.backend.DbBackend' 24 MAILER_EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' 25 SESSION_ENGINE = "django.contrib.sessions.backends.signed_cookies" Wednesday, June 19, 13
  • 19. • boilerplate default urls (index.html, etc.) • load urls according to settings.INSTALLED_APPS Wednesday, June 19, 13
  • 20. 1 # urls.py 2 3 from django.conf.urls import patterns, include, url 4 5 6 urlpatterns = patterns('', 7 ('', include("default_app.urls")), 8 ('', include("mezzanine.urls")), 9 ) Wednesday, June 19, 13
  • 21. 1 # default_urls.py 2 3 urlpatterns = patterns('', 4 # Default index.html 5 url(r'^$', TemplateView.as_view(template_name='index.html'), name="home"), 6 7 # Default favicon 8 url(r'^favicon.ico/$', RedirectView.as_view(url='/static/img/favicon. 9 ico'), name="favicon"), 10 ) 11 12 # Default robots.txt 13 urlpatterns += patterns('', 14 url(r'^robots.txt/$', TemplateView.as_view(template_name='robots.txt')), 15 ) 16 17 # Admin urls 18 if "django.contrib.admin" in settings.INSTALLED_APPS: 19 from django.contrib import admin 20 admin.autodiscover() 21 22 urlpatterns += patterns("", 23 (r"^admin/", include(admin.site.urls)), 24 ) 25 26 # Other apps 27 if "userena" in settings.INSTALLED_APPS: 28 urlpatterns += patterns("", 29 (r'^users/', include('userena.urls')), 30 ) 31 32 if "selectable" in settings.INSTALLED_APPS: 33 urlpatterns += patterns("", 34 url(r"^selectable/", include("selectable.urls")), 35 ) 36 37 if "actstream" in settings.INSTALLED_APPS: 38 urlpatterns += patterns("", 39 ('^activity/', include('actstream.urls')), 40 ) Wednesday, June 19, 13
  • 22. 1 # default_urls.py 2 3 urlpatterns = patterns('', 4 # Default index.html 5 url(r'^$', TemplateView.as_view(template_name='index.html'), name="home"), 6 7 # Default favicon 8 url(r'^favicon.ico/$', RedirectView.as_view(url='/static/img/favicon. 9 ico'), name="favicon"), 10 ) 11 12 # Default robots.txt 13 urlpatterns += patterns('', 14 url(r'^robots.txt/$', TemplateView.as_view(template_name='robots.txt')), 15 ) 16 17 # Admin urls 18 if "django.contrib.admin" in settings.INSTALLED_APPS: 19 from django.contrib import admin 20 admin.autodiscover() 21 22 urlpatterns += patterns("", 23 (r"^admin/", include(admin.site.urls)), 24 ) 25 26 # Other apps 27 if "userena" in settings.INSTALLED_APPS: 28 urlpatterns += patterns("", 29 (r'^users/', include('userena.urls')), 30 ) 31 32 if "selectable" in settings.INSTALLED_APPS: 33 urlpatterns += patterns("", 34 url(r"^selectable/", include("selectable.urls")), 35 ) 36 37 if "actstream" in settings.INSTALLED_APPS: 38 urlpatterns += patterns("", 39 ('^activity/', include('actstream.urls')), 40 ) Wednesday, June 19, 13
  • 23. 1 # urls.py 2 3 # Media and Static files for development 4 if settings.DEBUG: 5 # Static files 6 from django.contrib.staticfiles.urls import staticfiles_urlpatterns 7 urlpatterns += staticfiles_urlpatterns() 8 9 # Media files 10 from django.conf.urls.static import static 11 urlpatterns += static(settings.MEDIA_URL, document_root=settings. 12 MEDIA_ROOT) Wednesday, June 19, 13
  • 25. • Automatically load all apps in a directory. • Useful for plugins* • For more complex usage, .autodiscover() might be a better choice Wednesday, June 19, 13
  • 26. 1 # installed_plugins_list.py 2 3 def installed_plugins_list(plugin_path=None): 4 """Function to get a list of plugins from plugin_path 5 """ 6 import os 7 8 path = os.path.dirname(__file__) 9 path = os.path.join(path, plugin_path) 10 11 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_plugins Wednesday, June 19, 13
  • 27. 1 ########################## 2 # LABS SETTINGS # 3 ########################## 4 # Developer's playground # 5 # Play at ur own risk # 6 ########################## 7 8 if LABS_ENABLED and not "sis.labs" in INSTALLED_APPS: 9 from .installed_plugins_list import installed_plugins_list 10 11 TEMPLATE_CONTEXT_PROCESSORS += [ 12 "sis.context_processors.sis_labs" 13 ] 14 15 # Loads all modules from sis.plugins 16 for plugin in installed_plugins_list('plugins'): 17 INSTALLED_APPS.insert(0, "sis.plugins.%s" % plugin) 18 19 # Loads all modules from sis.labs.ui 20 for plugin in installed_plugins_list('labs/ui'): 21 INSTALLED_APPS.insert(0, "sis.labs.ui.%s" % plugin) 22 23 # Loads all modules from sis.labs.apps 24 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
  • 29. • Themes are just Django apps. • Actually, themes are Django app with static files and templates. • Themes can be overridden, just like how we override templates. • For more information, https://github.com/renyi/mezzanine-themes Wednesday, June 19, 13
  • 30. Typical theme structure my_awesome_theme/ - static/ - img/ - js/ - scripts.js - css/ - local.css - templates/ - base.html - index.html - includes/main.html Wednesday, June 19, 13
  • 31. Where to put the themes ? Wednesday, June 19, 13
  • 32. 1. Use main app as theme # directory structure my_project/my_app/templates my_project/my_app/static # in settings.py INSTALLED_APPS.insert(1, "my_app") Wednesday, June 19, 13
  • 33. 2. Have a dedicated theme directory # directory structure my_project/my_app/themes/default/templates my_project/my_app/themes/default/static # in settings.py INSTALLED_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 managing plugable apps (javascripts libraries, etc.) or let’s call it “plugins”. Wednesday, June 19, 13
  • 36. 1 <!-- my_app/templates/index.html --> 2 {% extends "base.html" %} 3 4 5 {% block header %} 6 <h1>Hello Title</h1> 7 {% endblock %} 8 9 10 {% 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> 11 12 <div role="main" id="main"> 13 {% block main %}{% endblock %} 14 </div> 15 16 <footer id="footer"> 17 {% block footer %}{% endblock %} 18 </footer> 19 20 {% 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" %} 3 4 5 {% 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" %} 3 4 5 {% 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 %} 10 11 12 {% 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"> 5 6 <!-- 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> 17 18 <div role="main" id="main"> 19 <!-- block main_styles --> 20 <p>Hello Body</p> 21 <!-- endblock --> 22 </div> 23 24 <footer id="footer"> 25 <!-- block footer_styles --> 26 <!-- endblock --> 27 </footer> 28 29 <!-- 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 priority Wednesday, June 19, 13
  • 42. #5: Class based views Wednesday, June 19, 13
  • 44. 1 # models.py 2 3 from django.db import models 4 5 6 class School(models.Model): 7 title = models.CharField(_("Title"), max_length=500) 8 slug = models.CharField(_("URL"), max_length=2000) 9 10 def __unicode__(self): 11 return self.title 12 13 def save(self, *args, **kwargs): 14 """ 15 Create a unique slug by appending an index. 16 """ 17 pass 18 19 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) 39 40 class Meta: 41 abstract = True 42 43 def __unicode__(self): 44 return self.title 45 46 def save(self, *args, **kwargs): 47 """ 48 Create a unique slug by appending an index. 49 """ 50 pass 51 52 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.py 2 3 from django.db import models 4 from .base import Slugged 5 6 7 class School(Slugged): 8 pass Wednesday, June 19, 13
  • 47. 1 # models.py 2 3 from django.db import models 4 from .base import Slugged 5 6 class School(Slugged): 7 8 @models.permalink 9 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 = True 4 5 def __init__(self, *args, **kwargs): 6 self._objname = self._meta.object_name.lower() 7 super(CrudUrl, self).__init__(*args, **kwargs) 8 9 @models.permalink 10 def get_absolute_url(self): 11 return ('%s_details' % self._objname, None, {'slug': self.slug}) 12 13 @models.permalink 14 def get_list_url(self): 15 return ('%s_list' % self._objname, None, {}) 16 17 @models.permalink 18 def get_create_url(self): 19 return ('%s_create' % self._objname, None, {}) 20 21 @models.permalink 22 def get_update_url(self): 23 return ('%s_update' % self._objname, None, {'slug': self.slug}) 24 25 @models.permalink 26 def get_delete_url(self): 27 return ('%s_delete' % self._objname, None, {'slug': self.slug}) 28 Wednesday, June 19, 13
  • 49. 1 class CrudUrl(models.Model): 2 class Meta: 3 abstract = True 4 5 def __init__(self, *args, **kwargs): 6 self._objname = self._meta.object_name.lower() 7 super(CrudUrl, self).__init__(*args, **kwargs) 8 9 @models.permalink 10 def get_absolute_url(self): 11 return ('%s_details' % self._objname, None, {'slug': self.slug}) 12 13 @models.permalink 14 def get_list_url(self): 15 return ('%s_list' % self._objname, None, {}) 16 17 @models.permalink 18 def get_create_url(self): 19 return ('%s_create' % self._objname, None, {}) 20 21 @models.permalink 22 def get_update_url(self): 23 return ('%s_update' % self._objname, None, {'slug': self.slug}) 24 25 @models.permalink 26 def get_delete_url(self): 27 return ('%s_delete' % self._objname, None, {'slug': self.slug}) 28 Wednesday, June 19, 13
  • 50. 1 # models.py 2 3 from django.db import models 4 from .base import Slugged, CrudUrl 5 6 class School(Slugged, CrudUrl): 7 pass Wednesday, June 19, 13
  • 52. 1 # urls.py 2 3 from django.conf.urls import patterns, include, url 4 from django.views.generic import (ListView, DetailView, 5 CreateView, UpdateView, DeleteView) 6 from .models import School 7 8 9 urlpatterns = patterns('', 10 url(r'^school/$', 11 ListView.as_view(), 12 name="school_list"), 13 14 url(r'^school/add/$', 15 CreateView.as_view(), 16 name="school_create"), 17 18 url(r'^school/update/(?P<slug>.*)/$', 19 UpdateView.as_view(), 20 name="school_update"), 21 22 url(r'^school/delete/(?P<slug>.*)/$', 23 DeleteView.as_view(), 24 name="school_delete"), 25 26 url(r'^school/(?P<slug>.*)/$', 27 DetailView.as_view(), 28 name="school_details"), 29 ) Wednesday, June 19, 13
  • 54. 1 # views.py 2 3 from django.views.generic import (ListView, DetailView, 4 CreateView, UpdateView, DeleteView) 5 from .models import School 6 7 8 class SchoolListView(ListView): 9 ''' 10 Template: school/school_list.html 11 ''' 12 model = School 13 14 class SchoolDetailView(DetailView): 15 ''' 16 Template: school/school_detail.html 17 ''' 18 model = School 19 20 class SchoolCreateView(CreateView): 21 ''' 22 Template: school/school_form.html 23 ''' 24 model = School 25 26 class SchoolUpdateView(UpdateView): 27 ''' 28 Template: school/school_form.html 29 ''' 30 model = School 31 32 class SchoolDeleteView(DeleteView): 33 ''' 34 Template: school/school_confirm_delete.html 35 ''' 36 model = School Wednesday, June 19, 13
  • 55. 1 from django.views.generic.base import TemplateResponseMixin 2 3 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 = [] 12 13 try: 14 opts = self.form_class._meta.model._meta 15 except: 16 try: 17 opts = self.object_list.model._meta 18 except: 19 try: 20 opts = self.object._meta 21 except: 22 opts = None 23 24 # Generates template name based on object name 24 if opts: 25 opts_list = (opts.app_label, opts.object_name.lower(), self. 26 template_name_suffix) 27 28 if self.request.is_ajax(): 29 name = "%s/includes/%s%s.html" % opts_list 30 31 else: 32 name = "%s/%s%s.html" % opts_list 33 34 names.append(name) 35 36 return names Wednesday, June 19, 13
  • 56. 1 from django.views.generic.base import TemplateResponseMixin 2 3 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 = [] 12 13 try: 14 opts = self.form_class._meta.model._meta 15 except: 16 try: 17 opts = self.object_list.model._meta 18 except: 19 try: 20 opts = self.object._meta 21 except: 22 opts = None 23 24 # Generates template name based on object name 24 if opts: 25 opts_list = (opts.app_label, opts.object_name.lower(), self. 26 template_name_suffix) 27 28 if self.request.is_ajax(): 29 name = "%s/includes/%s%s.html" % opts_list 30 31 else: 32 name = "%s/%s%s.html" % opts_list 33 34 names.append(name) 35 36 return names Wednesday, June 19, 13
  • 57. 1 from django.views.generic.base import TemplateResponseMixin 2 3 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 = [] 12 13 try: 14 opts = self.form_class._meta.model._meta 15 except: 16 try: 17 opts = self.object_list.model._meta 18 except: 19 try: 20 opts = self.object._meta 21 except: 22 opts = None 23 24 # Generates template name based on object name 24 if opts: 25 opts_list = (opts.app_label, opts.object_name.lower(), self. 26 template_name_suffix) 27 28 if self.request.is_ajax(): 29 name = "%s/includes/%s%s.html" % opts_list 30 31 else: 32 name = "%s/%s%s.html" % opts_list 33 34 names.append(name) 35 36 return names Wednesday, June 19, 13
  • 58. 1 # views.py 2 3 from django.views.generic import (ListView, DetailView, 4 CreateView, UpdateView, DeleteView) 5 from .models import School 6 from .mixin import AjaxTemplateResponseMixin 7 8 9 class SchoolListView(ListView, AjaxTemplateResponseMixin): 10 ''' 11 Template: school/school_list.html 12 AJAX Template: school/includes/school_list.html 13 ''' 14 model = School 15 16 class SchoolDetailView(DetailView, AjaxTemplateResponseMixin): 17 ''' 18 Template: school/school_detail.html 19 AJAX Template: school/includes/school_detail.html 20 ''' 21 model = School 22 23 class SchoolCreateView(CreateView, AjaxTemplateResponseMixin): 24 ''' 25 Template: school/school_form.html 26 AJAX Template: school/includes/school_form.html 27 ''' 28 model = School 29 30 class SchoolUpdateView(UpdateView, AjaxTemplateResponseMixin): 31 ''' 32 Template: school/school_form.html 33 AJAX Template: school/includes/school_form.html 34 ''' 35 model = School 36 Wednesday, June 19, 13
  • 59. 8 class FilterMixin(object): 9 allowed_filters = {} 10 11 def get_queryset_filters(self): 12 filters = {} 13 14 for item in self.request.GET: 15 allowed = self.allowed_filters.get(item) 16 if allowed: 17 keyname = "%s" % allowed 18 filter_values = self.request.GET.getlist(item) 19 filters[keyname] = filter_values 20 return filters 21 22 def get_queryset(self): 23 qs = super(FilterMixin, self).get_queryset() 24 return qs.filter(**self.get_queryset_filters()) Wednesday, June 19, 13
  • 61. 8 class FilterMixin(object): 9 allowed_filters = {} 10 11 def get_queryset_filters(self): 12 filters = {} 13 14 for item in self.request.GET: 15 allowed = self.allowed_filters.get(item) 16 if allowed: 17 keyname = "%s" % allowed 18 filter_values = self.request.GET.getlist(item) 19 filters[keyname] = filter_values 20 return filters 21 22 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 = {} 10 11 def get_queryset_filters(self): 12 filters = {} 13 14 for item in self.request.GET: 15 allowed = self.allowed_filters.get(item) 16 if allowed: 17 keyname = "%s" % allowed 18 filter_values = self.request.GET.getlist(item) 19 filters[keyname] = filter_values 20 return filters 21 22 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.py 2 3 from django.views.generic import (ListView, DetailView, 4 CreateView, UpdateView, DeleteView) 5 from .models import School 6 from .mixin import AjaxTemplateResponseMixin, FilterMixin 7 8 9 class SchoolListView(ListView, FilterMixin, AjaxTemplateResponseMixin): 10 ''' 11 Template: school/school_list.html 12 AJAX Template: school/includes/school_list.html 13 ''' 14 model = School 15 allowed_filters = { 16 'title': 'title__icontains', 17 'slug': 'slug__icontains', 18 } 19 Wednesday, June 19, 13
  • 65. 1 # urls.py 2 3 from django.conf.urls import patterns, include, url 4 from .views import (SchoolListView, SchoolDetailView, 5 SchoolCreateView, SchoolUpdateView, 6 SchoolDeleteView) 7 from .models import School 8 9 10 urlpatterns = patterns('', 11 url(r'^school/$', 12 SchoolListView.as_view(), 13 name="school_list"), 14 15 url(r'^school/add/$', 16 SchoolCreateView.as_view(), 17 name="school_create"), 18 19 url(r'^school/update/(?P<slug>.*)/$', 20 SchoolUpdateView.as_view(), 21 name="school_update"), 22 23 url(r'^school/delete/(?P<slug>.*)/$', 24 SchoolDeleteView.as_view(), 25 name="school_delete"), 26 27 url(r'^school/(?P<slug>.*)/$', 28 SchoolDetailView.as_view(), 29 name="school_details"), 30 ) 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 foreign keys. - More flexibility Wednesday, 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) if custom 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 you inherit from AbstractUser, you should be fine. - No, if you want to override existing fields or functions. Unless you know what you’re doing, you might 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 Khor renyi.ace@gmail.com @renyikhor https://github.com/renyi/django-tips-and-tricks Wednesday, June 19, 13