1 """ |
1 """ |
2 Convenience routines for creating non-trivial Field subclasses. |
2 Convenience routines for creating non-trivial Field subclasses, as well as |
|
3 backwards compatibility utilities. |
3 |
4 |
4 Add SubfieldBase as the __metaclass__ for your Field subclass, implement |
5 Add SubfieldBase as the __metaclass__ for your Field subclass, implement |
5 to_python() and the other necessary methods and everything will work seamlessly. |
6 to_python() and the other necessary methods and everything will work seamlessly. |
6 """ |
7 """ |
7 |
8 |
8 class SubfieldBase(type): |
9 from inspect import getargspec |
|
10 from warnings import warn |
|
11 |
|
12 def call_with_connection(func): |
|
13 arg_names, varargs, varkwargs, defaults = getargspec(func) |
|
14 updated = ('connection' in arg_names or varkwargs) |
|
15 if not updated: |
|
16 warn("A Field class whose %s method hasn't been updated to take a " |
|
17 "`connection` argument." % func.__name__, |
|
18 PendingDeprecationWarning, stacklevel=2) |
|
19 |
|
20 def inner(*args, **kwargs): |
|
21 if 'connection' not in kwargs: |
|
22 from django.db import connection |
|
23 kwargs['connection'] = connection |
|
24 warn("%s has been called without providing a connection argument. " % |
|
25 func.__name__, PendingDeprecationWarning, |
|
26 stacklevel=1) |
|
27 if updated: |
|
28 return func(*args, **kwargs) |
|
29 if 'connection' in kwargs: |
|
30 del kwargs['connection'] |
|
31 return func(*args, **kwargs) |
|
32 return inner |
|
33 |
|
34 def call_with_connection_and_prepared(func): |
|
35 arg_names, varargs, varkwargs, defaults = getargspec(func) |
|
36 updated = ( |
|
37 ('connection' in arg_names or varkwargs) and |
|
38 ('prepared' in arg_names or varkwargs) |
|
39 ) |
|
40 if not updated: |
|
41 warn("A Field class whose %s method hasn't been updated to take " |
|
42 "`connection` and `prepared` arguments." % func.__name__, |
|
43 PendingDeprecationWarning, stacklevel=2) |
|
44 |
|
45 def inner(*args, **kwargs): |
|
46 if 'connection' not in kwargs: |
|
47 from django.db import connection |
|
48 kwargs['connection'] = connection |
|
49 warn("%s has been called without providing a connection argument. " % |
|
50 func.__name__, PendingDeprecationWarning, |
|
51 stacklevel=1) |
|
52 if updated: |
|
53 return func(*args, **kwargs) |
|
54 if 'connection' in kwargs: |
|
55 del kwargs['connection'] |
|
56 if 'prepared' in kwargs: |
|
57 del kwargs['prepared'] |
|
58 return func(*args, **kwargs) |
|
59 return inner |
|
60 |
|
61 class LegacyConnection(type): |
|
62 """ |
|
63 A metaclass to normalize arguments give to the get_db_prep_* and db_type |
|
64 methods on fields. |
|
65 """ |
|
66 def __new__(cls, names, bases, attrs): |
|
67 new_cls = super(LegacyConnection, cls).__new__(cls, names, bases, attrs) |
|
68 for attr in ('db_type', 'get_db_prep_save'): |
|
69 setattr(new_cls, attr, call_with_connection(getattr(new_cls, attr))) |
|
70 for attr in ('get_db_prep_lookup', 'get_db_prep_value'): |
|
71 setattr(new_cls, attr, call_with_connection_and_prepared(getattr(new_cls, attr))) |
|
72 return new_cls |
|
73 |
|
74 class SubfieldBase(LegacyConnection): |
9 """ |
75 """ |
10 A metaclass for custom Field subclasses. This ensures the model's attribute |
76 A metaclass for custom Field subclasses. This ensures the model's attribute |
11 has the descriptor protocol attached to it. |
77 has the descriptor protocol attached to it. |
12 """ |
78 """ |
13 def __new__(cls, base, name, attrs): |
79 def __new__(cls, base, name, attrs): |