The task is getting harder and harder, humongous change list.
So we'll discuss some notable changes.
2 new features were crowd funded:
Not official nor stable
for field in self._meta.fields:
if f.name == 'foo':
pass
f = self._meta.get_field('foo')
all_fields_list = self._meta.get_fields()
pip install Jinja2
In settings (new in 1.8):
TEMPLATES = [
{
'BACKEND': 'django.template.backends.jinja2.Jinja2',
'APP_DIRS': True,
},
]
Above APP_DIRS means Jinja2 engines look for templates in
the jinja2 subdirectory of installed applications.
autoescape, correct template loader for APP_DIRS,
auto_reload and undefined.
environment option to add Django specific api. From the docs,
assuming we've created myproject/jinja2.py:
from __future__ import absolute_import # Python 2 only
from django.contrib.staticfiles.storage import staticfiles_storage
from django.core.urlresolvers import reverse
from jinja2 import Environment
def environment(**options):
env = Environment(**options)
env.globals.update({
'static': staticfiles_storage.url,
'url': reverse,
})
return env
TEMPLATE options:
TEMPLATES = [
{
'BACKEND': 'django.template.backends.jinja2.Jinja2',
'APP_DIRS': True,
'OPTIONS': {
'environment': 'myproject.jinja2.environment',
}
},
]
Usage in the template:
Administration
Integrated several features from django-secure
Security Middleware
django.middleware.security.SecurityMiddleware
Provides some security enhancements for request/response. Enable each separately using a setting.
./manage.py check --deploy
New option for check management command --deploy,
check settings file to increase site security.
Stored as the native uuid data type on PostgreSQL and as a fixed length character field on other backends.
Has a corresponding
form field
will accept any any string format accepted as the hex
argument to Python's UUID constructor.
For storing periods of time (timedelta)
interval type on PostgreSQL.INTERVAL DAY(9) TO SECOND(6) on oracle.bigint of microseconds on other backends.
django.contrib.postgres.fields has extensions
for PostgreSQL specific features:
ArrayField, HStoreField,
Range Fields, and unaccent lookup.
class Post(models.Model):
name = models.CharField(max_length=200)
tags = ArrayField(models.CharField(max_length=200), blank=True)
>>> Post.objects.create(name='First post', tags=['thoughts', 'django'])
>>> Post.objects.create(name='Second post', tags=['thoughts'])
>>> Post.objects.create(name='Third post', tags=['tutorial', 'django'])
Multitude of query options, index, and slice transforms:
containscontained_byoverlaplenSee the documentation.
HStoreField stores key/value mappings of strings to strings.
Need to setup the hstore extension on your db by adding a migration with
HStoreExtension operation.
class Dog(models.Model):
name = models.CharField(max_length=200)
data = HStoreField()
>>> Dog.objects.create(name='Rufus', data={'breed': 'labrador'})
>>> Dog.objects.create(name='Meg', data={'breed': 'collie'})
data__breed='collie')containscontained_byhas_keyhas_keyskeysvaluesSee the documentation.
Five range field types, corresponding to the built-in range types in PostgreSQL.
IntegerRangeFieldBigIntegerRangeFieldFloatRangeFieldDateTimeRangeFieldDateRangeFieldCan define custom range types.
class Event(models.Model):
name = models.CharField(max_length=200)
ages = IntegerRangeField()
>>> Event.objects.create(name='Soft play', ages=(0, 10))
>>> Event.objects.create(name='Pub trip', ages=(21, None))
contains
>>> from psycopg2.extras import NumericRange
>>> Event.objects.filter(ages__contains=NumericRange(4, 5))
containscontained_byoverlapfully_ltfully_gtnot_ltnot_gtadjacent_tostartswithendswithisemptyhaccent or use UnaccentExtension
in a migration.
>>> City.objects.filter(name__unaccent="México")
['<City: Mexico>']
>>> User.objects.filter(first_name__unaccent__startswith="Jerem")
['<User: Jeremy>', '<User: Jérémy>', '<User: Jérémie>', '<User: Jeremie>']
More SQL power for us
annotate()
and aggregate()by Josh Smeaton.
order_by() can accept expressions.
# Aggregates can contain complex computations also
Company.objects.annotate(num_offerings=Count(F('products') + F('services')))
# Expressions can also be used in order_by()
Company.objects.order_by(Length('name').asc())
Company.objects.order_by(Length('name').desc())
Let you use if ... elif ... else
logic within filters, annotations, aggregations, and updates
WhenCase
>>> # Get the discount for each Client based on the account type
>>> Client.objects.annotate(
... discount=Case(
... When(account_type=Client.GOLD, then=Value('5%')),
... When(account_type=Client.PLATINUM, then=Value('10%')),
... default=Value('0%'),
... output_field=CharField(),
... ),
... ).values_list('name', 'discount')
>>> a_month_ago = date.today() - timedelta(days=30)
>>> a_year_ago = date.today() - timedelta(days=365)
>>> # Update the account_type for each Client from the registration date
>>> Client.objects.update(
... account_type=Case(
... When(registered_on__lte=a_year_ago,
... then=Value(Client.PLATINUM)),
... When(registered_on__lte=a_month_ago,
... then=Value(Client.GOLD)),
... default=Value(Client.REGULAR)
... ),
... )
>>> Client.objects.values_list('name', 'account_type')
[('Jane Doe', 'G'), ('James Smith', 'R'), ('Jack Black', 'P')]
>>> from django.db.models import IntegerField, Sum
>>> Client.objects.aggregate(
... regular=Sum(
... Case(When(account_type=Client.REGULAR, then=1),
... output_field=IntegerField())
... ),
... gold=Sum(
... Case(When(account_type=Client.GOLD, then=1),
... output_field=IntegerField())
... ),
... platinum=Sum(
... Case(When(account_type=Client.PLATINUM, then=1),
... output_field=IntegerField())
... )
... )
{'regular': 2, 'gold': 1, 'platinum': 3}
Use functions provided by the underlying database in annotations, filters, etc.
CoalesceConcatLengthLowerUpperSubstratomic block, class level and for each test.TestCase.setUpTestData() allows setting initial data at the class level for the whole test.setup() which runs for each test.TestCase is now performed once for the whole TestCasePasswordResetForm by overriding
send_email()has_module_permission().InlineModelAdmin.show_change_link.AdminSite.site_url for the link to "View site", default to "/". AdminSite.has_permission().Form.has_error(field).required_css_class on labels of required fields.Field.label_suffix to override label_suffix per field.runserver uses daemon threads for faster reloading.dumpdata --output.loaddata --ignorenonexistent to ignore data for non existent models.showmigrations.makemigrations --name for custom migration name.insepectdb outputs Meta.uniqute_together,
introspects AutoField for PostgreSQL and MySQL, and introspects database views (only tables in < 1.8).RunSQL can handle parameters.RunSQL.noop and RunPython.noop.default_related_name for model.Model.from_db() can customize model loading behaviour in the ORM.Model.refresh_from_db()EmailField.max_length is 254 instead of 75.GET and POST are QueryDict instead of Dict, FILES is a MultiValueDict.HttpResponse.charsetFileResponse for streaming files.HttpResponse.setdefault(), allows setting a header unless already been set.select_related() checks validity of given fields instead of ignoring.add(), remove(), clear(), direct assignment) are run in a transaction to reduce data corruption risk.django.contrib.formtools moved to separate packages.django.contrib.comments (after the deprecation in 1.6).TransactionMiddleware, decorators and context managers defined in django.db.transaction (autocommit, commit_on_success, and commit_manually).patterns() and string view referencing, instead use:
from django.conf.urls import url
from myapp import views
urlpatterns = [
url('^$', views.myview),
url('^other/$', views.otherview),
]
django.core.context_processors moved to django.template.context_processors.NoArgsCommand, use BaseCommand which takes no arguments by default.django.contrib.webdesign, the lorem tag is now built in.After preparing this talk: