Skip to content

Commit

Permalink
Merge branch 'master' of https://github.com/saturn597/django into 19496
Browse files Browse the repository at this point in the history
  • Loading branch information
saturn597 committed Sep 29, 2013
2 parents 0a4dfce + a834bc8 commit 1f3626b
Show file tree
Hide file tree
Showing 45 changed files with 628 additions and 148 deletions.
1 change: 1 addition & 0 deletions AUTHORS
Expand Up @@ -89,6 +89,7 @@ answer newbie questions, and generally made Django that much better:
David Avsajanishvili <avsd05@gmail.com>
Mike Axiak <axiak@mit.edu>
Niran Babalola <niran@niran.org>
Christopher Babiak <chrisbabiak@gmail.com>
Vitaly Babiy <vbabiy86@gmail.com>
Morten Bagai <m@bagai.com>
Jeff Balogh <jbalogh@mozilla.com>
Expand Down
9 changes: 7 additions & 2 deletions django/contrib/admin/filters.py
Expand Up @@ -303,6 +303,11 @@ def __init__(self, field, request, params, model, model_admin, field_path):
else: # field is a models.DateField
today = now.date()
tomorrow = today + datetime.timedelta(days=1)
if today.month == 12:
next_month = today.replace(year=today.year + 1, month=1, day=1)
else:
next_month = today.replace(month=today.month + 1, day=1)
next_year = today.replace(year=today.year + 1, month=1, day=1)

