Skip to content

Commit fcf957d

Browse files
committed
[soc2009/admin-ui] merging trunk up to r11004 into my branch
git-svn-id: http://code.djangoproject.com/svn/django/branches/soc2009/admin-ui@11006 bcc190cf-cafb-0310-a4f2-bffc1f526a37
1 parent 59e26c7 commit fcf957d

File tree

25 files changed

+579
-129
lines changed

25 files changed

+579
-129
lines changed

django/contrib/admin/templates/admin/pagination.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,5 @@
88
{% endif %}
99
{{ cl.result_count }} {% ifequal cl.result_count 1 %}{{ cl.opts.verbose_name }}{% else %}{{ cl.opts.verbose_name_plural }}{% endifequal %}
1010
{% if show_all_url %}&nbsp;&nbsp;<a href="{{ show_all_url }}" class="showall">{% trans 'Show all' %}</a>{% endif %}
11-
{% if cl.formset and cl.result_count %}<input type="submit" name="_save" class="default" value="Save"/>{% endif %}
11+
{% if cl.formset and cl.result_count %}<input type="submit" name="_save" class="default" value="{% trans 'Save' %}"/>{% endif %}
1212
</p>

django/contrib/contenttypes/generic.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -317,7 +317,7 @@ def get_default_prefix(cls):
317317
def get_queryset(self):
318318
# Avoid a circular import.
319319
from django.contrib.contenttypes.models import ContentType
320-
if self.instance is None:
320+
if self.instance is None or self.instance.pk is None:
321321
return self.model._default_manager.none()
322322
return self.model._default_manager.filter(**{
323323
self.ct_field.name: ContentType.objects.get_for_model(self.instance),

django/contrib/gis/gdal/libgdal.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
lib_names = None
1515
elif os.name == 'nt':
1616
# Windows NT shared library
17-
lib_names = ['gdal15']
17+
lib_names = ['gdal16', 'gdal15']
1818
elif os.name == 'posix':
1919
# *NIX library names.
2020
lib_names = ['gdal', 'GDAL', 'gdal1.6.0', 'gdal1.5.0', 'gdal1.4.0']

django/contrib/gis/tests/test_geoip.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -84,16 +84,15 @@ def test04_city(self):
8484
self.assertEqual('USA', d['country_code3'])
8585
self.assertEqual('Houston', d['city'])
8686
self.assertEqual('TX', d['region'])
87-
self.assertEqual('77002', d['postal_code'])
8887
self.assertEqual(713, d['area_code'])
8988
geom = g.geos(query)
9089
self.failIf(not isinstance(geom, GEOSGeometry))
91-
lon, lat = (-95.366996765, 29.752300262)
90+
lon, lat = (-95.4152, 29.7755)
9291
lat_lon = g.lat_lon(query)
9392
lat_lon = (lat_lon[1], lat_lon[0])
9493
for tup in (geom.tuple, g.coords(query), g.lon_lat(query), lat_lon):
95-
self.assertAlmostEqual(lon, tup[0], 9)
96-
self.assertAlmostEqual(lat, tup[1], 9)
94+
self.assertAlmostEqual(lon, tup[0], 4)
95+
self.assertAlmostEqual(lat, tup[1], 4)
9796

9897
def suite():
9998
s = unittest.TestSuite()

django/contrib/gis/utils/geoip.py

Lines changed: 52 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
GeoIP(R) is a registered trademark of MaxMind, LLC of Boston, Massachusetts.
77
88
For IP-based geolocation, this module requires the GeoLite Country and City
9-
datasets, in binary format (CSV will not work!). The datasets may be
9+
datasets, in binary format (CSV will not work!). The datasets may be
1010
downloaded from MaxMind at http://www.maxmind.com/download/geoip/database/.
1111
Grab GeoIP.dat.gz and GeoLiteCity.dat.gz, and unzip them in the directory
1212
corresponding to settings.GEOIP_PATH. See the GeoIP docstring and examples
@@ -34,7 +34,7 @@
3434
>>> g.lat_lon('salon.com')
3535
(37.789798736572266, -122.39420318603516)
3636
>>> g.lon_lat('uh.edu')
37-
(-95.415199279785156, 29.77549934387207)
37+
(-95.415199279785156, 29.77549934387207)
3838
>>> g.geos('24.124.1.80').wkt
3939
'POINT (-95.2087020874023438 39.0392990112304688)'
4040
"""
@@ -45,7 +45,7 @@
4545
if not settings.configured: settings.configure()
4646

4747
# Creating the settings dictionary with any settings, if needed.
48-
GEOIP_SETTINGS = dict((key, getattr(settings, key))
48+
GEOIP_SETTINGS = dict((key, getattr(settings, key))
4949
for key in ('GEOIP_PATH', 'GEOIP_LIBRARY_PATH', 'GEOIP_COUNTRY', 'GEOIP_CITY')
5050
if hasattr(settings, key))
5151
lib_path = GEOIP_SETTINGS.get('GEOIP_LIBRARY_PATH', None)
@@ -83,8 +83,17 @@ class GeoIPRecord(Structure):
8383
('postal_code', c_char_p),
8484
('latitude', c_float),
8585
('longitude', c_float),
86+
# TODO: In 1.4.6 this changed from `int dma_code;` to
87+
# `union {int metro_code; int dma_code;};`. Change
88+
# to a `ctypes.Union` in to accomodate in future when
89+
# pre-1.4.6 versions are no longer distributed.
8690
('dma_code', c_int),
8791
('area_code', c_int),
92+
# TODO: The following structure fields were added in 1.4.3 --
93+
# uncomment these fields when sure previous versions are no
94+
# longer distributed by package maintainers.
95+
#('charset', c_int),
96+
#('continent_code', c_char_p),
8897
]
8998
class GeoIPTag(Structure): pass
9099

@@ -99,9 +108,12 @@ def record_output(func):
99108
rec_by_addr = record_output(lgeoip.GeoIP_record_by_addr)
100109
rec_by_name = record_output(lgeoip.GeoIP_record_by_name)
101110

102-
# For opening up GeoIP databases.
111+
# For opening & closing GeoIP database files.
103112
geoip_open = lgeoip.GeoIP_open
104113
geoip_open.restype = DBTYPE
114+
geoip_close = lgeoip.GeoIP_delete
115+
geoip_close.argtypes = [DBTYPE]
116+
geoip_close.restype = None
105117

106118
# String output routines.
107119
def string_output(func):
@@ -136,6 +148,12 @@ class GeoIP(object):
136148
GEOIP_CHECK_CACHE = 2
137149
GEOIP_INDEX_CACHE = 4
138150
cache_options = dict((opt, None) for opt in (0, 1, 2, 4))
151+
_city_file = ''
152+
_country_file = ''
153+
154+
# Initially, pointers to GeoIP file references are NULL.
155+
_city = None
156+
_country = None
139157

140158
def __init__(self, path=None, cache=0, country=None, city=None):
141159
"""
@@ -174,43 +192,42 @@ def __init__(self, path=None, cache=0, country=None, city=None):
174192
if not isinstance(path, basestring):
175193
raise TypeError('Invalid path type: %s' % type(path).__name__)
176194

177-
cntry_ptr, city_ptr = (None, None)
178195
if os.path.isdir(path):
179-
# Getting the country and city files using the settings
180-
# dictionary. If no settings are provided, default names
181-
# are assigned.
182-
country = os.path.join(path, country or GEOIP_SETTINGS.get('GEOIP_COUNTRY', 'GeoIP.dat'))
183-
city = os.path.join(path, city or GEOIP_SETTINGS.get('GEOIP_CITY', 'GeoLiteCity.dat'))
196+
# Constructing the GeoIP database filenames using the settings
197+
# dictionary. If the database files for the GeoLite country
198+
# and/or city datasets exist, then try and open them.
199+
country_db = os.path.join(path, country or GEOIP_SETTINGS.get('GEOIP_COUNTRY', 'GeoIP.dat'))
200+
if os.path.isfile(country_db):
201+
self._country = geoip_open(country_db, cache)
202+
self._country_file = country_db
203+
204+
city_db = os.path.join(path, city or GEOIP_SETTINGS.get('GEOIP_CITY', 'GeoLiteCity.dat'))
205+
if os.path.isfile(city_db):
206+
self._city = geoip_open(city_db, cache)
207+
self._city_file = city_db
184208
elif os.path.isfile(path):
185209
# Otherwise, some detective work will be needed to figure
186210
# out whether the given database path is for the GeoIP country
187211
# or city databases.
188212
ptr = geoip_open(path, cache)
189213
info = geoip_dbinfo(ptr)
190214
if lite_regex.match(info):
191-
# GeoLite City database.
192-
city, city_ptr = path, ptr
215+
# GeoLite City database detected.
216+
self._city = ptr
217+
self._city_file = path
193218
elif free_regex.match(info):
194-
# GeoIP Country database.
195-
country, cntry_ptr = path, ptr
219+
# GeoIP Country database detected.
220+
self._country = ptr
221+
self._country_file = path
196222
else:
197223
raise GeoIPException('Unable to recognize database edition: %s' % info)
198224
else:
199225
raise GeoIPException('GeoIP path must be a valid file or directory.')
200-
201-
# `_init_db` does the dirty work.
202-
self._init_db(country, cache, '_country', cntry_ptr)
203-
self._init_db(city, cache, '_city', city_ptr)
204-
205-
def _init_db(self, db_file, cache, attname, ptr=None):
206-
"Helper routine for setting GeoIP ctypes database properties."
207-
if ptr:
208-
# Pointer already retrieved.
209-
pass
210-
elif os.path.isfile(db_file or ''):
211-
ptr = geoip_open(db_file, cache)
212-
setattr(self, attname, ptr)
213-
setattr(self, '%s_file' % attname, db_file)
226+
227+
def __del__(self):
228+
# Cleaning any GeoIP file handles lying around.
229+
if self._country: geoip_close(self._country)
230+
if self._city: geoip_close(self._city)
214231

215232
def _check_query(self, query, country=False, city=False, city_or_country=False):
216233
"Helper routine for checking the query and database availability."
@@ -219,11 +236,11 @@ def _check_query(self, query, country=False, city=False, city_or_country=False):
219236
raise TypeError('GeoIP query must be a string, not type %s' % type(query).__name__)
220237

221238
# Extra checks for the existence of country and city databases.
222-
if city_or_country and self._country is None and self._city is None:
239+
if city_or_country and not (self._country or self._city):
223240
raise GeoIPException('Invalid GeoIP country and city data files.')
224-
elif country and self._country is None:
241+
elif country and not self._country:
225242
raise GeoIPException('Invalid GeoIP country data file: %s' % self._country_file)
226-
elif city and self._city is None:
243+
elif city and not self._city:
227244
raise GeoIPException('Invalid GeoIP city data file: %s' % self._city_file)
228245

229246
def city(self, query):
@@ -247,7 +264,7 @@ def city(self, query):
247264
return dict((tup[0], getattr(record, tup[0])) for tup in record._fields_)
248265
else:
249266
return None
250-
267+
251268
def country_code(self, query):
252269
"Returns the country code for the given IP Address or FQDN."
253270
self._check_query(query, city_or_country=True)
@@ -268,12 +285,12 @@ def country_name(self, query):
268285

269286
def country(self, query):
270287
"""
271-
Returns a dictonary with with the country code and name when given an
288+
Returns a dictonary with with the country code and name when given an
272289
IP address or a Fully Qualified Domain Name (FQDN). For example, both
273290
'24.124.1.80' and 'djangoproject.com' are valid parameters.
274291
"""
275292
# Returning the country code and name
276-
return {'country_code' : self.country_code(query),
293+
return {'country_code' : self.country_code(query),
277294
'country_name' : self.country_name(query),
278295
}
279296

@@ -318,7 +335,7 @@ def city_info(self):
318335
ci = geoip_dbinfo(self._city)
319336
return ci
320337
city_info = property(city_info)
321-
338+
322339
def info(self):
323340
"Returns information about all GeoIP databases in use."
324341
return 'Country:\n\t%s\nCity:\n\t%s' % (self.country_info, self.city_info)

django/core/mail.py

Lines changed: 64 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ class EmailMessage(object):
195195
A container for email information.
196196
"""
197197
content_subtype = 'plain'
198-
multipart_subtype = 'mixed'
198+
mixed_subtype = 'mixed'
199199
encoding = None # None => use settings default
200200

201201
def __init__(self, subject='', body='', from_email=None, to=None, bcc=None,
@@ -234,16 +234,7 @@ def message(self):
234234
encoding = self.encoding or settings.DEFAULT_CHARSET
235235
msg = SafeMIMEText(smart_str(self.body, settings.DEFAULT_CHARSET),
236236
self.content_subtype, encoding)
237-
if self.attachments:
238-
body_msg = msg
239-
msg = SafeMIMEMultipart(_subtype=self.multipart_subtype)
240-
if self.body:
241-
msg.attach(body_msg)
242-
for attachment in self.attachments:
243-
if isinstance(attachment, MIMEBase):
244-
msg.attach(attachment)
245-
else:
246-
msg.attach(self._create_attachment(*attachment))
237+
msg = self._create_message(msg)
247238
msg['Subject'] = self.subject
248239
msg['From'] = self.extra_headers.pop('From', self.from_email)
249240
msg['To'] = ', '.join(self.to)
@@ -277,8 +268,7 @@ def send(self, fail_silently=False):
277268
def attach(self, filename=None, content=None, mimetype=None):
278269
"""
279270
Attaches a file with the given filename and content. The filename can
280-
be omitted (useful for multipart/alternative messages) and the mimetype
281-
is guessed, if not provided.
271+
be omitted and the mimetype is guessed, if not provided.
282272
283273
If the first parameter is a MIMEBase subclass it is inserted directly
284274
into the resulting message attachments.
@@ -296,15 +286,26 @@ def attach_file(self, path, mimetype=None):
296286
content = open(path, 'rb').read()
297287
self.attach(filename, content, mimetype)
298288

299-
def _create_attachment(self, filename, content, mimetype=None):
289+
def _create_message(self, msg):
290+
return self._create_attachments(msg)
291+
292+
def _create_attachments(self, msg):
293+
if self.attachments:
294+
body_msg = msg
295+
msg = SafeMIMEMultipart(_subtype=self.mixed_subtype)
296+
if self.body:
297+
msg.attach(body_msg)
298+
for attachment in self.attachments:
299+
if isinstance(attachment, MIMEBase):
300+
msg.attach(attachment)
301+
else:
302+
msg.attach(self._create_attachment(*attachment))
303+
return msg
304+
305+
def _create_mime_attachment(self, content, mimetype):
300306
"""
301-
Converts the filename, content, mimetype triple into a MIME attachment
302-
object.
307+
Converts the content, mimetype pair into a MIME attachment object.
303308
"""
304-
if mimetype is None:
305-
mimetype, _ = mimetypes.guess_type(filename)
306-
if mimetype is None:
307-
mimetype = DEFAULT_ATTACHMENT_MIME_TYPE
308309
basetype, subtype = mimetype.split('/', 1)
309310
if basetype == 'text':
310311
attachment = SafeMIMEText(smart_str(content,
@@ -314,6 +315,18 @@ def _create_attachment(self, filename, content, mimetype=None):
314315
attachment = MIMEBase(basetype, subtype)
315316
attachment.set_payload(content)
316317
Encoders.encode_base64(attachment)
318+
return attachment
319+
320+
def _create_attachment(self, filename, content, mimetype=None):
321+
"""
322+
Converts the filename, content, mimetype triple into a MIME attachment
323+
object.
324+
"""
325+
if mimetype is None:
326+
mimetype, _ = mimetypes.guess_type(filename)
327+
if mimetype is None:
328+
mimetype = DEFAULT_ATTACHMENT_MIME_TYPE
329+
attachment = self._create_mime_attachment(content, mimetype)
317330
if filename:
318331
attachment.add_header('Content-Disposition', 'attachment',
319332
filename=filename)
@@ -325,11 +338,39 @@ class EmailMultiAlternatives(EmailMessage):
325338
messages. For example, including text and HTML versions of the text is
326339
made easier.
327340
"""
328-
multipart_subtype = 'alternative'
341+
alternative_subtype = 'alternative'
329342

330-
def attach_alternative(self, content, mimetype=None):
343+
def __init__(self, subject='', body='', from_email=None, to=None, bcc=None,
344+
connection=None, attachments=None, headers=None, alternatives=None):
345+
"""
346+
Initialize a single email message (which can be sent to multiple
347+
recipients).
348+
349+
All strings used to create the message can be unicode strings (or UTF-8
350+
bytestrings). The SafeMIMEText class will handle any necessary encoding
351+
conversions.
352+
"""
353+
super(EmailMultiAlternatives, self).__init__(subject, body, from_email, to, bcc, connection, attachments, headers)
354+
self.alternatives=alternatives or []
355+
356+
def attach_alternative(self, content, mimetype):
331357
"""Attach an alternative content representation."""
332-
self.attach(content=content, mimetype=mimetype)
358+
assert content is not None
359+
assert mimetype is not None
360+
self.alternatives.append((content, mimetype))
361+
362+
def _create_message(self, msg):
363+
return self._create_attachments(self._create_alternatives(msg))
364+
365+
def _create_alternatives(self, msg):
366+
if self.alternatives:
367+
body_msg = msg
368+
msg = SafeMIMEMultipart(_subtype=self.alternative_subtype)
369+
if self.body:
370+
msg.attach(body_msg)
371+
for alternative in self.alternatives:
372+
msg.attach(self._create_mime_attachment(*alternative))
373+
return msg
333374

334375
def send_mail(subject, message, from_email, recipient_list,
335376
fail_silently=False, auth_user=None, auth_password=None):

django/core/management/commands/dumpdata.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ def handle(self, *app_labels, **options):
7373
model_list = get_models(app)
7474

7575
for model in model_list:
76-
objects.extend(model.objects.all())
76+
objects.extend(model._default_manager.all())
7777

7878
try:
7979
return serializers.serialize(format, objects, indent=indent)

0 commit comments

Comments
 (0)