mirror of
				https://github.com/django/django.git
				synced 2025-10-31 09:41:08 +00:00 
			
		
		
		
	newforms-admin: Merged to [6013]
git-svn-id: http://code.djangoproject.com/svn/django/branches/newforms-admin@6014 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
		
							
								
								
									
										6
									
								
								AUTHORS
									
									
									
									
									
								
							
							
						
						
									
										6
									
								
								AUTHORS
									
									
									
									
									
								
							| @@ -95,6 +95,7 @@ answer newbie questions, and generally made Django that much better: | ||||
|     Alex Dedul | ||||
|     deric@monowerks.com | ||||
|     Max Derkachev <mderk@yandex.ru> | ||||
|     Sander Dijkhuis <sander.dijkhuis@gmail.com> | ||||
|     Jordan Dimov <s3x3y1@gmail.com> | ||||
|     dne@mayonnaise.net | ||||
|     Maximillian Dornseif <md@hudora.de> | ||||
| @@ -137,6 +138,7 @@ answer newbie questions, and generally made Django that much better: | ||||
|     Joe Heck <http://www.rhonabwy.com/wp/> | ||||
|     Joel Heenan <joelh-django@planetjoel.com> | ||||
|     hipertracker@gmail.com | ||||
|     Deryck Hodge <http://www.devurandom.org/> | ||||
|     Brett Hoerner <bretthoerner@bretthoerner.com> | ||||
|     Ian Holsman <http://feh.holsman.net/> | ||||
|     Kieran Holland <http://www.kieranholland.com> | ||||
| @@ -204,6 +206,7 @@ answer newbie questions, and generally made Django that much better: | ||||
|     Andreas Mock <andreas.mock@web.de> | ||||
|     Reza Mohammadi <reza@zeerak.ir> | ||||
|     Aljosa Mohorovic <aljosa.mohorovic@gmail.com> | ||||
|     Ramiro Morales <rm0@gmx.net> | ||||
|     Eric Moritz <http://eric.themoritzfamily.com/> | ||||
|     mrmachine <real.human@mrmachine.net> | ||||
|     Robin Munn <http://www.geekforgod.com/> | ||||
| @@ -213,6 +216,7 @@ answer newbie questions, and generally made Django that much better: | ||||
|     Fraser Nevett <mail@nevett.org> | ||||
|     Sam Newman <http://www.magpiebrain.com/> | ||||
|     Neal Norwitz <nnorwitz@google.com> | ||||
|     Todd O'Bryan <toddobryan@mac.com> | ||||
|     oggie rob <oz.robharvey@gmail.com> | ||||
|     Jay Parlar <parlar@gmail.com> | ||||
|     pavithran s <pavithran.s@gmail.com> | ||||
| @@ -228,10 +232,10 @@ answer newbie questions, and generally made Django that much better: | ||||
|     Daniel Poelzleithner <http://poelzi.org/> | ||||
|     polpak@yahoo.com | ||||
|     Matthias Pronk <django@masida.nl> | ||||
|     Jyrki Pulliainen <jyrki.pulliainen@gmail.com> | ||||
|     Johann Queuniet <johann.queuniet@adh.naellia.eu> | ||||
|     J. Rademaker | ||||
|     Michael Radziej <mir@noris.de> | ||||
|     Ramiro Morales <rm0@gmx.net> | ||||
|     Massimiliano Ravelli <massimiliano.ravelli@gmail.com> | ||||
|     Brian Ray <http://brianray.chipy.org/> | ||||
|     remco@diji.biz | ||||
|   | ||||
| @@ -4,5 +4,6 @@ def get_version(): | ||||
|     "Returns the version as a human-format string." | ||||
|     v = '.'.join([str(i) for i in VERSION[:-1]]) | ||||
|     if VERSION[-1]: | ||||
|         v += '-' + VERSION[-1] | ||||
|         from django.utils.version import get_svn_revision | ||||
|         v = '%s-%s-%s' % (v, VERSION[-1], get_svn_revision()) | ||||
|     return v | ||||
|   | ||||
| @@ -17,7 +17,7 @@ def login(request, template_name='registration/login.html'): | ||||
|         errors = manipulator.get_validation_errors(request.POST) | ||||
|         if not errors: | ||||
|             # Light security check -- make sure redirect_to isn't garbage. | ||||
|             if not redirect_to or '://' in redirect_to or ' ' in redirect_to: | ||||
|             if not redirect_to or '//' in redirect_to or ' ' in redirect_to: | ||||
|                 from django.conf import settings | ||||
|                 redirect_to = settings.LOGIN_REDIRECT_URL | ||||
|             from django.contrib.auth import login | ||||
|   | ||||
| @@ -1,6 +1,9 @@ | ||||
| from django.utils.translation import ungettext, ugettext as _ | ||||
| from django.utils.encoding import force_unicode | ||||
| from django import template | ||||
| from django.template import defaultfilters | ||||
| from django.conf import settings | ||||
| from datetime import date, timedelta | ||||
| import re | ||||
|  | ||||
| register = template.Library() | ||||
| @@ -67,3 +70,27 @@ def apnumber(value): | ||||
|         return value | ||||
|     return (_('one'), _('two'), _('three'), _('four'), _('five'), _('six'), _('seven'), _('eight'), _('nine'))[value-1] | ||||
| register.filter(apnumber) | ||||
|  | ||||
| def naturalday(value, arg=None): | ||||
|     """ | ||||
|     For date values that are tomorrow, today or yesterday compared to | ||||
|     present day returns representing string. Otherwise, returns a string | ||||
|     formatted according to settings.DATE_FORMAT. | ||||
|     """ | ||||
|     try:  | ||||
|         value = date(value.year, value.month, value.day) | ||||
|     except AttributeError: | ||||
|         # Passed value wasn't a date object | ||||
|         return value | ||||
|     except ValueError: | ||||
|         # Date arguments out of range | ||||
|         return value | ||||
|     delta = value - date.today() | ||||
|     if delta.days == 0: | ||||
|         return _(u'today') | ||||
|     elif delta.days == 1: | ||||
|         return _(u'tomorrow') | ||||
|     elif delta.days == -1: | ||||
|         return _(u'yesterday') | ||||
|     return defaultfilters.date(value, arg) | ||||
| register.filter(naturalday) | ||||
|   | ||||
| @@ -24,7 +24,7 @@ class Command(NoArgsCommand): | ||||
|             except ImportError: | ||||
|                 pass | ||||
|  | ||||
|         sql_list = sql_flush(self.style) | ||||
|         sql_list = sql_flush(self.style, only_django=True) | ||||
|  | ||||
|         if interactive: | ||||
|             confirm = raw_input("""You have requested a flush of the database. | ||||
|   | ||||
| @@ -30,7 +30,7 @@ class Command(BaseCommand): | ||||
|             raise CommandError("%r is not a valid port number." % port) | ||||
|  | ||||
|         use_reloader = options.get('use_reloader', True) | ||||
|         admin_media_dir = options.get('admin_media_dir', '') | ||||
|         admin_media_path = options.get('admin_media_path', '') | ||||
|         shutdown_message = options.get('shutdown_message', '') | ||||
|         quit_command = (sys.platform == 'win32') and 'CTRL-BREAK' or 'CONTROL-C' | ||||
|  | ||||
| @@ -42,7 +42,7 @@ class Command(BaseCommand): | ||||
|             print "Development server is running at http://%s:%s/" % (addr, port) | ||||
|             print "Quit the server with %s." % quit_command | ||||
|             try: | ||||
|                 path = admin_media_dir or django.__path__[0] + '/contrib/admin/media' | ||||
|                 path = admin_media_path or django.__path__[0] + '/contrib/admin/media' | ||||
|                 handler = AdminMediaHandler(WSGIHandler(), path) | ||||
|                 run(addr, int(port), handler) | ||||
|             except WSGIServerException, e: | ||||
|   | ||||
| @@ -7,4 +7,4 @@ class Command(NoArgsCommand): | ||||
|  | ||||
|     def handle_noargs(self, **options): | ||||
|         from django.core.management.sql import sql_flush | ||||
|         return '\n'.join(sql_flush(self.style)) | ||||
|         return '\n'.join(sql_flush(self.style, only_django=True)) | ||||
|   | ||||
| @@ -13,6 +13,25 @@ def table_list(): | ||||
|     cursor = connection.cursor() | ||||
|     return get_introspection_module().get_table_list(cursor) | ||||
|  | ||||
| def django_table_list(only_existing=False): | ||||
|     """ | ||||
|     Returns a list of all table names that have associated Django models and | ||||
|     are in INSTALLED_APPS. | ||||
|  | ||||
|     If only_existing is True, the resulting list will only include the tables | ||||
|     that actually exist in the database. | ||||
|     """ | ||||
|     from django.db import models | ||||
|     tables = [] | ||||
|     for app in models.get_apps(): | ||||
|         for model in models.get_models(app): | ||||
|             tables.append(model._meta.db_table) | ||||
|             tables.extend([f.m2m_db_table() for f in model._meta.many_to_many]) | ||||
|     if only_existing: | ||||
|         existing = table_list() | ||||
|         tables = [t for t in tables if t in existing] | ||||
|     return tables | ||||
|  | ||||
| def installed_models(table_list): | ||||
|     "Returns a set of all models that are installed, given a list of existing table names." | ||||
|     from django.db import connection, models | ||||
| @@ -181,10 +200,19 @@ def sql_reset(app, style): | ||||
|     "Returns a list of the DROP TABLE SQL, then the CREATE TABLE SQL, for the given module." | ||||
|     return sql_delete(app, style) + sql_all(app, style) | ||||
|  | ||||
| def sql_flush(style): | ||||
|     "Returns a list of the SQL statements used to flush the database." | ||||
| def sql_flush(style, only_django=False): | ||||
|     """ | ||||
|     Returns a list of the SQL statements used to flush the database. | ||||
|      | ||||
|     If only_django is True, then only table names that have associated Django | ||||
|     models and are in INSTALLED_APPS will be included. | ||||
|     """ | ||||
|     from django.db import connection | ||||
|     statements = connection.ops.sql_flush(style, table_list(), sequence_list()) | ||||
|     if only_django: | ||||
|         tables = django_table_list() | ||||
|     else: | ||||
|         tables = table_list() | ||||
|     statements = connection.ops.sql_flush(style, tables, sequence_list()) | ||||
|     return statements | ||||
|  | ||||
| def sql_custom(app): | ||||
|   | ||||
| @@ -8,6 +8,7 @@ ImproperlyConfigured. | ||||
| """ | ||||
|  | ||||
| from django.core.exceptions import ImproperlyConfigured | ||||
| from django.db.backends import BaseDatabaseFeatures, BaseDatabaseOperations | ||||
|  | ||||
| def complain(*args, **kwargs): | ||||
|     raise ImproperlyConfigured, "You haven't set the DATABASE_ENGINE setting yet." | ||||
| @@ -21,13 +22,12 @@ class DatabaseError(Exception): | ||||
| class IntegrityError(DatabaseError): | ||||
|     pass | ||||
|  | ||||
| class ComplainOnGetattr(object): | ||||
|     def __getattr__(self, *args, **kwargs): | ||||
|         complain() | ||||
| class DatabaseOperations(BaseDatabaseOperations): | ||||
|     quote_name = complain | ||||
|  | ||||
| class DatabaseWrapper(object): | ||||
|     features = ComplainOnGetattr() | ||||
|     ops = ComplainOnGetattr() | ||||
|     features = BaseDatabaseFeatures() | ||||
|     ops = DatabaseOperations() | ||||
|     operators = {} | ||||
|     cursor = complain | ||||
|     _commit = complain | ||||
|   | ||||
| @@ -70,7 +70,7 @@ class DatabaseOperations(BaseDatabaseOperations): | ||||
|         return "DROP SEQUENCE %s;" % self.quote_name(get_sequence_name(table)) | ||||
|  | ||||
|     def field_cast_sql(self, db_type): | ||||
|         if db_type.endswith('LOB'): | ||||
|         if db_type and db_type.endswith('LOB'): | ||||
|             return "DBMS_LOB.SUBSTR(%s)" | ||||
|         else: | ||||
|             return "%s" | ||||
|   | ||||
| @@ -102,9 +102,6 @@ class DatabaseWrapper(BaseDatabaseWrapper): | ||||
|             cursor.execute("SET TIME ZONE %s", [settings.TIME_ZONE]) | ||||
|         cursor.execute("SET client_encoding to 'UNICODE'") | ||||
|         cursor = UnicodeCursorWrapper(cursor, 'utf-8') | ||||
|         if self.ops.postgres_version is None: | ||||
|             cursor.execute("SELECT version()") | ||||
|             self.ops.postgres_version = [int(val) for val in cursor.fetchone()[0].split()[1].split('.')] | ||||
|         return cursor | ||||
|  | ||||
| def typecast_string(s): | ||||
|   | ||||
| @@ -4,8 +4,17 @@ from django.db.backends import BaseDatabaseOperations | ||||
| # used by both the 'postgresql' and 'postgresql_psycopg2' backends. | ||||
|  | ||||
| class DatabaseOperations(BaseDatabaseOperations): | ||||
|     def __init__(self, postgres_version=None): | ||||
|         self.postgres_version = postgres_version | ||||
|     def __init__(self): | ||||
|         self._postgres_version = None | ||||
|  | ||||
|     def _get_postgres_version(self): | ||||
|         if self._postgres_version is None: | ||||
|             from django.db import connection | ||||
|             cursor = connection.cursor() | ||||
|             cursor.execute("SELECT version()") | ||||
|             self._postgres_version = [int(val) for val in cursor.fetchone()[0].split()[1].split('.')] | ||||
|         return self._postgres_version | ||||
|     postgres_version = property(_get_postgres_version) | ||||
|  | ||||
|     def date_extract_sql(self, lookup_type, field_name): | ||||
|         # http://www.postgresql.org/docs/8.0/static/functions-datetime.html#FUNCTIONS-DATETIME-EXTRACT | ||||
| @@ -52,28 +61,14 @@ class DatabaseOperations(BaseDatabaseOperations): | ||||
|             for sequence_info in sequences: | ||||
|                 table_name = sequence_info['table'] | ||||
|                 column_name = sequence_info['column'] | ||||
|                 if column_name and len(column_name)>0: | ||||
|                     # sequence name in this case will be <table>_<column>_seq | ||||
|                     sql.append("%s %s %s %s %s %s;" % \ | ||||
|                         (style.SQL_KEYWORD('ALTER'), | ||||
|                         style.SQL_KEYWORD('SEQUENCE'), | ||||
|                         style.SQL_FIELD(self.quote_name('%s_%s_seq' % (table_name, column_name))), | ||||
|                         style.SQL_KEYWORD('RESTART'), | ||||
|                         style.SQL_KEYWORD('WITH'), | ||||
|                         style.SQL_FIELD('1') | ||||
|                         ) | ||||
|                     ) | ||||
|                 if column_name and len(column_name) > 0: | ||||
|                     sequence_name = '%s_%s_seq' % (table_name, column_name) | ||||
|                 else: | ||||
|                     # sequence name in this case will be <table>_id_seq | ||||
|                     sql.append("%s %s %s %s %s %s;" % \ | ||||
|                         (style.SQL_KEYWORD('ALTER'), | ||||
|                          style.SQL_KEYWORD('SEQUENCE'), | ||||
|                          style.SQL_FIELD(self.quote_name('%s_id_seq' % table_name)), | ||||
|                          style.SQL_KEYWORD('RESTART'), | ||||
|                          style.SQL_KEYWORD('WITH'), | ||||
|                          style.SQL_FIELD('1') | ||||
|                          ) | ||||
|                     ) | ||||
|                     sequence_name = '%s_id_seq' % table_name | ||||
|                 sql.append("%s setval('%s', 1, false);" % \ | ||||
|                     (style.SQL_KEYWORD('SELECT'), | ||||
|                     style.SQL_FIELD(self.quote_name(sequence_name))) | ||||
|                 ) | ||||
|             return sql | ||||
|         else: | ||||
|             return [] | ||||
| @@ -106,4 +101,4 @@ class DatabaseOperations(BaseDatabaseOperations): | ||||
|                     style.SQL_KEYWORD('IS NOT'), | ||||
|                     style.SQL_KEYWORD('FROM'), | ||||
|                     style.SQL_TABLE(f.m2m_db_table()))) | ||||
|         return output | ||||
|         return output | ||||
|   | ||||
| @@ -64,7 +64,4 @@ class DatabaseWrapper(BaseDatabaseWrapper): | ||||
|         cursor.tzinfo_factory = None | ||||
|         if set_tz: | ||||
|             cursor.execute("SET TIME ZONE %s", [settings.TIME_ZONE]) | ||||
|         if self.ops.postgres_version is None: | ||||
|             cursor.execute("SELECT version()") | ||||
|             self.ops.postgres_version = [int(val) for val in cursor.fetchone()[0].split()[1].split('.')] | ||||
|         return cursor | ||||
|   | ||||
							
								
								
									
										39
									
								
								django/utils/version.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								django/utils/version.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,39 @@ | ||||