self.lookup_kwarg_since = '%s__gte' % field_path
self.lookup_kwarg_until = '%s__lt' % field_path
Expand All @@ -318,11 +323,11 @@ def __init__(self, field, request, params, model, model_admin, field_path):
}),
(_('This month'), {
self.lookup_kwarg_since: str(today.replace(day=1)),
self.lookup_kwarg_until: str(tomorrow),
self.lookup_kwarg_until: str(next_month),
}),
(_('This year'), {
self.lookup_kwarg_since: str(today.replace(month=1, day=1)),
self.lookup_kwarg_until: str(tomorrow),
self.lookup_kwarg_until: str(next_year),
}),
)
super(DateFieldListFilter, self).__init__(
Expand Down
17 changes: 17 additions & 0 deletions django/contrib/contenttypes/generic.py
Expand Up @@ -319,6 +319,23 @@ def __init__(self, model=None, instance=None, symmetrical=None,
'%s__exact' % object_id_field_name: instance._get_pk_val(),
}

def __call__(self, **kwargs):
# We use **kwargs rather than a kwarg argument to enforce the
# `manager='manager_name'` syntax.
manager = getattr(self.model, kwargs.pop('manager'))
manager_class = create_generic_related_manager(manager.__class__)
return manager_class(
model = self.model,
instance = self.instance,
symmetrical = self.symmetrical,
source_col_name = self.source_col_name,
target_col_name = self.target_col_name,
content_type = self.content_type,
content_type_field_name = self.content_type_field_name,
object_id_field_name = self.object_id_field_name,
prefetch_cache_name = self.prefetch_cache_name,
)

def get_queryset(self):
try:
return self.instance._prefetched_objects_cache[self.prefetch_cache_name]
Expand Down
21 changes: 18 additions & 3 deletions django/core/cache/backends/db.py
Expand Up @@ -11,6 +11,7 @@
from django.conf import settings
from django.core.cache.backends.base import BaseCache, DEFAULT_TIMEOUT
from django.db import connections, transaction, router, DatabaseError
from django.db.backends.utils import typecast_timestamp
from django.utils import timezone, six
from django.utils.encoding import force_bytes

Expand Down Expand Up @@ -65,8 +66,13 @@ def get(self, key, default=None, version=None):
if row is None:
return default
now = timezone.now()

if row[2] < now:
expires = row[2]
if connections[db].features.needs_datetime_string_cast and not isinstance(expires, datetime):
# Note: typecasting is needed by some 3rd party database backends.
# All core backends work without typecasting, so be careful about
# changes here - test suite will NOT pick regressions here.
expires = typecast_timestamp(str(expires))
if expires < now:
db = router.db_for_write(self.cache_model_class)
cursor = connections[db].cursor()
cursor.execute("DELETE FROM %s "
Expand Down Expand Up @@ -112,12 +118,21 @@ def _base_set(self, mode, key, value, timeout=DEFAULT_TIMEOUT):
if six.PY3:
b64encoded = b64encoded.decode('latin1')
try:
# Note: typecasting for datetimes is needed by some 3rd party
# database backends. All core backends work without typecasting,
# so be careful about changes here - test suite will NOT pick
# regressions.
with transaction.atomic(using=db):
cursor.execute("SELECT cache_key, expires FROM %s "
"WHERE cache_key = %%s" % table, [key])
result = cursor.fetchone()
if result:
current_expires = result[1]
if (connections[db].features.needs_datetime_string_cast and not
isinstance(current_expires, datetime)):
current_expires = typecast_timestamp(str(current_expires))
exp = connections[db].ops.value_to_db_datetime(exp)
if result and (mode == 'set' or (mode == 'add' and result[1] < now)):
if result and (mode == 'set' or (mode == 'add' and current_expires < now)):
cursor.execute("UPDATE %s SET value = %%s, expires = %%s "
"WHERE cache_key = %%s" % table,
[b64encoded, exp, key])
Expand Down
7 changes: 5 additions & 2 deletions django/db/backends/__init__.py
@@ -1,7 +1,7 @@
import datetime
import time

from django.db.utils import DatabaseError
from django.db.utils import DatabaseError, ProgrammingError

try:
from django.utils.six.moves import _thread as thread
Expand Down Expand Up @@ -664,6 +664,9 @@ class BaseDatabaseFeatures(object):
# Does the backend require a connection reset after each material schema change?
connection_persists_old_columns = False

# What kind of error does the backend throw when accessing closed cursor?
closed_cursor_error_class = ProgrammingError

def __init__(self, connection):
self.connection = connection

Expand Down Expand Up @@ -1167,7 +1170,7 @@ def convert_values(self, value, field):
Coerce the value returned by the database backend into a consistent type
that is compatible with the field type.
"""
if value is None:
if value is None or field is None:
return value
internal_type = field.get_internal_type()
if internal_type == 'FloatField':
Expand Down
2 changes: 2 additions & 0 deletions django/db/backends/postgresql_psycopg2/base.py
Expand Up @@ -15,6 +15,7 @@
from django.db.backends.postgresql_psycopg2.version import get_version
from django.db.backends.postgresql_psycopg2.introspection import DatabaseIntrospection
from django.db.backends.postgresql_psycopg2.schema import DatabaseSchemaEditor
from django.db.utils import InterfaceError
from django.utils.encoding import force_str
from django.utils.functional import cached_property
from django.utils.safestring import SafeText, SafeBytes
Expand Down Expand Up @@ -60,6 +61,7 @@ class DatabaseFeatures(BaseDatabaseFeatures):
can_rollback_ddl = True
supports_combined_alters = True
nulls_order_largest = True
closed_cursor_error_class = InterfaceError


class DatabaseWrapper(BaseDatabaseWrapper):
Expand Down
1 change: 1 addition & 0 deletions django/db/backends/postgresql_psycopg2/introspection.py
Expand Up @@ -137,6 +137,7 @@ def get_constraints(self, cursor, table_name):
WHERE
kc.table_schema = %s AND
kc.table_name = %s
ORDER BY kc.ordinal_position ASC
""", ["public", table_name])
for constraint, column, kind, used_cols in cursor.fetchall():
# If we're the first column, make the record
Expand Down
8 changes: 8 additions & 0 deletions django/db/backends/utils.py
Expand Up @@ -36,6 +36,14 @@ def __getattr__(self, attr):
def __iter__(self):
return iter(self.cursor)

def __enter__(self):
return self

def __exit__(self, type, value, traceback):
# Ticket #17671 - Close instead of passing thru to avoid backend
# specific behavior.
self.close()


class CursorDebugWrapper(CursorWrapper):

Expand Down
51 changes: 38 additions & 13 deletions django/db/migrations/operations/special.py
@@ -1,6 +1,7 @@
import re
import textwrap
from .base import Operation
from django.utils import six


class SeparateDatabaseAndState(Operation):
Expand Down Expand Up @@ -106,13 +107,25 @@ class RunPython(Operation):
reduces_to_sql = False
reversible = False

def __init__(self, code):
# Trim any leading whitespace that is at the start of all code lines
# so users can nicely indent code in migration files
code = textwrap.dedent(code)
# Run the code through a parser first to make sure it's at least
# syntactically correct
self.code = compile(code, "<string>", "exec")
def __init__(self, code, reverse_code=None):
# Forwards code
if isinstance(code, six.string_types):
# Trim any leading whitespace that is at the start of all code lines
# so users can nicely indent code in migration files
code = textwrap.dedent(code)
# Run the code through a parser first to make sure it's at least
# syntactically correct
self.code = compile(code, "<string>", "exec")
else:
self.code = code
# Reverse code
if reverse_code is None:
self.reverse_code = None
elif isinstance(reverse_code, six.string_types):
reverse_code = textwrap.dedent(reverse_code)
self.reverse_code = compile(reverse_code, "<string>", "exec")
else:
self.reverse_code = reverse_code

def state_forwards(self, app_label, state):
# RunPython objects have no state effect. To add some, combine this
Expand All @@ -124,14 +137,26 @@ def database_forwards(self, app_label, schema_editor, from_state, to_state):
# object, representing the versioned models as an AppCache.
# We could try to override the global cache, but then people will still
# use direct imports, so we go with a documentation approach instead.
context = {
"models": from_state.render(),
"schema_editor": schema_editor,
}
eval(self.code, context)
if six.callable(self.code):
self.code(models=from_state.render(), schema_editor=schema_editor)
else:
context = {
"models": from_state.render(),
"schema_editor": schema_editor,
}
eval(self.code, context)

def database_backwards(self, app_label, schema_editor, from_state, to_state):
raise NotImplementedError("You cannot reverse this operation")
if self.reverse_code is None:
raise NotImplementedError("You cannot reverse this operation")
elif six.callable(self.reverse_code):
self.reverse_code(models=from_state.render(), schema_editor=schema_editor)
else:
context = {
"models": from_state.render(),
"schema_editor": schema_editor,
}
eval(self.reverse_code, context)

def describe(self):
return "Raw Python operation"
2 changes: 2 additions & 0 deletions django/db/models/fields/__init__.py
Expand Up @@ -1312,6 +1312,8 @@ class IPAddressField(Field):
description = _("IPv4 address")

def __init__(self, *args, **kwargs):
warnings.warn("IPAddressField has been deprecated. Use GenericIPAddressField instead.",
PendingDeprecationWarning)
kwargs['max_length'] = 15
Field.__init__(self, *args, **kwargs)

Expand Down

0 comments on commit 1f3626b

Please sign in to comment.