mirror of
https://github.com/django/django.git
synced 2025-07-06 18:59:13 +00:00
[soc2009/model-validation] Merged to trunk at r11155
git-svn-id: http://code.djangoproject.com/svn/django/branches/soc2009/model-validation@11158 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
481fb86e13
commit
d628498c58
@ -36,7 +36,7 @@
|
||||
<ul>
|
||||
{% regroup models by app_label as grouped_models %}
|
||||
{% for group in grouped_models %}
|
||||
<li><a href="#{{ group.grouper }}">{{ group.grouper|capfirst }}</a></li>
|
||||
<li><a href="#app-{{ group.grouper }}">{{ group.grouper|capfirst }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
|
@ -214,6 +214,22 @@ def model_detail(request, app_label, model_name):
|
||||
'help_text': field.help_text,
|
||||
})
|
||||
|
||||
# Gather many-to-many fields.
|
||||
for field in opts.many_to_many:
|
||||
data_type = related_object_name = field.rel.to.__name__
|
||||
app_label = field.rel.to._meta.app_label
|
||||
verbose = _("related `%(app_label)s.%(object_name)s` objects") % {'app_label': app_label, 'object_name': data_type}
|
||||
fields.append({
|
||||
'name': "%s.all" % field.name,
|
||||
"data_type": 'List',
|
||||
'verbose': utils.parse_rst(_("all %s") % verbose , 'model', _('model:') + opts.module_name),
|
||||
})
|
||||
fields.append({
|
||||
'name' : "%s.count" % field.name,
|
||||
'data_type' : 'Integer',
|
||||
'verbose' : utils.parse_rst(_("number of %s") % verbose , 'model', _('model:') + opts.module_name),
|
||||
})
|
||||
|
||||
# Gather model methods.
|
||||
for func_name, func in model.__dict__.items():
|
||||
if (inspect.isfunction(func) and len(inspect.getargspec(func)[0]) == 1):
|
||||
@ -233,7 +249,7 @@ def model_detail(request, app_label, model_name):
|
||||
})
|
||||
|
||||
# Gather related objects
|
||||
for rel in opts.get_all_related_objects():
|
||||
for rel in opts.get_all_related_objects() + opts.get_all_related_many_to_many_objects():
|
||||
verbose = _("related `%(app_label)s.%(object_name)s` objects") % {'app_label': rel.opts.app_label, 'object_name': rel.opts.object_name}
|
||||
accessor = rel.get_accessor_name()
|
||||
fields.append({
|
||||
|
@ -32,7 +32,7 @@ class GeoModelAdmin(ModelAdmin):
|
||||
map_height = 400
|
||||
map_srid = 4326
|
||||
map_template = 'gis/admin/openlayers.html'
|
||||
openlayers_url = 'http://openlayers.org/api/2.7/OpenLayers.js'
|
||||
openlayers_url = 'http://openlayers.org/api/2.8/OpenLayers.js'
|
||||
point_zoom = num_zoom - 6
|
||||
wms_url = 'http://labs.metacarta.com/wms/vmap0'
|
||||
wms_layer = 'basic'
|
||||
|
@ -225,7 +225,7 @@ class GeoQuery(sql.Query):
|
||||
values.append(self.convert_values(value, field))
|
||||
else:
|
||||
values.extend(row[index_start:])
|
||||
return values
|
||||
return tuple(values)
|
||||
|
||||
def convert_values(self, value, field):
|
||||
"""
|
||||
|
@ -21,7 +21,7 @@ class GoogleMap(object):
|
||||
def __init__(self, key=None, api_url=None, version=None,
|
||||
center=None, zoom=None, dom_id='map',
|
||||
kml_urls=[], polylines=None, polygons=None, markers=None,
|
||||
template='gis/google/google-single.js',
|
||||
template='gis/google/google-map.js',
|
||||
js_module='geodjango',
|
||||
extra_context={}):
|
||||
|
||||
@ -162,7 +162,7 @@ class GoogleMapSet(GoogleMap):
|
||||
|
||||
# This is the template used to generate the GMap load JavaScript for
|
||||
# each map in the set.
|
||||
self.map_template = kwargs.pop('map_template', 'gis/google/google-map.js')
|
||||
self.map_template = kwargs.pop('map_template', 'gis/google/google-single.js')
|
||||
|
||||
# Running GoogleMap.__init__(), and resetting the template
|
||||
# value with default obtained above.
|
||||
|
@ -1,7 +0,0 @@
|
||||
{% block vars %}var geodjango = {};{% for icon in icons %}
|
||||
var {{ icon.varname }} = new GIcon(G_DEFAULT_ICON);
|
||||
{% if icon.image %}{{ icon.varname }}.image = "{{ icon.image }}";{% endif %}
|
||||
{% if icon.shadow %}{{ icon.varname }}.shadow = "{{ icon.shadow }}";{% endif %} {% if icon.shadowsize %}{{ icon.varname }}.shadowSize = new GSize({{ icon.shadowsize.0 }}, {{ icon.shadowsize.1 }});{% endif %}
|
||||
{% if icon.iconanchor %}{{ icon.varname }}.iconAnchor = new GPoint({{ icon.iconanchor.0 }}, {{ icon.iconanchor.1 }});{% endif %} {% if icon.iconsize %}{{ icon.varname }}.iconSize = new GSize({{ icon.iconsize.0 }}, {{ icon.iconsize.1 }});{% endif %}
|
||||
{% if icon.infowindowanchor %}{{ icon.varname }}.infoWindowAnchor = new GPoint({{ icon.infowindowanchor.0 }}, {{ icon.infowindowanchor.1 }});{% endif %}{% endfor %}{% endblock %}
|
||||
{% block functions %}{% endblock %}
|
@ -1,10 +1,16 @@
|
||||
{% autoescape off %}
|
||||
{% block vars %}var geodjango = {};{% for icon in icons %}
|
||||
var {{ icon.varname }} = new GIcon(G_DEFAULT_ICON);
|
||||
{% if icon.image %}{{ icon.varname }}.image = "{{ icon.image }}";{% endif %}
|
||||
{% if icon.shadow %}{{ icon.varname }}.shadow = "{{ icon.shadow }}";{% endif %} {% if icon.shadowsize %}{{ icon.varname }}.shadowSize = new GSize({{ icon.shadowsize.0 }}, {{ icon.shadowsize.1 }});{% endif %}
|
||||
{% if icon.iconanchor %}{{ icon.varname }}.iconAnchor = new GPoint({{ icon.iconanchor.0 }}, {{ icon.iconanchor.1 }});{% endif %} {% if icon.iconsize %}{{ icon.varname }}.iconSize = new GSize({{ icon.iconsize.0 }}, {{ icon.iconsize.1 }});{% endif %}
|
||||
{% if icon.infowindowanchor %}{{ icon.varname }}.infoWindowAnchor = new GPoint({{ icon.infowindowanchor.0 }}, {{ icon.infowindowanchor.1 }});{% endif %}{% endfor %}
|
||||
{% endblock vars %}{% block functions %}
|
||||
{% block load %}{{ js_module }}.{{ dom_id }}_load = function(){
|
||||
if (GBrowserIsCompatible()) {
|
||||
{{ js_module }}.{{ dom_id }} = new GMap2(document.getElementById("{{ dom_id }}"));
|
||||
{{ js_module }}.{{ dom_id }}.setCenter(new GLatLng({{ center.1 }}, {{ center.0 }}), {{ zoom }});
|
||||
{% block controls %}{{ js_module }}.{{ dom_id }}.addControl(new GSmallMapControl());
|
||||
{{ js_module }}.{{ dom_id }}.addControl(new GMapTypeControl());{% endblock %}
|
||||
{% block controls %}{{ js_module }}.{{ dom_id }}.setUIToDefault();{% endblock %}
|
||||
{% if calc_zoom %}var bounds = new GLatLngBounds(); var tmp_bounds = new GLatLngBounds();{% endif %}
|
||||
{% for kml_url in kml_urls %}{{ js_module }}.{{ dom_id }}_kml{{ forloop.counter }} = new GGeoXml("{{ kml_url }}");
|
||||
{{ js_module }}.{{ dom_id }}.addOverlay({{ js_module }}.{{ dom_id }}_kml{{ forloop.counter }});{% endfor %}
|
||||
@ -26,4 +32,4 @@
|
||||
alert("Sorry, the Google Maps API is not compatible with this browser.");
|
||||
}
|
||||
}
|
||||
{% endblock %}{% endautoescape %}
|
||||
{% endblock load %}{% endblock functions %}{% endautoescape %}
|
||||
|
@ -1,4 +1,4 @@
|
||||
{% extends "gis/google/google-base.js" %}
|
||||
{% extends "gis/google/google-map.js" %}
|
||||
{% block functions %}
|
||||
{{ load_map_js }}
|
||||
{{ js_module }}.load = function(){
|
||||
|
@ -1,2 +1,2 @@
|
||||
{% extends "gis/google/google-base.js" %}
|
||||
{% block functions %}{% include "gis/google/google-map.js" %}{% endblock %}
|
||||
{% extends "gis/google/google-map.js" %}
|
||||
{% block vars %}{# No vars here because used within GoogleMapSet #}{% endblock %}
|
@ -40,5 +40,5 @@ class Author(models.Model):
|
||||
|
||||
class Book(models.Model):
|
||||
title = models.CharField(max_length=100)
|
||||
author = models.ForeignKey(Author, related_name='books')
|
||||
author = models.ForeignKey(Author, related_name='books', null=True)
|
||||
objects = models.GeoManager()
|
||||
|
@ -257,6 +257,13 @@ class RelatedGeoModelTest(unittest.TestCase):
|
||||
self.assertEqual(1, len(qs))
|
||||
self.assertEqual(3, qs[0].num_books)
|
||||
|
||||
def test13_select_related_null_fk(self):
|
||||
"Testing `select_related` on a nullable ForeignKey via `GeoManager`. See #11381."
|
||||
no_author = Book.objects.create(title='Without Author')
|
||||
b = Book.objects.select_related('author').get(title='Without Author')
|
||||
# Should be `None`, and not a 'dummy' model.
|
||||
self.assertEqual(None, b.author)
|
||||
|
||||
# TODO: Related tests for KML, GML, and distance lookups.
|
||||
|
||||
def suite():
|
||||
|
@ -185,7 +185,11 @@ class RegexURLResolver(object):
|
||||
try:
|
||||
sub_match = pattern.resolve(new_path)
|
||||
except Resolver404, e:
|
||||
tried.extend([(pattern.regex.pattern + ' ' + t) for t in e.args[0]['tried']])
|
||||
sub_tried = e.args[0].get('tried')
|
||||
if sub_tried is not None:
|
||||
tried.extend([(pattern.regex.pattern + ' ' + t) for t in sub_tried])
|
||||
else:
|
||||
tried.append(pattern.regex.pattern)
|
||||
else:
|
||||
if sub_match:
|
||||
sub_match_dict = dict([(smart_str(k), v) for k, v in match.groupdict().items()])
|
||||
@ -195,6 +199,7 @@ class RegexURLResolver(object):
|
||||
return sub_match[0], sub_match[1], sub_match_dict
|
||||
tried.append(pattern.regex.pattern)
|
||||
raise Resolver404, {'tried': tried, 'path': new_path}
|
||||
raise Resolver404, {'path' : path}
|
||||
|
||||
def _get_urlconf_module(self):
|
||||
try:
|
||||
|
@ -667,6 +667,43 @@ Controls where on the page the actions bar appears. By default, the admin
|
||||
changelist displays actions at the top of the page (``actions_on_top = True;
|
||||
actions_on_bottom = False``).
|
||||
|
||||
.. attribute:: ModelAdmin.change_list_template
|
||||
|
||||
Path to a custom template that will be used by the model objects "change list"
|
||||
view. Templates can override or extend base admin templates as described in
|
||||
`Overriding Admin Templates`_.
|
||||
|
||||
If you don't specify this attribute, a default template shipped with Django
|
||||
that provides the standard appearance is used.
|
||||
|
||||
.. attribute:: ModelAdmin.change_form_template
|
||||
|
||||
Path to a custom template that will be used by both the model object creation
|
||||
and change views. Templates can override or extend base admin templates as
|
||||
described in `Overriding Admin Templates`_.
|
||||
|
||||
If you don't specify this attribute, a default template shipped with Django
|
||||
that provides the standard appearance is used.
|
||||
|
||||
.. attribute:: ModelAdmin.object_history_template
|
||||
|
||||
Path to a custom template that will be used by the model object change history
|
||||
display view. Templates can override or extend base admin templates as
|
||||
described in `Overriding Admin Templates`_.
|
||||
|
||||
If you don't specify this attribute, a default template shipped with Django
|
||||
that provides the standard appearance is used.
|
||||
|
||||
.. attribute:: ModelAdmin.delete_confirmation_template
|
||||
|
||||
Path to a custom template that will be used by the view responsible of showing
|
||||
the confirmation page when the user decides to delete one or more model
|
||||
objects. Templates can override or extend base admin templates as described in
|
||||
`Overriding Admin Templates`_.
|
||||
|
||||
If you don't specify this attribute, a default template shipped with Django
|
||||
that provides the standard appearance is used.
|
||||
|
||||
``ModelAdmin`` methods
|
||||
----------------------
|
||||
|
||||
@ -762,6 +799,56 @@ return a subset of objects for this foreign key field based on the user::
|
||||
This uses the ``HttpRequest`` instance to filter the ``Car`` foreign key field
|
||||
to only the cars owned by the ``User`` instance.
|
||||
|
||||
Other methods
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
.. method:: ModelAdmin.add_view(self, request, form_url='', extra_context=None)
|
||||
|
||||
Django view for the model instance addition page. See note below.
|
||||
|
||||
.. method:: ModelAdmin.change_view(self, request, object_id, extra_context=None)
|
||||
|
||||
Django view for the model instance edition page. See note below.
|
||||
|
||||
.. method:: ModelAdmin.changelist_view(self, request, extra_context=None)
|
||||
|
||||
Django view for the model instances change list/actions page. See note below.
|
||||
|
||||
.. method:: ModelAdmin.delete_view(self, request, object_id, extra_context=None)
|
||||
|
||||
Django view for the model instance(s) deletion confirmation page. See note below.
|
||||
|
||||
.. method:: ModelAdmin.history_view(self, request, object_id, extra_context=None)
|
||||
|
||||
Django view for the page that shows the modification history for a given model
|
||||
instance.
|
||||
|
||||
Unlike the hook-type ``ModelAdmin`` methods detailed in the previous section,
|
||||
these five methods are in reality designed to be invoked as Django views from
|
||||
the admin application URL dispatching handler to render the pages that deal
|
||||
with model instances CRUD operations. As a result, completely overriding these
|
||||
methods will significantly change the behavior of the admin application.
|
||||
|
||||
One comon reason for overriding these methods is to augment the context data
|
||||
that is provided to the template that renders the view. In the following
|
||||
example, the change view is overridden so that the rendered template is
|
||||
provided some extra mapping data that would not otherwise be available::
|
||||
|
||||
class MyModelAdmin(admin.ModelAdmin):
|
||||
|
||||
# A template for a very customized change view:
|
||||
change_form_template = 'admin/myapp/extras/openstreetmap_change_form.html'
|
||||
|
||||
def get_osm_info(self):
|
||||
# ...
|
||||
|
||||
def change_view(self, request, object_id, extra_context=None):
|
||||
my_context = {
|
||||
'osm_data': self.get_osm_info(),
|
||||
}
|
||||
return super(MyModelAdmin, self).change_view(request, object_id,
|
||||
extra_context=my_context))
|
||||
|
||||
``ModelAdmin`` media definitions
|
||||
--------------------------------
|
||||
|
||||
@ -783,7 +870,7 @@ Adding custom validation to the admin
|
||||
-------------------------------------
|
||||
|
||||
Adding custom validation of data in the admin is quite easy. The automatic admin
|
||||
interfaces reuses :mod:`django.forms`, and the ``ModelAdmin`` class gives you
|
||||
interface reuses :mod:`django.forms`, and the ``ModelAdmin`` class gives you
|
||||
the ability define your own form::
|
||||
|
||||
class ArticleAdmin(admin.ModelAdmin):
|
||||
@ -803,7 +890,9 @@ any field::
|
||||
|
||||
It is important you use a ``ModelForm`` here otherwise things can break. See the
|
||||
:ref:`forms <ref-forms-index>` documentation on :ref:`custom validation
|
||||
<ref-forms-validation>` for more information.
|
||||
<ref-forms-validation>` and, more specifically, the
|
||||
:ref:`model form validation notes <overriding-modelform-clean-method>` for more
|
||||
information.
|
||||
|
||||
.. _admin-inlines:
|
||||
|
||||
@ -1106,7 +1195,7 @@ directory, our link would appear on every model's change form.
|
||||
Templates which may be overridden per app or model
|
||||
--------------------------------------------------
|
||||
|
||||
Not every template in ``contrib\admin\templates\admin`` may be overridden per
|
||||
Not every template in ``contrib/admin/templates/admin`` may be overridden per
|
||||
app or per model. The following can:
|
||||
|
||||
* ``app_index.html``
|
||||
@ -1131,8 +1220,8 @@ Root and login templates
|
||||
------------------------
|
||||
|
||||
If you wish to change the index or login templates, you are better off creating
|
||||
your own ``AdminSite`` instance (see below), and changing the ``index_template``
|
||||
or ``login_template`` properties.
|
||||
your own ``AdminSite`` instance (see below), and changing the :attr:`AdminSite.index_template`
|
||||
or :attr:`AdminSite.login_template` properties.
|
||||
|
||||
``AdminSite`` objects
|
||||
=====================
|
||||
@ -1151,6 +1240,21 @@ or add anything you like. Then, simply create an instance of your
|
||||
Python class), and register your models and ``ModelAdmin`` subclasses
|
||||
with it instead of using the default.
|
||||
|
||||
``AdminSite`` attributes
|
||||
------------------------
|
||||
|
||||
.. attribute:: AdminSite.index_template
|
||||
|
||||
Path to a custom template that will be used by the admin site main index view.
|
||||
Templates can override or extend base admin templates as described in
|
||||
`Overriding Admin Templates`_.
|
||||
|
||||
.. attribute:: AdminSite.login_template
|
||||
|
||||
Path to a custom template that will be used by the admin site login view.
|
||||
Templates can override or extend base admin templates as described in
|
||||
`Overriding Admin Templates`_.
|
||||
|
||||
Hooking ``AdminSite`` instances into your URLconf
|
||||
-------------------------------------------------
|
||||
|
||||
|
@ -251,7 +251,7 @@ Here's a sample configuration which uses a MySQL option file::
|
||||
DATABASE_OPTIONS = {
|
||||
'read_default_file': '/path/to/my.cnf',
|
||||
}
|
||||
|
||||
|
||||
# my.cnf
|
||||
[client]
|
||||
database = DATABASE_NAME
|
||||
@ -445,10 +445,10 @@ If you're getting this error, you can solve it by:
|
||||
* Switching to another database backend. At a certain point SQLite becomes
|
||||
too "lite" for real-world applications, and these sorts of concurrency
|
||||
errors indicate you've reached that point.
|
||||
|
||||
* Rewriting your code to reduce concurrency and ensure that database
|
||||
|
||||
* Rewriting your code to reduce concurrency and ensure that database
|
||||
transactions are short-lived.
|
||||
|
||||
|
||||
* Increase the default timeout value by setting the ``timeout`` database
|
||||
option option::
|
||||
|
||||
@ -457,7 +457,7 @@ If you're getting this error, you can solve it by:
|
||||
"timeout": 20,
|
||||
# ...
|
||||
}
|
||||
|
||||
|
||||
This will simply make SQLite wait a bit longer before throwing "database
|
||||
is locked" errors; it won't really do anything to solve them.
|
||||
|
||||
@ -601,3 +601,28 @@ some limitations on the usage of such LOB columns in general:
|
||||
Oracle. A workaround to this is to keep ``TextField`` columns out of any
|
||||
models that you foresee performing ``distinct()`` queries on, and to
|
||||
include the ``TextField`` in a related model instead.
|
||||
|
||||
.. _third-party-notes:
|
||||
|
||||
Using a 3rd-party database backend
|
||||
==================================
|
||||
|
||||
In addition to the officially supported databases, there are backends provided
|
||||
by 3rd parties that allow you to use other databases with Django:
|
||||
|
||||
* `Sybase SQL Anywhere`_
|
||||
* `IBM DB2`_
|
||||
* `Microsoft SQL Server 2005`_
|
||||
* Firebird_
|
||||
* ODBC_
|
||||
|
||||
The Django versions and ORM features supported by these unofficial backends
|
||||
vary considerably. Queries regarding the specific capabilities of these
|
||||
unofficial backends, along with any support queries, should be directed to
|
||||
the support channels provided by each 3rd party project.
|
||||
|
||||
.. _Sybase SQL Anywhere: http://code.google.com/p/sqlany-django/
|
||||
.. _IBM DB2: http://code.google.com/p/ibm-db/
|
||||
.. _Microsoft SQL Server 2005: http://code.google.com/p/django-mssql/
|
||||
.. _Firebird: http://code.google.com/p/django-firebird/
|
||||
.. _ODBC: http://code.google.com/p/django-pyodbc/
|
||||
|
@ -35,7 +35,7 @@ You can evaluate a ``QuerySet`` in the following ways:
|
||||
|
||||
* **Slicing.** As explained in :ref:`limiting-querysets`, a ``QuerySet`` can
|
||||
be sliced, using Python's array-slicing syntax. Usually slicing a
|
||||
``QuerySet`` returns another (unevaluated ) ``QuerySet``, but Django will
|
||||
``QuerySet`` returns another (unevaluated) ``QuerySet``, but Django will
|
||||
execute the database query if you use the "step" parameter of slice
|
||||
syntax.
|
||||
|
||||
|
@ -397,16 +397,26 @@ to be rendered first, we could specify the following ``ModelForm``::
|
||||
... model = Book
|
||||
... fields = ['title', 'author']
|
||||
|
||||
.. _overriding-modelform-clean-method:
|
||||
|
||||
Overriding the clean() method
|
||||
-----------------------------
|
||||
|
||||
You can override the ``clean()`` method on a model form to provide additional
|
||||
validation in the same way you can on a normal form. However, by default the
|
||||
``clean()`` method validates the uniqueness of fields that are marked as
|
||||
``unique``, ``unique_together`` or ``unique_for_date|month|year`` on the model.
|
||||
Therefore, if you would like to override the ``clean()`` method and maintain the
|
||||
default validation, you must call the parent class's ``clean()`` method.
|
||||
validation in the same way you can on a normal form.
|
||||
|
||||
In this regard, model forms have two specific characteristics when compared to
|
||||
forms:
|
||||
|
||||
By default the ``clean()`` method validates the uniqueness of fields that are
|
||||
marked as ``unique``, ``unique_together`` or ``unique_for_date|month|year`` on
|
||||
the model. Therefore, if you would like to override the ``clean()`` method and
|
||||
maintain the default validation, you must call the parent class's ``clean()``
|
||||
method.
|
||||
|
||||
Also, a model form instance bound to a model object will contain a
|
||||
``self.instance`` attribute that gives model form methods access to that
|
||||
specific model instance.
|
||||
|
||||
Form inheritance
|
||||
----------------
|
||||
|
@ -978,15 +978,17 @@ message files (``.po``). Translation work itself just involves editing existing
|
||||
files of this type, but if you want to create your own message files, or want to
|
||||
test or compile a changed message file, you will need the ``gettext`` utilities:
|
||||
|
||||
* Download the following zip files from
|
||||
http://sourceforge.net/projects/gettext
|
||||
* Download the following zip files from the GNOME servers
|
||||
http://ftp.gnome.org/pub/gnome/binaries/win32/dependencies/ or from one
|
||||
of its mirrors_
|
||||
|
||||
* ``gettext-runtime-X.bin.woe32.zip``
|
||||
* ``gettext-tools-X.bin.woe32.zip``
|
||||
* ``libiconv-X.bin.woe32.zip``
|
||||
* ``gettext-runtime-X.zip``
|
||||
* ``gettext-tools-X.zip``
|
||||
|
||||
* Extract the 3 files in the same folder (i.e. ``C:\Program
|
||||
Files\gettext-utils``)
|
||||
``X`` is the version number, we recomend using ``0.15`` or higher.
|
||||
|
||||
* Extract the contents of the ``bin\`` directories in both files to the
|
||||
same folder on your system (i.e. ``C:\Program Files\gettext-utils``)
|
||||
|
||||
* Update the system PATH:
|
||||
|
||||
@ -995,6 +997,8 @@ test or compile a changed message file, you will need the ``gettext`` utilities:
|
||||
* Add ``;C:\Program Files\gettext-utils\bin`` at the end of the
|
||||
``Variable value`` field
|
||||
|
||||
.. _mirrors: http://ftp.gnome.org/pub/GNOME/MIRRORS
|
||||
|
||||
You may also use ``gettext`` binaries you have obtained elsewhere, so long as
|
||||
the ``xgettext --version`` command works properly. Some version 0.14.4 binaries
|
||||
have been found to not support this command. Do not attempt to use Django
|
||||
|
@ -61,13 +61,27 @@ for each platform.
|
||||
Get your database running
|
||||
=========================
|
||||
|
||||
If you plan to use Django's database API functionality, you'll need to
|
||||
make sure a database server is running. Django works with PostgreSQL_,
|
||||
MySQL_, Oracle_ and SQLite_ (although SQLite doesn't require a separate server
|
||||
to be running).
|
||||
If you plan to use Django's database API functionality, you'll need to make
|
||||
sure a database server is running. Django supports many different database
|
||||
servers and is officially supported with PostgreSQL_, MySQL_, Oracle_ and
|
||||
SQLite_ (although SQLite doesn't require a separate server to be running).
|
||||
|
||||
Additionally, you'll need to make sure your Python database bindings are
|
||||
installed.
|
||||
In addition to the officially supported databases, there are backends provided
|
||||
by 3rd parties that allow you to use other databases with Django:
|
||||
|
||||
* `Sybase SQL Anywhere`_
|
||||
* `IBM DB2`_
|
||||
* `Microsoft SQL Server 2005`_
|
||||
* Firebird_
|
||||
* ODBC_
|
||||
|
||||
The Django versions and ORM features supported by these unofficial backends
|
||||
vary considerably. Queries regarding the specific capabilities of these
|
||||
unofficial backends, along with any support queries, should be directed to the
|
||||
support channels provided by each 3rd party project.
|
||||
|
||||
In addition to a database backend, you'll need to make sure your Python
|
||||
database bindings are installed.
|
||||
|
||||
* If you're using PostgreSQL, you'll need the psycopg_ package. Django supports
|
||||
both version 1 and 2. (When you configure Django's database layer, specify
|
||||
@ -89,6 +103,9 @@ installed.
|
||||
:ref:`Oracle backend <oracle-notes>` for important information
|
||||
regarding supported versions of both Oracle and ``cx_Oracle``.
|
||||
|
||||
* If you're using an unofficial 3rd party backend, please consult the
|
||||
documentation provided for any additional requirements.
|
||||
|
||||
If you plan to use Django's ``manage.py syncdb`` command to
|
||||
automatically create database tables for your models, you'll need to
|
||||
ensure that Django has permission to create and alter tables in the
|
||||
@ -111,7 +128,11 @@ Django will need permission to create a test database.
|
||||
.. _pysqlite: http://pysqlite.org/
|
||||
.. _cx_Oracle: http://cx-oracle.sourceforge.net/
|
||||
.. _Oracle: http://www.oracle.com/
|
||||
|
||||
.. _Sybase SQL Anywhere: http://code.google.com/p/sqlany-django/
|
||||
.. _IBM DB2: http://code.google.com/p/ibm-db/
|
||||
.. _Microsoft SQL Server 2005: http://code.google.com/p/django-mssql/
|
||||
.. _Firebird: http://code.google.com/p/django-firebird/
|
||||
.. _ODBC: http://code.google.com/p/django-pyodbc/
|
||||
.. _removing-old-versions-of-django:
|
||||
|
||||
Remove any old versions of Django
|
||||
|
@ -14,6 +14,9 @@ class Reporter(models.Model):
|
||||
last_name = models.CharField(max_length=30)
|
||||
email = models.EmailField()
|
||||
|
||||
class Meta:
|
||||
ordering = ('first_name', 'last_name')
|
||||
|
||||
def __unicode__(self):
|
||||
return u"%s %s" % (self.first_name, self.last_name)
|
||||
|
||||
|
@ -22,6 +22,9 @@ class Comment(models.Model):
|
||||
post = models.ForeignKey(Post, null=True)
|
||||
comment_text = models.CharField(max_length=250)
|
||||
|
||||
class Meta:
|
||||
ordering = ('comment_text',)
|
||||
|
||||
def __unicode__(self):
|
||||
return self.comment_text
|
||||
|
||||
|
@ -103,7 +103,7 @@ def data_compare(testcase, pk, klass, data):
|
||||
def generic_compare(testcase, pk, klass, data):
|
||||
instance = klass.objects.get(id=pk)
|
||||
testcase.assertEqual(data[0], instance.data)
|
||||
testcase.assertEqual(data[1:], [t.data for t in instance.tags.all()])
|
||||
testcase.assertEqual(data[1:], [t.data for t in instance.tags.order_by('id')])
|
||||
|
||||
def fk_compare(testcase, pk, klass, data):
|
||||
instance = klass.objects.get(id=pk)
|
||||
@ -111,7 +111,7 @@ def fk_compare(testcase, pk, klass, data):
|
||||
|
||||
def m2m_compare(testcase, pk, klass, data):
|
||||
instance = klass.objects.get(id=pk)
|
||||
testcase.assertEqual(data, [obj.id for obj in instance.data.all()])
|
||||
testcase.assertEqual(data, [obj.id for obj in instance.data.order_by('id')])
|
||||
|
||||
def im2m_compare(testcase, pk, klass, data):
|
||||
instance = klass.objects.get(id=pk)
|
||||
|
@ -14,8 +14,9 @@ Traceback (most recent call last):
|
||||
ImproperlyConfigured: The included urlconf regressiontests.urlpatterns_reverse.no_urls doesn't have any patterns in it
|
||||
"""}
|
||||
|
||||
import unittest
|
||||
|
||||
from django.core.urlresolvers import reverse, NoReverseMatch
|
||||
from django.core.urlresolvers import reverse, resolve, NoReverseMatch, Resolver404
|
||||
from django.http import HttpResponseRedirect, HttpResponsePermanentRedirect
|
||||
from django.shortcuts import redirect
|
||||
from django.test import TestCase
|
||||
@ -112,6 +113,21 @@ class URLPatternReverse(TestCase):
|
||||
else:
|
||||
self.assertEquals(got, expected)
|
||||
|
||||
class ResolverTests(unittest.TestCase):
|
||||
def test_non_regex(self):
|
||||
"""
|
||||
Verifies that we raise a Resolver404 if what we are resolving doesn't
|
||||
meet the basic requirements of a path to match - i.e., at the very
|
||||
least, it matches the root pattern '^/'. We must never return None
|
||||
from resolve, or we will get a TypeError further down the line.
|
||||
|
||||
Regression for #10834.
|
||||
"""
|
||||
self.assertRaises(Resolver404, resolve, '')
|
||||
self.assertRaises(Resolver404, resolve, 'a')
|
||||
self.assertRaises(Resolver404, resolve, '\\')
|
||||
self.assertRaises(Resolver404, resolve, '.')
|
||||
|
||||
class ReverseShortcutTests(TestCase):
|
||||
urls = 'regressiontests.urlpatterns_reverse.urls'
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user