| import django | ||||
| import os.path | ||||
| import re | ||||
|  | ||||
| def get_svn_revision(path=None): | ||||
|     """ | ||||
|     Returns the SVN revision in the form SVN-XXXX, | ||||
|     where XXXX is the revision number. | ||||
|  | ||||
|     Returns SVN-unknown if anything goes wrong, such as an unexpected | ||||
|     format of internal SVN files. | ||||
|  | ||||
|     If path is provided, it should be a directory whose SVN info you want to | ||||
|     inspect. If it's not provided, this will use the root django/ package | ||||
|     directory. | ||||
|     """ | ||||
|     rev = None | ||||
|     if path is None: | ||||
|         path = django.__path__[0] | ||||
|     entries_path = '%s/.svn/entries' % path | ||||
|  | ||||
|     if os.path.exists(entries_path): | ||||
|         entries = open(entries_path, 'r').read() | ||||
|         # Versions >= 7 of the entries file are flat text.  The first line is | ||||
|         # the version number. The next set of digits after 'dir' is the revision. | ||||
|         if re.match('(\d+)', entries): | ||||
|             rev_match = re.search('\d+\s+dir\s+(\d+)', entries) | ||||
|             if rev_match: | ||||
|                 rev = rev_match.groups()[0] | ||||
|         # Older XML versions of the file specify revision as an attribute of | ||||
|         # the first entries node. | ||||
|         else: | ||||
|             from xml.dom import minidom | ||||
|             dom = minidom.parse(entries_path) | ||||
|             rev = dom.getElementsByTagName('entry')[0].getAttribute('revision') | ||||
|  | ||||
|     if rev: | ||||
|         return u'SVN-%s' % rev | ||||
|     return u'SVN-unknown' | ||||
| @@ -138,6 +138,29 @@ Examples: | ||||
|  | ||||
| You can pass in either an integer or a string representation of an integer. | ||||
|  | ||||
| naturalday | ||||
| ---------- | ||||
|  | ||||
| **New in Django development version** | ||||
|  | ||||
| For dates that are the current day or within one day, return "today", | ||||
| "tomorrow" or "yesterday", as appropriate. Otherwise, format the date using | ||||
| the passed in format string. | ||||
|  | ||||
| **Argument:** Date formatting string as described in default tag now_. | ||||
|  | ||||
| .. _now: ../templates/#now | ||||
|  | ||||
| Examples (when 'today' is 17 Feb 2007): | ||||
|  | ||||
|     * ``16 Feb 2007`` becomes ``yesterday``. | ||||
|     * ``17 Feb 2007`` becomes ``today``. | ||||
|     * ``18 Feb 2007`` becomes ``tomorrow``. | ||||
|     * Any other day is formatted according to given argument or the | ||||
|       `DATE_FORMAT`_ setting if no argument is given. | ||||
|  | ||||
| .. _DATE_FORMAT: ../settings/#date_format | ||||
|  | ||||
| flatpages | ||||
| ========= | ||||
|  | ||||
|   | ||||
| @@ -207,14 +207,23 @@ the database until you explicitly call ``save()``. | ||||
|  | ||||
| The ``save()`` method has no return value. | ||||
|  | ||||
| Updating ``ForeignKey`` fields works exactly the same way; simply assign an | ||||
| object of the right type to the field in question:: | ||||
| Saving ForeignKey and ManyToManyField fields | ||||
| -------------------------------------------- | ||||
|  | ||||
| Updating ``ForeignKey`` fields works exactly the same way as saving a normal | ||||
| field; simply assign an object of the right type to the field in question::  | ||||
|  | ||||
|     cheese_blog = Blog.objects.get(name="Cheddar Talk")  | ||||
|     entry.blog = cheese_blog  | ||||
|     entry.save()  | ||||
|  | ||||
| Updating a ``ManyToManyField`` works a little differently; use the ``add()`` | ||||
| method on the field to add a record to the relation:: | ||||
|  | ||||
|     joe = Author.objects.create(name="Joe") | ||||
|     entry.author = joe | ||||
|     entry.save() | ||||
|     entry.authors.add(joe) | ||||
|  | ||||
| Django will complain if you try to assign an object of the wrong type. | ||||
| Django will complain if you try to assign or add an object of the wrong type. | ||||
|  | ||||
| How Django knows to UPDATE vs. INSERT | ||||
| ------------------------------------- | ||||
|   | ||||
| @@ -124,6 +124,13 @@ executed. This means that all data will be removed from the database, any | ||||
| post-synchronization handlers will be re-executed, and the ``initial_data`` | ||||
| fixture will be re-installed. | ||||
|  | ||||
| The behavior of this command has changed in the Django development version. | ||||
| Previously, this command cleared *every* table in the database, including any | ||||
| table that Django didn't know about (i.e., tables that didn't have associated | ||||
| models and/or weren't in ``INSTALLED_APPS``). Now, the command only clears | ||||
| tables that are represented by Django models and are activated in | ||||
| ``INSTALLED_APPS``. | ||||
|  | ||||
| inspectdb | ||||
| --------- | ||||
|  | ||||
| @@ -240,6 +247,7 @@ Executes the equivalent of ``sqlreset`` for the given appnames. | ||||
|  | ||||
| runfcgi [options] | ||||
| ----------------- | ||||
|  | ||||
| Starts a set of FastCGI processes suitable for use with any web server | ||||
| which supports the FastCGI protocol. See the `FastCGI deployment | ||||
| documentation`_ for details. Requires the Python FastCGI module from | ||||
| @@ -337,7 +345,7 @@ Refer to the description of ``sqlcustom`` for an explanation of how to | ||||
| specify initial data. | ||||
|  | ||||
| sqlclear [appname appname ...] | ||||
| -------------------------------------- | ||||
| ------------------------------ | ||||
|  | ||||
| Prints the DROP TABLE SQL statements for the given appnames. | ||||
|  | ||||
| @@ -360,18 +368,23 @@ table modifications, or insert any SQL functions into the database. | ||||
|  | ||||
| Note that the order in which the SQL files are processed is undefined. | ||||
|  | ||||
| sqlflush | ||||
| -------- | ||||
|  | ||||
| Prints the SQL statements that would be executed for the `flush`_ command. | ||||
|  | ||||
| sqlindexes [appname appname ...] | ||||
| ---------------------------------------- | ||||
| -------------------------------- | ||||
|  | ||||
| Prints the CREATE INDEX SQL statements for the given appnames. | ||||
|  | ||||
| sqlreset [appname appname ...] | ||||
| -------------------------------------- | ||||
| ------------------------------ | ||||
|  | ||||
| Prints the DROP TABLE SQL, then the CREATE TABLE SQL, for the given appnames. | ||||
|  | ||||
| sqlsequencereset [appname appname ...] | ||||
| ---------------------------------------------- | ||||
| -------------------------------------- | ||||
|  | ||||
| Prints the SQL statements for resetting sequences for the given | ||||
| appnames. | ||||
|   | ||||
| @@ -204,10 +204,6 @@ out a few points, we want to make sure they reflect the final state of things | ||||
| at Django 1.0, not some intermediary step. In other words, we don't want to | ||||
| spend a lot of energy creating screencasts yet, because Django APIs will shift. | ||||
|  | ||||
| In the meantime, though, check out this `unofficial Django screencast`_. | ||||
|  | ||||
| .. _unofficial Django screencast: http://www.throwingbeans.org/django_screencasts.html | ||||
|  | ||||
| Is Django a content-management-system (CMS)? | ||||
| -------------------------------------------- | ||||
|  | ||||
|   | ||||
| @@ -344,7 +344,7 @@ development version. See the `Django 0.96 documentation`_ for the old behavior. | ||||
| ``ImageField`` | ||||
| ~~~~~~~~~~~~~~ | ||||
|  | ||||
| Like ``FileField``, but validates that the uploaded object is a valid | ||||
| Like `FileField`_, but validates that the uploaded object is a valid | ||||
| image. Has two extra optional arguments, ``height_field`` and | ||||
| ``width_field``, which, if set, will be auto-populated with the height and | ||||
| width of the image each time a model instance is saved. | ||||
|   | ||||
| @@ -1462,10 +1462,10 @@ commonly used groups of widgets: | ||||
|     ``Textarea``                  ``<textarea>...</textarea>`` | ||||
|     ``CheckboxInput``             ``<input type='checkbox' ...`` | ||||
|     ``Select``                    ``<select><option ...`` | ||||
|     ``NullBooleanSelect``         Select widget with options 'Unknown',  | ||||
|     ``NullBooleanSelect``         Select widget with options 'Unknown', | ||||
|                                   'Yes' and 'No' | ||||
|     ``SelectMultiple``            ``<select multiple='multiple'><option ...`` | ||||
|     ``RadioSelect``               ``<ul><li><input type='radio' ...``  | ||||
|     ``RadioSelect``               ``<ul><li><input type='radio' ...`` | ||||
|     ``CheckboxSelectMultiple``    ``<ul><li><input type='checkbox' ...`` | ||||
|     ``MultiWidget``               Wrapper around multiple other widgets | ||||
|     ``SplitDateTimeWidget``       Wrapper around two ``TextInput`` widgets: | ||||
| @@ -1476,19 +1476,19 @@ Specifying widgets | ||||
| ------------------ | ||||
|  | ||||
| Whenever you specify a field on a form, Django will use a default widget | ||||
| that is appropriate to the type of data that is to be displayed. To find  | ||||
| that is appropriate to the type of data that is to be displayed. To find | ||||
| which widget is used on which field, see the documentation for the | ||||
| built-in Field classes. | ||||
|  | ||||
| However, if you want to use a different widget for a field, you can -  | ||||
| However, if you want to use a different widget for a field, you can - | ||||
| just use the 'widget' argument on the field definition. For example:: | ||||
|  | ||||
|     class CommentForm(forms.Form): | ||||
|         name = forms.CharField() | ||||
|         url = forms.URLField() | ||||
|         comment = forms.CharField(widget=forms.Textarea) | ||||
|          | ||||
| This would specify a form with a comment that uses a larger Textarea widget,  | ||||
|  | ||||
| This would specify a form with a comment that uses a larger Textarea widget, | ||||
| rather than the default TextInput widget. | ||||
|  | ||||
| Customizing widget instances | ||||
| @@ -1499,8 +1499,8 @@ HTML - Django doesn't add a class definition, or any other widget-specific | ||||
| attributes. This means that all 'TextInput' widgets will appear the same | ||||
| on your web page. | ||||
|  | ||||
| If you want to make one widget look different to another, you need to  | ||||
| specify additional attributes for each widget. When you specify a  | ||||
| If you want to make one widget look different to another, you need to | ||||
| specify additional attributes for each widget. When you specify a | ||||
| widget, you can provide a list of attributes that will be added to the | ||||
| rendered HTML for the widget. | ||||
|  | ||||
| @@ -1522,13 +1522,13 @@ each widget will be rendered exactly the same:: | ||||
|     <tr><th>Comment:</th><td><input type="text" name="comment" /></td></tr> | ||||
|  | ||||
| On a real web page, you probably don't want every widget to look the same. You | ||||
| might want a larger input element for the comment, and you might want the  | ||||
| 'name' widget to have some special CSS class. To do this, you specify a  | ||||
| custom widget for your fields, and specify some attributes to use  | ||||
| might want a larger input element for the comment, and you might want the | ||||
| 'name' widget to have some special CSS class. To do this, you specify a | ||||
| custom widget for your fields, and specify some attributes to use | ||||
| when rendering those widgets:: | ||||
|  | ||||
|     class CommentForm(forms.Form): | ||||
|         name = forms.CharField(                    | ||||
|         name = forms.CharField( | ||||
|                     widget=forms.TextInput(attrs={'class':'special'})) | ||||
|         url = forms.URLField() | ||||
|         comment = forms.CharField( | ||||
| @@ -1546,19 +1546,19 @@ Custom Widgets | ||||
| -------------- | ||||
|  | ||||
| When you start to write a lot of forms, you will probably find that you will | ||||
| reuse certain sets of widget attributes over and over again. Rather than  | ||||
| repeat these attribute definitions every time you need them, Django allows  | ||||
| reuse certain sets of widget attributes over and over again. Rather than | ||||
| repeat these attribute definitions every time you need them, Django allows | ||||
| you to capture those definitions as a custom widget. | ||||
|  | ||||
| For example, if you find that you are including a lot of comment fields on forms, | ||||
| you could capture the idea of a ``TextInput`` with a specific ``size`` attribute  | ||||
| you could capture the idea of a ``TextInput`` with a specific ``size`` attribute | ||||
| as a custom extension to the ``TextInput`` widget:: | ||||
|  | ||||
|     class CommentWidget(forms.TextInput): | ||||
|         def __init__(self, *args, **kwargs): | ||||
|             kwargs.setdefault('attrs',{}).update({'size': '40'}) | ||||
|             super(forms.TextInput, self).__init__(*args, **kwargs) | ||||
|              | ||||
|             super(CommentWidget, self).__init__(*args, **kwargs) | ||||
|  | ||||
| Then you can use this widget in your forms:: | ||||
|  | ||||
|     class CommentForm(forms.Form): | ||||
| @@ -1566,8 +1566,8 @@ Then you can use this widget in your forms:: | ||||
|         url = forms.URLField() | ||||
|         comment = forms.CharField(widget=CommentWidget) | ||||
|  | ||||
| You can even customize your custom widget, in the same way as you would  | ||||
| any other widget. Adding a once-off class to your ``CommentWidget`` is as  | ||||
| You can even customize your custom widget, in the same way as you would | ||||
| any other widget. Adding a once-off class to your ``CommentWidget`` is as | ||||
| simple as adding an attribute definition:: | ||||
|  | ||||
|     class CommentForm(forms.Form): | ||||
| @@ -1582,14 +1582,14 @@ by defining:: | ||||
|  | ||||
|     class CommentInput(forms.CharField): | ||||
|         widget = CommentWidget | ||||
|          | ||||
|  | ||||
| You can then use this field whenever you have a form that requires a comment:: | ||||
|  | ||||
|     class CommentForm(forms.Form): | ||||
|         name = forms.CharField() | ||||
|         url = forms.URLField() | ||||
|         comment = CommentInput() | ||||
|          | ||||
|  | ||||
| Generating forms for models | ||||
| =========================== | ||||
|  | ||||
| @@ -1934,6 +1934,42 @@ will raise ``ValueError`` if the data doesn't validate. | ||||
| ``form_for_instance()`` has ``form``, ``fields`` and ``formfield_callback`` | ||||
| arguments that behave the same way as they do for ``form_for_model()``. | ||||
|  | ||||
| Let's modify the earlier `contact form`_ view example a little bit. Suppose we | ||||
| have a ``Message`` model that holds each contact submission. Something like:: | ||||
|  | ||||
|     class Message(models.Model): | ||||
|         subject = models.CharField(max_length=100) | ||||
|         message = models.TextField() | ||||
|         sender = models.EmailField() | ||||
|         cc_myself = models.BooleanField() | ||||
|  | ||||
| You could use this model to create a form (using ``form_for_model()``). You | ||||
| could also use existing ``Message`` instances to create a form for editing | ||||
| messages. The earlier_ view can be changed slightly to accept the ``id`` value | ||||
| of an existing ``Message`` and present it for editing:: | ||||
|  | ||||
|     def contact_edit(request, msg_id): | ||||
|         # Create the form from the message id. | ||||
|         message = get_object_or_404(Message, id=msg_id) | ||||
|         ContactForm = form_for_instance(message) | ||||
|  | ||||
|         if request.method == 'POST': | ||||
|             form = ContactForm(request.POST) | ||||
|             if form.is_valid(): | ||||
|                 form.save() | ||||
|                 return HttpResponseRedirect('/url/on_success/') | ||||
|         else: | ||||
|             form = ContactForm() | ||||
|         return render_to_response('contact.html', {'form': form}) | ||||
|  | ||||
| Aside from how we create the ``ContactForm`` class here, the main point to | ||||
| note is that the form display in the ``GET`` branch of the function | ||||
| will use the values from the ``message`` instance as initial values for the | ||||
| form field. | ||||
|  | ||||
| .. _contact form: `Simple view example`_ | ||||
| .. _earlier: `Simple view example`_ | ||||
|  | ||||
| When should you use ``form_for_model()`` and ``form_for_instance()``? | ||||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||||
|  | ||||
|   | ||||
| @@ -1101,10 +1101,11 @@ To disable this behavior, just remove all entries from the ``ADMINS`` setting. | ||||
| 404 errors | ||||
| ---------- | ||||
|  | ||||
| When ``DEBUG`` is ``False`` and your ``MIDDLEWARE_CLASSES`` setting includes | ||||
| ``CommonMiddleware``, Django will e-mail the users listed in the ``MANAGERS`` | ||||
| setting whenever your code raises a 404 and the request has a referer. | ||||
| (It doesn't bother to e-mail for 404s that don't have a referer.) | ||||
| When ``DEBUG`` is ``False``, ``SEND_BROKEN_LINK_EMAILS`` is ``True`` and your | ||||
| ``MIDDLEWARE_CLASSES`` setting includes ``CommonMiddleware``, Django will | ||||
| e-mail the users listed in the ``MANAGERS`` setting whenever your code raises | ||||
| a 404 and the request has a referer. (It doesn't bother to e-mail for 404s | ||||
| that don't have a referer.) | ||||
|  | ||||
| You can tell Django to stop reporting particular 404s by tweaking the | ||||
| ``IGNORABLE_404_ENDS`` and ``IGNORABLE_404_STARTS`` settings. Both should be a | ||||
|   | ||||
| @@ -473,7 +473,7 @@ Once you have a ``Client`` instance, you can call any of the following methods: | ||||
|     data. For example:: | ||||
|  | ||||
|         >>> c = Client() | ||||
|         >>> c.get('/login/', {'name': 'fred', 'passwd': 'secret'}) | ||||
|         >>> c.post('/login/', {'name': 'fred', 'passwd': 'secret'}) | ||||
|  | ||||
|     ...will result in the evaluation of a POST request to this URL:: | ||||
|  | ||||
|   | ||||
| @@ -259,6 +259,22 @@ These concepts are represented by simple Python classes. Edit the | ||||
|         choice = models.CharField(max_length=200) | ||||
|         votes = models.IntegerField() | ||||
|  | ||||
| .. adminition:: Errors about ``max_length`` | ||||
|  | ||||
|    If Django gives you an error message saying that ``max_length`` is | ||||
|    not a valid argument, you're most likely using an old version of | ||||
|    Django. (This version of the tutorial is written for the latest | ||||
|    development version of Django.) If you're using a Subversion checkout | ||||
|    of Django's development version (see `the installation docs`_ for | ||||
|    more information), you shouldn't have any problems. | ||||
|  | ||||
|    If you want to stick with an older version of Django, you'll want to | ||||
|    switch to `the Django 0.96 tutorial`_, because this tutorial covers | ||||
|    several features that only exist in the Django development version. | ||||
|  | ||||
| .. _the installation docs: ../install/ | ||||
| .. _the Django 0.96 tutorial: ../0.96/tutorial01/ | ||||
|  | ||||
| The code is straightforward. Each model is represented by a class that | ||||
| subclasses ``django.db.models.Model``. Each model has a number of class | ||||
| variables, each of which represents a database field in the model. | ||||
| @@ -487,6 +503,23 @@ the ``polls/models.py`` file) and adding a ``__unicode__()`` method to both | ||||
|         def __unicode__(self): | ||||
|             return self.choice | ||||
|  | ||||
| .. admonition:: If ``__unicode__()`` doesn't seem to work | ||||
|  | ||||
|    If you add the ``__unicode__()`` method to your models and don't | ||||
|    see any change in how they're represented, you're most likely using | ||||
|    an old version of Django. (This version of the tutorial is written | ||||
|    for the latest development version of Django.) If you're using a | ||||
|    Subversion checkout of of Django's development version (see `the | ||||
|    installation docs`_ for more information), you shouldn't have any | ||||
|    problems. | ||||
|  | ||||
|    If you want to stick with an older version of Django, you'll want to | ||||
|    switch to `the Django 0.96 tutorial`_, because this tutorial covers | ||||
|    several features that only exist in the Django development version. | ||||
|  | ||||
| .. _the installation docs: ../install/ | ||||
| .. _the Django 0.96 tutorial: ../0.96/tutorial01/ | ||||
|  | ||||
| It's important to add ``__unicode__()`` methods to your models, not only for | ||||
| your own sanity when dealing with the interactive prompt, but also because | ||||
| objects' representations are used throughout Django's automatically-generated | ||||
|   | ||||
| @@ -1,5 +1,8 @@ | ||||
| import unittest | ||||
| from datetime import timedelta, date | ||||
| from django.template import Template, Context, add_to_builtins | ||||
| from django.utils.dateformat import DateFormat | ||||
| from django.utils.translation import ugettext as _ | ||||
|  | ||||
| add_to_builtins('django.contrib.humanize.templatetags.humanize') | ||||
|  | ||||
| @@ -8,13 +11,12 @@ class HumanizeTests(unittest.TestCase): | ||||
|     def humanize_tester(self, test_list, result_list, method): | ||||
|         # Using max below ensures we go through both lists | ||||
|         # However, if the lists are not equal length, this raises an exception | ||||
|         for index in xrange(len(max(test_list,result_list))): | ||||
|         for index in xrange(max(len(test_list), len(result_list))): | ||||
|             test_content = test_list[index] | ||||
|             t = Template('{{ test_content|%s }}' % method) | ||||
|             rendered = t.render(Context(locals())).strip() | ||||
|             self.assertEqual(rendered, result_list[index], | ||||
|                              msg="""%s test failed, produced %s, | ||||
| should've produced %s""" % (method, rendered, result_list[index])) | ||||
|                              msg="%s test failed, produced %s, should've produced %s" % (method, rendered, result_list[index])) | ||||
|  | ||||
|     def test_ordinal(self): | ||||
|         test_list = ('1','2','3','4','11','12', | ||||
| @@ -49,6 +51,20 @@ should've produced %s""" % (method, rendered, result_list[index])) | ||||
|  | ||||
|         self.humanize_tester(test_list, result_list, 'apnumber') | ||||
|  | ||||
|     def test_naturalday(self): | ||||
|         from django.template import defaultfilters | ||||
|         today = date.today() | ||||
|         yesterday = today - timedelta(days=1) | ||||
|         tomorrow = today + timedelta(days=1) | ||||
|         someday = today - timedelta(days=10) | ||||
|         notdate = u"I'm not a date value" | ||||
|  | ||||
|         test_list = (today, yesterday, tomorrow, someday, notdate) | ||||
|         someday_result = defaultfilters.date(someday) | ||||
|         result_list = (_(u'today'), _(u'yesterday'), _(u'tomorrow'), | ||||
|                        someday_result, u"I'm not a date value") | ||||
|         self.humanize_tester(test_list, result_list, 'naturalday') | ||||
|  | ||||
| if __name__ == '__main__': | ||||
|     unittest.main() | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user