1
0
mirror of https://github.com/django/django.git synced 2025-07-04 17:59:13 +00:00

[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
This commit is contained in:
Zain Memon 2009-06-15 04:34:41 +00:00
parent 59e26c75f7
commit fcf957d599
25 changed files with 578 additions and 128 deletions

View File

@ -8,5 +8,5 @@
{% endif %}
{{ cl.result_count }} {% ifequal cl.result_count 1 %}{{ cl.opts.verbose_name }}{% else %}{{ cl.opts.verbose_name_plural }}{% endifequal %}
{% if show_all_url %}&nbsp;&nbsp;<a href="{{ show_all_url }}" class="showall">{% trans 'Show all' %}</a>{% endif %}
{% if cl.formset and cl.result_count %}<input type="submit" name="_save" class="default" value="Save"/>{% endif %}
{% if cl.formset and cl.result_count %}<input type="submit" name="_save" class="default" value="{% trans 'Save' %}"/>{% endif %}
</p>

View File

@ -317,7 +317,7 @@ class BaseGenericInlineFormSet(BaseModelFormSet):
def get_queryset(self):
# Avoid a circular import.
from django.contrib.contenttypes.models import ContentType
if self.instance is None:
if self.instance is None or self.instance.pk is None:
return self.model._default_manager.none()
return self.model._default_manager.filter(**{
self.ct_field.name: ContentType.objects.get_for_model(self.instance),

View File

@ -14,7 +14,7 @@ if lib_path:
lib_names = None
elif os.name == 'nt':
# Windows NT shared library
lib_names = ['gdal15']
lib_names = ['gdal16', 'gdal15']
elif os.name == 'posix':
# *NIX library names.
lib_names = ['gdal', 'GDAL', 'gdal1.6.0', 'gdal1.5.0', 'gdal1.4.0']

View File

@ -84,16 +84,15 @@ class GeoIPTest(unittest.TestCase):
self.assertEqual('USA', d['country_code3'])
self.assertEqual('Houston', d['city'])
self.assertEqual('TX', d['region'])
self.assertEqual('77002', d['postal_code'])
self.assertEqual(713, d['area_code'])
geom = g.geos(query)
self.failIf(not isinstance(geom, GEOSGeometry))
lon, lat = (-95.366996765, 29.752300262)
lon, lat = (-95.4152, 29.7755)
lat_lon = g.lat_lon(query)
lat_lon = (lat_lon[1], lat_lon[0])
for tup in (geom.tuple, g.coords(query), g.lon_lat(query), lat_lon):
self.assertAlmostEqual(lon, tup[0], 9)
self.assertAlmostEqual(lat, tup[1], 9)
self.assertAlmostEqual(lon, tup[0], 4)
self.assertAlmostEqual(lat, tup[1], 4)
def suite():
s = unittest.TestSuite()

View File

@ -83,8 +83,17 @@ class GeoIPRecord(Structure):
('postal_code', c_char_p),
('latitude', c_float),
('longitude', c_float),
# TODO: In 1.4.6 this changed from `int dma_code;` to
# `union {int metro_code; int dma_code;};`. Change
# to a `ctypes.Union` in to accomodate in future when
# pre-1.4.6 versions are no longer distributed.
('dma_code', c_int),
('area_code', c_int),
# TODO: The following structure fields were added in 1.4.3 --
# uncomment these fields when sure previous versions are no
# longer distributed by package maintainers.
#('charset', c_int),
#('continent_code', c_char_p),
]
class GeoIPTag(Structure): pass
@ -99,9 +108,12 @@ def record_output(func):
rec_by_addr = record_output(lgeoip.GeoIP_record_by_addr)
rec_by_name = record_output(lgeoip.GeoIP_record_by_name)
# For opening up GeoIP databases.
# For opening & closing GeoIP database files.
geoip_open = lgeoip.GeoIP_open
geoip_open.restype = DBTYPE
geoip_close = lgeoip.GeoIP_delete
geoip_close.argtypes = [DBTYPE]
geoip_close.restype = None
# String output routines.
def string_output(func):
@ -136,6 +148,12 @@ class GeoIP(object):
GEOIP_CHECK_CACHE = 2
GEOIP_INDEX_CACHE = 4
cache_options = dict((opt, None) for opt in (0, 1, 2, 4))
_city_file = ''
_country_file = ''
# Initially, pointers to GeoIP file references are NULL.
_city = None
_country = None
def __init__(self, path=None, cache=0, country=None, city=None):
"""
@ -174,13 +192,19 @@ class GeoIP(object):
if not isinstance(path, basestring):
raise TypeError('Invalid path type: %s' % type(path).__name__)
cntry_ptr, city_ptr = (None, None)
if os.path.isdir(path):
# Getting the country and city files using the settings
# dictionary. If no settings are provided, default names
# are assigned.
country = os.path.join(path, country or GEOIP_SETTINGS.get('GEOIP_COUNTRY', 'GeoIP.dat'))
city = os.path.join(path, city or GEOIP_SETTINGS.get('GEOIP_CITY', 'GeoLiteCity.dat'))
# Constructing the GeoIP database filenames using the settings
# dictionary. If the database files for the GeoLite country
# and/or city datasets exist, then try and open them.
country_db = os.path.join(path, country or GEOIP_SETTINGS.get('GEOIP_COUNTRY', 'GeoIP.dat'))
if os.path.isfile(country_db):
self._country = geoip_open(country_db, cache)
self._country_file = country_db
city_db = os.path.join(path, city or GEOIP_SETTINGS.get('GEOIP_CITY', 'GeoLiteCity.dat'))
if os.path.isfile(city_db):
self._city = geoip_open(city_db, cache)
self._city_file = city_db
elif os.path.isfile(path):
# Otherwise, some detective work will be needed to figure
# out whether the given database path is for the GeoIP country
@ -188,29 +212,22 @@ class GeoIP(object):
ptr = geoip_open(path, cache)
info = geoip_dbinfo(ptr)
if lite_regex.match(info):
# GeoLite City database.
city, city_ptr = path, ptr
# GeoLite City database detected.
self._city = ptr
self._city_file = path
elif free_regex.match(info):
# GeoIP Country database.
country, cntry_ptr = path, ptr
# GeoIP Country database detected.
self._country = ptr
self._country_file = path
else:
raise GeoIPException('Unable to recognize database edition: %s' % info)
else:
raise GeoIPException('GeoIP path must be a valid file or directory.')
# `_init_db` does the dirty work.
self._init_db(country, cache, '_country', cntry_ptr)
self._init_db(city, cache, '_city', city_ptr)
def _init_db(self, db_file, cache, attname, ptr=None):
"Helper routine for setting GeoIP ctypes database properties."
if ptr:
# Pointer already retrieved.
pass
elif os.path.isfile(db_file or ''):
ptr = geoip_open(db_file, cache)
setattr(self, attname, ptr)
setattr(self, '%s_file' % attname, db_file)
def __del__(self):
# Cleaning any GeoIP file handles lying around.
if self._country: geoip_close(self._country)
if self._city: geoip_close(self._city)
def _check_query(self, query, country=False, city=False, city_or_country=False):
"Helper routine for checking the query and database availability."
@ -219,11 +236,11 @@ class GeoIP(object):
raise TypeError('GeoIP query must be a string, not type %s' % type(query).__name__)
# Extra checks for the existence of country and city databases.
if city_or_country and self._country is None and self._city is None:
if city_or_country and not (self._country or self._city):
raise GeoIPException('Invalid GeoIP country and city data files.')
elif country and self._country is None:
elif country and not self._country:
raise GeoIPException('Invalid GeoIP country data file: %s' % self._country_file)
elif city and self._city is None:
elif city and not self._city:
raise GeoIPException('Invalid GeoIP city data file: %s' % self._city_file)
def city(self, query):

View File

@ -195,7 +195,7 @@ class EmailMessage(object):
A container for email information.
"""
content_subtype = 'plain'
multipart_subtype = 'mixed'
mixed_subtype = 'mixed'
encoding = None # None => use settings default
def __init__(self, subject='', body='', from_email=None, to=None, bcc=None,
@ -234,16 +234,7 @@ class EmailMessage(object):
encoding = self.encoding or settings.DEFAULT_CHARSET
msg = SafeMIMEText(smart_str(self.body, settings.DEFAULT_CHARSET),
self.content_subtype, encoding)
if self.attachments:
body_msg = msg
msg = SafeMIMEMultipart(_subtype=self.multipart_subtype)
if self.body:
msg.attach(body_msg)
for attachment in self.attachments:
if isinstance(attachment, MIMEBase):
msg.attach(attachment)
else:
msg.attach(self._create_attachment(*attachment))
msg = self._create_message(msg)
msg['Subject'] = self.subject
msg['From'] = self.extra_headers.pop('From', self.from_email)
msg['To'] = ', '.join(self.to)
@ -277,8 +268,7 @@ class EmailMessage(object):
def attach(self, filename=None, content=None, mimetype=None):
"""
Attaches a file with the given filename and content. The filename can
be omitted (useful for multipart/alternative messages) and the mimetype
is guessed, if not provided.
be omitted and the mimetype is guessed, if not provided.
If the first parameter is a MIMEBase subclass it is inserted directly
into the resulting message attachments.
@ -296,15 +286,26 @@ class EmailMessage(object):
content = open(path, 'rb').read()
self.attach(filename, content, mimetype)
def _create_attachment(self, filename, content, mimetype=None):
def _create_message(self, msg):
return self._create_attachments(msg)
def _create_attachments(self, msg):
if self.attachments:
body_msg = msg
msg = SafeMIMEMultipart(_subtype=self.mixed_subtype)
if self.body:
msg.attach(body_msg)
for attachment in self.attachments:
if isinstance(attachment, MIMEBase):
msg.attach(attachment)
else:
msg.attach(self._create_attachment(*attachment))
return msg
def _create_mime_attachment(self, content, mimetype):
"""
Converts the filename, content, mimetype triple into a MIME attachment
object.
Converts the content, mimetype pair into a MIME attachment object.
"""
if mimetype is None:
mimetype, _ = mimetypes.guess_type(filename)
if mimetype is None:
mimetype = DEFAULT_ATTACHMENT_MIME_TYPE
basetype, subtype = mimetype.split('/', 1)
if basetype == 'text':
attachment = SafeMIMEText(smart_str(content,
@ -314,6 +315,18 @@ class EmailMessage(object):
attachment = MIMEBase(basetype, subtype)
attachment.set_payload(content)
Encoders.encode_base64(attachment)
return attachment
def _create_attachment(self, filename, content, mimetype=None):
"""
Converts the filename, content, mimetype triple into a MIME attachment
object.
"""
if mimetype is None:
mimetype, _ = mimetypes.guess_type(filename)
if mimetype is None:
mimetype = DEFAULT_ATTACHMENT_MIME_TYPE
attachment = self._create_mime_attachment(content, mimetype)
if filename:
attachment.add_header('Content-Disposition', 'attachment',
filename=filename)
@ -325,11 +338,39 @@ class EmailMultiAlternatives(EmailMessage):
messages. For example, including text and HTML versions of the text is
made easier.
"""
multipart_subtype = 'alternative'
alternative_subtype = 'alternative'
def attach_alternative(self, content, mimetype=None):
def __init__(self, subject='', body='', from_email=None, to=None, bcc=None,
connection=None, attachments=None, headers=None, alternatives=None):
"""
Initialize a single email message (which can be sent to multiple
recipients).
All strings used to create the message can be unicode strings (or UTF-8
bytestrings). The SafeMIMEText class will handle any necessary encoding
conversions.
"""
super(EmailMultiAlternatives, self).__init__(subject, body, from_email, to, bcc, connection, attachments, headers)
self.alternatives=alternatives or []
def attach_alternative(self, content, mimetype):
"""Attach an alternative content representation."""
self.attach(content=content, mimetype=mimetype)
assert content is not None
assert mimetype is not None
self.alternatives.append((content, mimetype))
def _create_message(self, msg):
return self._create_attachments(self._create_alternatives(msg))
def _create_alternatives(self, msg):
if self.alternatives:
body_msg = msg
msg = SafeMIMEMultipart(_subtype=self.alternative_subtype)
if self.body:
msg.attach(body_msg)
for alternative in self.alternatives:
msg.attach(self._create_mime_attachment(*alternative))
return msg
def send_mail(subject, message, from_email, recipient_list,
fail_silently=False, auth_user=None, auth_password=None):

View File

@ -73,7 +73,7 @@ class Command(BaseCommand):
model_list = get_models(app)
for model in model_list:
objects.extend(model.objects.all())
objects.extend(model._default_manager.all())
try:
return serializers.serialize(format, objects, indent=indent)

View File

@ -25,6 +25,13 @@ class BaseDatabaseCreation(object):
def __init__(self, connection):
self.connection = connection
def _digest(self, *args):
"""
Generates a 32-bit digest of a set of arguments that can be used to
shorten identifying names.
"""
return '%x' % (abs(hash(args)) % 4294967296L) # 2**32
def sql_create_model(self, model, style, known_models=set()):
"""
Returns the SQL required to create a single model, as a tuple of:
@ -128,7 +135,7 @@ class BaseDatabaseCreation(object):
col = opts.get_field(f.rel.field_name).column
# For MySQL, r_name must be unique in the first 64 characters.
# So we are careful with character usage here.
r_name = '%s_refs_%s_%x' % (r_col, col, abs(hash((r_table, table))))
r_name = '%s_refs_%s_%s' % (r_col, col, self._digest(r_table, table))
final_output.append(style.SQL_KEYWORD('ALTER TABLE') + ' %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s)%s;' % \
(qn(r_table), qn(truncate_name(r_name, self.connection.ops.max_name_length())),
qn(r_col), qn(table), qn(col),
@ -187,8 +194,7 @@ class BaseDatabaseCreation(object):
output.append('\n'.join(table_output))
for r_table, r_col, table, col in deferred:
r_name = '%s_refs_%s_%x' % (r_col, col,
abs(hash((r_table, table))))
r_name = '%s_refs_%s_%s' % (r_col, col, self._digest(r_table, table))
output.append(style.SQL_KEYWORD('ALTER TABLE') + ' %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s)%s;' %
(qn(r_table),
qn(truncate_name(r_name, self.connection.ops.max_name_length())),
@ -289,7 +295,7 @@ class BaseDatabaseCreation(object):
col = f.column
r_table = model._meta.db_table
r_col = model._meta.get_field(f.rel.field_name).column
r_name = '%s_refs_%s_%x' % (col, r_col, abs(hash((table, r_table))))
r_name = '%s_refs_%s_%s' % (col, r_col, self._digest(table, r_table))
output.append('%s %s %s %s;' % \
(style.SQL_KEYWORD('ALTER TABLE'),
style.SQL_TABLE(qn(table)),

View File

@ -411,29 +411,37 @@ class Model(object):
save.alters_data = True
def save_base(self, raw=False, cls=None, force_insert=False,
force_update=False):
def save_base(self, raw=False, cls=None, origin=None,
force_insert=False, force_update=False):
"""
Does the heavy-lifting involved in saving. Subclasses shouldn't need to
override this method. It's separate from save() in order to hide the
need for overrides of save() to pass around internal-only parameters
('raw' and 'cls').
('raw', 'cls', and 'origin').
"""
assert not (force_insert and force_update)
if not cls:
if cls is None:
cls = self.__class__
meta = self._meta
signal = True
signals.pre_save.send(sender=self.__class__, instance=self, raw=raw)
meta = cls._meta
if not meta.proxy:
origin = cls
else:
meta = cls._meta
signal = False
if origin:
signals.pre_save.send(sender=origin, instance=self, raw=raw)
# If we are in a raw save, save the object exactly as presented.
# That means that we don't try to be smart about saving attributes
# that might have come from the parent class - we just save the
# attributes we have been given to the class we have been given.
if not raw:
# We also go through this process to defer the save of proxy objects
# to their actual underlying model.
if not raw or meta.proxy:
if meta.proxy:
org = cls
else:
org = None
for parent, field in meta.parents.items():
# At this point, parent's primary key field may be unknown
# (for example, from administration form which doesn't fill
@ -441,7 +449,8 @@ class Model(object):
if field and getattr(self, parent._meta.pk.attname) is None and getattr(self, field.attname) is not None:
setattr(self, parent._meta.pk.attname, getattr(self, field.attname))
self.save_base(cls=parent)
self.save_base(cls=parent, origin=org)
if field:
setattr(self, field.attname, self._get_pk_val(parent._meta))
if meta.proxy:
@ -492,8 +501,8 @@ class Model(object):
setattr(self, meta.pk.attname, result)
transaction.commit_unless_managed()
if signal:
signals.post_save.send(sender=self.__class__, instance=self,
if origin:
signals.post_save.send(sender=origin, instance=self,
created=(not record_exists), raw=raw)
save_base.alters_data = True

View File

@ -132,7 +132,8 @@ class RelatedField(object):
v, field = getattr(v, v._meta.pk.name), v._meta.pk
except AttributeError:
pass
if field:
if not field:
field = self.rel.get_related_field()
if lookup_type in ('range', 'in'):
v = [v]
v = field.get_db_prep_lookup(lookup_type, v)
@ -958,4 +959,3 @@ class ManyToManyField(RelatedField, Field):
# A ManyToManyField is not represented by a single column,
# so return None.
return None

View File

@ -7,6 +7,8 @@ try:
except NameError:
from sets import Set as set # Python 2.3 fallback
from copy import deepcopy
from django.db import connection, transaction, IntegrityError
from django.db.models.aggregates import Aggregate
from django.db.models.fields import DateField
@ -40,6 +42,17 @@ class QuerySet(object):
# PYTHON MAGIC METHODS #
########################
def __deepcopy__(self, memo):
"""
Deep copy of a QuerySet doesn't populate the cache
"""
obj_dict = deepcopy(self.__dict__, memo)
obj_dict['_iter'] = None
obj = self.__class__()
obj.__dict__.update(obj_dict)
return obj
def __getstate__(self):
"""
Allows the QuerySet to be pickled.
@ -190,7 +203,25 @@ class QuerySet(object):
index_start = len(extra_select)
aggregate_start = index_start + len(self.model._meta.fields)
load_fields = only_load.get(self.model)
load_fields = []
# If only/defer clauses have been specified,
# build the list of fields that are to be loaded.
if only_load:
for field, model in self.model._meta.get_fields_with_model():
if model is None:
model = self.model
if field == self.model._meta.pk:
# Record the index of the primary key when it is found
pk_idx = len(load_fields)
try:
if field.name in only_load[model]:
# Add a field that has been explicitly included
load_fields.append(field.name)
except KeyError:
# Model wasn't explicitly listed in the only_load table
# Therefore, we need to load all fields from this model
load_fields.append(field.name)
skip = None
if load_fields and not fill_cache:
# Some fields have been deferred, so we have to initialise

View File

@ -635,10 +635,10 @@ class BaseQuery(object):
# models.
workset = {}
for model, values in seen.iteritems():
for field, f_model in model._meta.get_fields_with_model():
for field in model._meta.local_fields:
if field in values:
continue
add_to_dict(workset, f_model or model, field)
add_to_dict(workset, model, field)
for model, values in must_include.iteritems():
# If we haven't included a model in workset, we don't add the
# corresponding must_include fields for that model, since an
@ -657,6 +657,12 @@ class BaseQuery(object):
# included any fields, we have to make sure it's mentioned
# so that only the "must include" fields are pulled in.
seen[model] = values
# Now ensure that every model in the inheritance chain is mentioned
# in the parent list. Again, it must be mentioned to ensure that
# only "must include" fields are pulled in.
for model in orig_opts.get_parent_list():
if model not in seen:
seen[model] = set()
for model, values in seen.iteritems():
callback(target, model, values)
@ -1619,10 +1625,14 @@ class BaseQuery(object):
entry.negate()
self.where.add(entry, AND)
break
elif not (lookup_type == 'in' and not value) and field.null:
elif not (lookup_type == 'in'
and not hasattr(value, 'as_sql')
and not hasattr(value, '_as_sql')
and not value) and field.null:
# Leaky abstraction artifact: We have to specifically
# exclude the "foo__in=[]" case from this handling, because
# it's short-circuited in the Where class.
# We also need to handle the case where a subquery is provided
entry = self.where_class()
entry.add((Constraint(alias, col, None), 'isnull', True), AND)
entry.negate()

View File

@ -20,7 +20,7 @@ tutorial, so that the template contains an HTML ``<form>`` element:
{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}
<form action="vote/" method="post">
<form action="/polls/{{ poll.id }}/vote/" method="post">
{% for choice in poll.choice_set.all %}
<input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}" />
<label for="choice{{ forloop.counter }}">{{ choice.choice }}</label><br />
@ -36,12 +36,12 @@ A quick rundown:
selects one of the radio buttons and submits the form, it'll send the
POST data ``choice=3``. This is HTML Forms 101.
* We set the form's ``action`` to ``vote/``, and we set ``method="post"``.
Using ``method="post"`` (as opposed to ``method="get"``) is very
important, because the act of submitting this form will alter data
server-side. Whenever you create a form that alters data server-side, use
``method="post"``. This tip isn't specific to Django; it's just good Web
development practice.
* We set the form's ``action`` to ``/polls/{{ poll.id }}/vote/``, and we
set ``method="post"``. Using ``method="post"`` (as opposed to
``method="get"``) is very important, because the act of submitting this
form will alter data server-side. Whenever you create a form that alters
data server-side, use ``method="post"``. This tip isn't specific to
Django; it's just good Web development practice.
* ``forloop.counter`` indicates how many times the :ttag:`for` tag has gone
through its loop

View File

@ -43,8 +43,8 @@ modify the filename as necessary to get a unique name. The actual name of the
stored file will be returned.
The ``content`` argument must be an instance of
:class:`django.db.files.File` or of a subclass of
:class:`~django.db.files.File`.
:class:`django.core.files.File` or of a subclass of
:class:`~django.core.files.File`.
``Storage.delete(name)``
~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -800,21 +800,22 @@ you can use the name of the model, rather than the model object itself::
class Manufacturer(models.Model):
# ...
Note, however, that this only refers to models in the same ``models.py`` file --
you cannot use a string to reference a model defined in another application or
imported from elsewhere.
.. versionadded:: 1.0
.. versionchanged:: 1.0
Refering models in other applications must include the application label.
To refer to models defined in another
application, you must instead explicitly specify the application label. For
example, if the ``Manufacturer`` model above is defined in another application
called ``production``, you'd need to use::
To refer to models defined in another application, you can explicitly specify
a model with the full application label. For example, if the ``Manufacturer``
model above is defined in another application called ``production``, you'd
need to use::
class Car(models.Model):
manufacturer = models.ForeignKey('production.Manufacturer')
This sort of reference can be useful when resolving circular import
dependencies between two applications.
Database Representation
~~~~~~~~~~~~~~~~~~~~~~~
Behind the scenes, Django appends ``"_id"`` to the field name to create its
database column name. In the above example, the database table for the ``Car``
model will have a ``manufacturer_id`` column. (You can change this explicitly by
@ -824,6 +825,9 @@ deal with the field names of your model object.
.. _foreign-key-arguments:
Arguments
~~~~~~~~~
:class:`ForeignKey` accepts an extra set of arguments -- all optional -- that
define the details of how the relation works.
@ -871,6 +875,9 @@ the model is related. This works exactly the same as it does for
:class:`ForeignKey`, including all the options regarding :ref:`recursive
<recursive-relationships>` and :ref:`lazy <lazy-relationships>` relationships.
Database Representation
~~~~~~~~~~~~~~~~~~~~~~~
Behind the scenes, Django creates an intermediary join table to represent the
many-to-many relationship. By default, this table name is generated using the
names of the two tables being joined. Since some databases don't support table
@ -882,6 +889,9 @@ You can manually provide the name of the join table using the
.. _manytomany-arguments:
Arguments
~~~~~~~~~
:class:`ManyToManyField` accepts an extra set of arguments -- all optional --
that control how the relationship functions.

View File

@ -323,16 +323,19 @@ Since the Author model has only 3 fields, 'name', 'title', and
to be empty, and does not provide a default value for the missing fields,
any attempt to ``save()`` a ``ModelForm`` with missing fields will fail.
To avoid this failure, you must instantiate your model with initial values
for the missing, but required fields, or use ``save(commit=False)`` and
manually set any extra required fields::
for the missing, but required fields::
instance = Instance(required_field='value')
form = InstanceForm(request.POST, instance=instance)
new_instance = form.save()
author = Author(title='Mr')
form = PartialAuthorForm(request.POST, instance=author)
form.save()
instance = form.save(commit=False)
instance.required_field = 'new value'
new_instance = instance.save()
Alternatively, you can use ``save(commit=False)`` and manually set
any extra required fields::
form = PartialAuthorForm(request.POST)
author = form.save(commit=False)
author.title = 'Mr'
author.save()
See the `section on saving forms`_ for more details on using
``save(commit=False)``.

View File

@ -0,0 +1,54 @@
import random
import string
from django.db import models
class MyWrapper(object):
def __init__(self, value):
self.value = value
def __repr__(self):
return "<%s: %s>" % (self.__class__.__name__, self.value)
def __unicode__(self):
return self.value
def __eq__(self, other):
if isinstance(other, self.__class__):
return self.value == other.value
return self.value == other
class MyAutoField(models.CharField):
__metaclass__ = models.SubfieldBase
def __init__(self, *args, **kwargs):
kwargs['max_length'] = 10
super(MyAutoField, self).__init__(*args, **kwargs)
def pre_save(self, instance, add):
value = getattr(instance, self.attname, None)
if not value:
value = MyWrapper(''.join(random.sample(string.lowercase, 10)))
setattr(instance, self.attname, value)
return value
def to_python(self, value):
if not value:
return
if not isinstance(value, MyWrapper):
value = MyWrapper(value)
return value
def get_db_prep_save(self, value):
if not value:
return
if isinstance(value, MyWrapper):
return unicode(value)
return value
def get_db_prep_value(self, value):
if not value:
return
if isinstance(value, MyWrapper):
return unicode(value)
return value

View File

@ -9,6 +9,8 @@ this behavior by explicitly adding ``primary_key=True`` to a field.
from django.conf import settings
from django.db import models, transaction, IntegrityError
from fields import MyAutoField
class Employee(models.Model):
employee_code = models.IntegerField(primary_key=True, db_column = 'code')
first_name = models.CharField(max_length=20)
@ -28,6 +30,16 @@ class Business(models.Model):
def __unicode__(self):
return self.name
class Bar(models.Model):
id = MyAutoField(primary_key=True, db_index=True)
def __unicode__(self):
return repr(self.pk)
class Foo(models.Model):
bar = models.ForeignKey(Bar)
__test__ = {'API_TESTS':"""
>>> dan = Employee(employee_code=123, first_name='Dan', last_name='Jones')
>>> dan.save()
@ -121,6 +133,21 @@ DoesNotExist: Employee matching query does not exist.
... print "Fail with %s" % type(e)
Pass
# Regression for #10785 -- Custom fields can be used for primary keys.
>>> new_bar = Bar.objects.create()
>>> new_foo = Foo.objects.create(bar=new_bar)
>>> f = Foo.objects.get(bar=new_bar.pk)
>>> f == new_foo
True
>>> f.bar == new_bar
True
>>> f = Foo.objects.get(bar=new_bar)
>>> f == new_foo
True
>>> f.bar == new_bar
True
"""}
# SQLite lets objects be saved with an empty primary key, even though an

View File

@ -17,6 +17,12 @@ class Primary(models.Model):
def __unicode__(self):
return self.name
class Child(Primary):
pass
class BigChild(Primary):
other = models.CharField(max_length=50)
def count_delayed_fields(obj, debug=False):
"""
Returns the number of delayed attributes on the given model instance.
@ -33,7 +39,7 @@ def count_delayed_fields(obj, debug=False):
__test__ = {"API_TEST": """
To all outward appearances, instances with deferred fields look the same as
normal instances when we examine attribut values. Therefore we test for the
normal instances when we examine attribute values. Therefore we test for the
number of deferred fields on returned instances (by poking at the internals),
as a way to observe what is going on.
@ -98,5 +104,89 @@ Using defer() and only() with get() is also valid.
>>> Primary.objects.all()
[<Primary: a new name>]
# Regression for #10572 - A subclass with no extra fields can defer fields from the base class
>>> _ = Child.objects.create(name="c1", value="foo", related=s1)
# You can defer a field on a baseclass when the subclass has no fields
>>> obj = Child.objects.defer("value").get(name="c1")
>>> count_delayed_fields(obj)
1
>>> obj.name
u"c1"
>>> obj.value
u"foo"
>>> obj.name = "c2"
>>> obj.save()
# You can retrive a single column on a base class with no fields
>>> obj = Child.objects.only("name").get(name="c2")
>>> count_delayed_fields(obj)
3
>>> obj.name
u"c2"
>>> obj.value
u"foo"
>>> obj.name = "cc"
>>> obj.save()
>>> _ = BigChild.objects.create(name="b1", value="foo", related=s1, other="bar")
# You can defer a field on a baseclass
>>> obj = BigChild.objects.defer("value").get(name="b1")
>>> count_delayed_fields(obj)
1
>>> obj.name
u"b1"
>>> obj.value
u"foo"
>>> obj.other
u"bar"
>>> obj.name = "b2"
>>> obj.save()
# You can defer a field on a subclass
>>> obj = BigChild.objects.defer("other").get(name="b2")
>>> count_delayed_fields(obj)
1
>>> obj.name
u"b2"
>>> obj.value
u"foo"
>>> obj.other
u"bar"
>>> obj.name = "b3"
>>> obj.save()
# You can retrieve a single field on a baseclass
>>> obj = BigChild.objects.only("name").get(name="b3")
>>> count_delayed_fields(obj)
4
>>> obj.name
u"b3"
>>> obj.value
u"foo"
>>> obj.other
u"bar"
>>> obj.name = "b4"
>>> obj.save()
# You can retrieve a single field on a baseclass
>>> obj = BigChild.objects.only("other").get(name="b4")
>>> count_delayed_fields(obj)
4
>>> obj.name
u"b4"
>>> obj.value
u"foo"
>>> obj.other
u"bar"
>>> obj.name = "bb"
>>> obj.save()
# Finally, we need to flush the app cache for the defer module.
# Using only/defer creates some artifical entries in the app cache
# that messes up later tests. Purge all entries, just to be sure.
>>> from django.db.models.loading import cache
>>> cache.app_models['defer'] = {}
"""}

View File

@ -0,0 +1,9 @@
[
{
"pk": 100,
"model": "proxy_models.myperson",
"fields": {
"name": "Elvis Presley"
}
}
]

View File

@ -259,6 +259,40 @@ FieldError: Proxy model 'NoNewFields' contains model fields.
>>> OtherPerson._default_manager.all()
[<OtherPerson: barney>, <OtherPerson: wilma>]
# Test save signals for proxy models
>>> from django.db.models import signals
>>> def make_handler(model, event):
... def _handler(*args, **kwargs):
... print u"%s %s save" % (model, event)
... return _handler
>>> h1 = make_handler('MyPerson', 'pre')
>>> h2 = make_handler('MyPerson', 'post')
>>> h3 = make_handler('Person', 'pre')
>>> h4 = make_handler('Person', 'post')
>>> signals.pre_save.connect(h1, sender=MyPerson)
>>> signals.post_save.connect(h2, sender=MyPerson)
>>> signals.pre_save.connect(h3, sender=Person)
>>> signals.post_save.connect(h4, sender=Person)
>>> dino = MyPerson.objects.create(name=u"dino")
MyPerson pre save
MyPerson post save
# Test save signals for proxy proxy models
>>> h5 = make_handler('MyPersonProxy', 'pre')
>>> h6 = make_handler('MyPersonProxy', 'post')
>>> signals.pre_save.connect(h5, sender=MyPersonProxy)
>>> signals.post_save.connect(h6, sender=MyPersonProxy)
>>> dino = MyPersonProxy.objects.create(name=u"pebbles")
MyPersonProxy pre save
MyPersonProxy post save
>>> signals.pre_save.disconnect(h1, sender=MyPerson)
>>> signals.post_save.disconnect(h2, sender=MyPerson)
>>> signals.pre_save.disconnect(h3, sender=Person)
>>> signals.post_save.disconnect(h4, sender=Person)
>>> signals.pre_save.disconnect(h5, sender=MyPersonProxy)
>>> signals.post_save.disconnect(h6, sender=MyPersonProxy)
# A proxy has the same content type as the model it is proxying for (at the
# storage level, it is meant to be essentially indistinguishable).
>>> ctype = ContentType.objects.get_for_model
@ -266,7 +300,7 @@ FieldError: Proxy model 'NoNewFields' contains model fields.
True
>>> MyPersonProxy.objects.all()
[<MyPersonProxy: barney>, <MyPersonProxy: fred>]
[<MyPersonProxy: barney>, <MyPersonProxy: dino>, <MyPersonProxy: fred>, <MyPersonProxy: pebbles>]
>>> u = User.objects.create(name='Bruce')
>>> User.objects.all()
@ -327,4 +361,11 @@ True
# Select related + filter on a related proxy of proxy field
>>> ProxyImprovement.objects.select_related().get(associated_bug__summary__icontains='fix')
<ProxyImprovement: ProxyImprovement:improve that>
Proxy models can be loaded from fixtures (Regression for #11194)
>>> from django.core import management
>>> management.call_command('loaddata', 'mypeople.json', verbosity=0)
>>> MyPerson.objects.get(pk=100)
<MyPerson: Elvis Presley>
"""}

View File

@ -84,7 +84,8 @@ Some further checks for select_related() and inherited model behaviour
(regression for #10710).
>>> c1 = Child.objects.create(name="c1", value=42)
>>> obj = Leaf.objects.create(name="l1", child=c1)
>>> c2 = Child.objects.create(name="c2", value=37)
>>> obj = Leaf.objects.create(name="l1", child=c1, second_child=c2)
>>> obj = Leaf.objects.only("name", "child").select_related()[0]
>>> obj.child.name
@ -101,5 +102,24 @@ types as their non-deferred versions (bug #10738).
>>> c1 is c2 is c3
True
# Regression for #10733 - only() can be used on a model with two foreign keys.
>>> results = Leaf.objects.all().only('name', 'child', 'second_child').select_related()
>>> results[0].child.name
u'c1'
>>> results[0].second_child.name
u'c2'
>>> results = Leaf.objects.all().only('name', 'child', 'second_child', 'child__name', 'second_child__name').select_related()
>>> results[0].child.name
u'c1'
>>> results[0].second_child.name
u'c2'
# Finally, we need to flush the app cache for the defer module.
# Using only/defer creates some artifical entries in the app cache
# that messes up later tests. Purge all entries, just to be sure.
>>> from django.db.models.loading import cache
>>> cache.app_models['defer_regress'] = {}
"""
}

View File

@ -9,6 +9,9 @@ class Animal(models.Model):
count = models.IntegerField()
weight = models.FloatField()
# use a non-default name for the default manager
specimens = models.Manager()
def __unicode__(self):
return self.common_name
@ -161,4 +164,10 @@ Weight = 1.2 (<type 'float'>)
>>> models.signals.pre_save.disconnect(animal_pre_save_check)
###############################################
# Regression for #11286 -- Ensure that dumpdata honors the default manager
# Dump the current contents of the database as a JSON fixture
>>> management.call_command('dumpdata', 'fixtures_regress.animal', format='json')
[{"pk": 1, "model": "fixtures_regress.animal", "fields": {"count": 3, "weight": 1.2, "name": "Lion", "latin_name": "Panthera leo"}}, {"pk": 2, "model": "fixtures_regress.animal", "fields": {"count": 2, "weight": 2.29..., "name": "Platypus", "latin_name": "Ornithorhynchus anatinus"}}, {"pk": 10, "model": "fixtures_regress.animal", "fields": {"count": 42, "weight": 1.2, "name": "Emu", "latin_name": "Dromaius novaehollandiae"}}]
"""}

View File

@ -4,7 +4,7 @@ r"""
>>> from django.conf import settings
>>> from django.core import mail
>>> from django.core.mail import EmailMessage, mail_admins, mail_managers
>>> from django.core.mail import EmailMessage, mail_admins, mail_managers, EmailMultiAlternatives
>>> from django.utils.translation import ugettext_lazy
# Test normal ascii character case:
@ -95,4 +95,48 @@ BadHeaderError: Header values can't contain newlines (got u'Subject\nInjection T
>>> message['From']
'from@example.com'
# Handle attachments within an multipart/alternative mail correctly (#9367)
# (test is not as precise/clear as it could be w.r.t. email tree structure,
# but it's good enough.)
>>> headers = {"Date": "Fri, 09 Nov 2001 01:08:47 -0000", "Message-ID": "foo"}
>>> subject, from_email, to = 'hello', 'from@example.com', 'to@example.com'
>>> text_content = 'This is an important message.'
>>> html_content = '<p>This is an <strong>important</strong> message.</p>'
>>> msg = EmailMultiAlternatives(subject, text_content, from_email, [to], headers=headers)
>>> msg.attach_alternative(html_content, "text/html")
>>> msg.attach("an attachment.pdf", "%PDF-1.4.%...", mimetype="application/pdf")
>>> print msg.message().as_string()
Content-Type: multipart/mixed; boundary="..."
MIME-Version: 1.0
Subject: hello
From: from@example.com
To: to@example.com
Date: Fri, 09 Nov 2001 01:08:47 -0000
Message-ID: foo
...
Content-Type: multipart/alternative; boundary="..."
MIME-Version: 1.0
...
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: quoted-printable
...
This is an important message.
...
Content-Type: text/html; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: quoted-printable
...
<p>This is an <strong>important</strong> message.</p>
...
...
Content-Type: application/pdf
MIME-Version: 1.0
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="an attachment.pdf"
...
JVBERi0xLjQuJS4uLg==
...
"""

View File

@ -1143,6 +1143,36 @@ True
>>> r.save()
>>> Ranking.objects.all()
[<Ranking: 3: a1>, <Ranking: 2: a2>, <Ranking: 1: a3>]
# Regression test for #10742:
# Queries used in an __in clause don't execute subqueries
>>> subq = Author.objects.filter(num__lt=3000)
>>> qs = Author.objects.filter(pk__in=subq)
>>> list(qs)
[<Author: a1>, <Author: a2>]
# The subquery result cache should not be populated
>>> subq._result_cache is None
True
>>> subq = Author.objects.filter(num__lt=3000)
>>> qs = Author.objects.exclude(pk__in=subq)
>>> list(qs)
[<Author: a3>, <Author: a4>]
# The subquery result cache should not be populated
>>> subq._result_cache is None
True
>>> subq = Author.objects.filter(num__lt=3000)
>>> list(Author.objects.filter(Q(pk__in=subq) & Q(name='a1')))
[<Author: a1>]
# The subquery result cache should not be populated
>>> subq._result_cache is None
True
"""}
# In Python 2.3 and the Python 2.6 beta releases, exceptions raised in __len__