mirror of
https://github.com/django/django.git
synced 2025-07-04 09:49:12 +00:00
Merged revisions 4350-4357,4359-4365,4371-4372,4374-4377,4380-4386,4388,4390-4391,4400-4402,4404-4408,4410,4412-4419,4426-4427,4430-4432,4434,4441,4443-4444,4446-4447,4450,4452-4453,4455-4458,4476,4503,4546,4564-4569,4580-4586,4617,4630,4641-4643,4653-4655,4657,4669,4673-4675,4694-4696,4713-4714,4720-4723,4725-4732,4735-4741,4750,4755,4758,4769-4770,4776-4777,4783-4795,4798,4805-4808,4810,4813-4815,4817,4824,4836,4838-4843,4851-4855,4869,4872,4882-4884,4906,4916,4935-4936,4940-4944,4946-4953,4962-4963,4969,4971-4973,4990,4994-4997,5000-5003,5006-5008,5013-5014,5019-5024,5026-5036,5046-5047,5054-5059,5062,5079,5081-5083,5090,5100-5101,5114,5122-5123,5126,5128,5134-5136,5148-5149,5151,5157,5174,5178,5183-5185,5192-5195,5197-5200,5203,5205,5208,5214,5223-5224,5226-5227,5229-5230,5235-5236,5238-5244,5246-5249,5251,5254-5262,5266-5280,5282-5284,5286,5301,5307,5309-5310,5312,5314-5317,5319-5332,5334-5345,5372-5378,5381-5382,5384,5386,5388-5390,5393-5397,5399-5400,5416,5419-5430,5440-5441,5444-5448,5461-5464,5467,5473-5481,5487-5489,5491-5492,5498-5499,5507-5510,5512,5527,5529,5531-5535,5540-5541,5546,5570,5572-5574,5576-5578,5580-5581,5583-5589,5591,5595-5597,5601-5608,5613,5626-5826 via svnmerge from
http://code.djangoproject.com/svn/django/trunk ........ r5626 | russellm | 2007-07-07 10:16:23 +0800 (Sat, 07 Jul 2007) | 2 lines Added some uncredited authors that worked on the Oracle branch. ........ r5629 | mtredinnick | 2007-07-08 01:15:54 +0800 (Sun, 08 Jul 2007) | 8 lines Changed HttpRequest.path to be a Unicode object. It has already been URL-decoded by the time we see it anyway, so keeping it as a UTF-8 bytestring was causing unnecessary problems. Also added handling for non-ASCII URL fragments in feed creation (the portion that was outside the control of the Feed class was messed up). ........ r5630 | mtredinnick | 2007-07-08 02:24:27 +0800 (Sun, 08 Jul 2007) | 4 lines Fixed #4772 -- Fixed reverse URL creation to work with non-ASCII arguments. Also included a test for non-ASCII strings in URL patterns, although that already worked correctly. ........ r5631 | mtredinnick | 2007-07-08 02:39:23 +0800 (Sun, 08 Jul 2007) | 3 lines Corrected misleading comment from [5619]. Not sure what I was smoking at the time. ........ r5632 | mtredinnick | 2007-07-08 08:39:32 +0800 (Sun, 08 Jul 2007) | 5 lines Fixed reverse URL lookup using functions when the original URL pattern was a string. This is now just as fragile as it was prior to [5609], but works in a few cases that people were relying on, apparently. ........ r5636 | mtredinnick | 2007-07-08 19:22:53 +0800 (Sun, 08 Jul 2007) | 4 lines Fixed #4798-- Made sure that function keyword arguments are strings (for the keywords themselves) when using Unicode URL patterns. ........ r5638 | gwilson | 2007-07-10 10:34:42 +0800 (Tue, 10 Jul 2007) | 2 lines Fixed #4817 -- Removed leading forward slashes from some urlconf examples in the documentation. ........ r5639 | gwilson | 2007-07-10 10:45:11 +0800 (Tue, 10 Jul 2007) | 2 lines Fixed #4814 -- Fixed some whitespace issues in tutorial01, thanks John Shaffer. ........ r5640 | gwilson | 2007-07-10 11:26:26 +0800 (Tue, 10 Jul 2007) | 2 lines Fixed #4812 -- Fixed an octal escape in regular expression that is used in the `isValidEmail` validator, thanks batchman@free.fr. ........ r5641 | mtredinnick | 2007-07-10 20:02:06 +0800 (Tue, 10 Jul 2007) | 3 lines Fixed #4823 -- Fixed a Python 2.3 incompatibility from [5636] (it was even demonstrated by existing tests, so I really screwed this up). ........ r5642 | mtredinnick | 2007-07-10 20:03:36 +0800 (Tue, 10 Jul 2007) | 3 lines Fixed #4804 -- Fixed a problem when validating choice lists with non-ASCII data. Thanks, django@vonposer.de. ........ r5643 | mtredinnick | 2007-07-10 20:33:55 +0800 (Tue, 10 Jul 2007) | 4 lines Fixed #3760 -- Added the ability to manually set feed- and item-level id elements in Atom feeds. This is fully backwards compatible. Based on a patch from spark343@cs.ubc.ca. ........ r5644 | mtredinnick | 2007-07-11 14:55:12 +0800 (Wed, 11 Jul 2007) | 3 lines Fixed #4815 -- Fixed decoding of request parameters when the input encoding is not UTF-8. Thanks, Jordan Dimov. ........ r5645 | mtredinnick | 2007-07-11 15:00:27 +0800 (Wed, 11 Jul 2007) | 3 lines Fixed #4802 -- Updated French translation. Combined contribution from baptiste.goupil@gmail.com and rocherl@club-internet.fr. ........ r5646 | mtredinnick | 2007-07-11 15:12:50 +0800 (Wed, 11 Jul 2007) | 2 lines Fixed #4753 -- Small update to Spanish translation from Mario Gonzalez. ........ r5649 | jacob | 2007-07-12 08:33:44 +0800 (Thu, 12 Jul 2007) | 1 line Fixed #4615: corrected reverse URL resolution examples in tutorial 4. Thanks for the patch, simeonf. ........ r5650 | adrian | 2007-07-12 12:43:29 +0800 (Thu, 12 Jul 2007) | 1 line Added 'New in Django development version' note to docs/syndication_feeds.txt changes from [5643] ........ r5651 | adrian | 2007-07-12 12:44:45 +0800 (Thu, 12 Jul 2007) | 1 line Edited changes to docs/tutorial04.txt from [5649] ........ r5652 | adrian | 2007-07-12 13:23:47 +0800 (Thu, 12 Jul 2007) | 1 line Added helpful error message to SiteManager.get_current() if the user hasn't set SITE_ID ........ r5653 | adrian | 2007-07-12 13:28:04 +0800 (Thu, 12 Jul 2007) | 1 line Added RequestSite class to sites framework ........ r5654 | adrian | 2007-07-12 13:29:32 +0800 (Thu, 12 Jul 2007) | 1 line Improved syndication feed framework to use RequestSite if the sites framework is not installed -- i.e., the sites framework is no longer required to use the syndication feed framework. This is backwards incompatible if anybody has subclassed Feed and overridden __init__(), because the second parameter is now expected to be an HttpRequest object instead of request.path ........ r5658 | russellm | 2007-07-12 15:45:35 +0800 (Thu, 12 Jul 2007) | 2 lines Fixed #4459 -- Added 'raw' argument to save method, to override any pre-save processing, and modified serializers to use a raw-save. This enables serialization of DateFields with auto_now/auto_now_add. Also modified serializers to invoke save() directly on the model baseclass, to avoid any (potentially order-dependent, data modifying) behavior in a custom save() method. ........ r5659 | russellm | 2007-07-12 19:24:16 +0800 (Thu, 12 Jul 2007) | 2 lines Fixed #3770 -- Remove null=True tag from OneToOne serialization test. OneToOne fields can't have a value of null. ........ r5660 | russellm | 2007-07-12 19:27:38 +0800 (Thu, 12 Jul 2007) | 2 lines Fixed #3768 -- Disabled NullBooleanField PK serialization test. We can't and don't test null PK values. ........ r5662 | russellm | 2007-07-12 20:33:24 +0800 (Thu, 12 Jul 2007) | 2 lines Fixed #4837 -- Updated Debian packaging details. Thanks for the suggestion, Yasushi Masuda <whosaysni@gmail.com>. ........ r5663 | russellm | 2007-07-12 20:44:05 +0800 (Thu, 12 Jul 2007) | 2 lines Fixed #4808 -- Added Chilean regions in localflavor. Thanks, Marijn Vriens <marijn@metronomo.cl>. ........ r5664 | russellm | 2007-07-12 20:48:27 +0800 (Thu, 12 Jul 2007) | 2 lines Fixed #4745 -- Updated docs to point out that 0 is not a valid SITE_ID when running the tests. Thanks for the suggestion, Lars Stavholm <stava@telcotec.se>. ........ r5665 | russellm | 2007-07-12 20:50:02 +0800 (Thu, 12 Jul 2007) | 2 lines Fixed #4763 -- Minor typo in cache documentations. Thanks, dan@coffeecode.net. ........ r5666 | russellm | 2007-07-12 20:55:28 +0800 (Thu, 12 Jul 2007) | 2 lines Fixed #4627 -- Added details on MacPorts packaging of Django. Thanks, Paul Bissex. ........ r5667 | russellm | 2007-07-12 21:23:11 +0800 (Thu, 12 Jul 2007) | 2 lines Fixed #4640 -- Fixed import to stringfilter in docs. Proposed solution to move stringfilter into django.template.__init__ introduces a circular import problem. ........ r5668 | russellm | 2007-07-12 21:32:00 +0800 (Thu, 12 Jul 2007) | 2 lines Fixed #4722 -- Clarified discussion about PYTHONPATH in modpython docs. Thanks for the suggestion, Collin Grady <cgrady@the-magi.us>. ........ r5669 | russellm | 2007-07-12 21:37:59 +0800 (Thu, 12 Jul 2007) | 2 lines Fixed #4755 -- Modified newforms MultipleChoiceField to use list comprehension, rather than iteration. ........ r5670 | russellm | 2007-07-12 21:41:27 +0800 (Thu, 12 Jul 2007) | 2 lines Fixed #4764 -- Added reference to Locale middleware in middleware docs. Thanks, dan@coffeecode.net. ........ r5671 | russellm | 2007-07-12 21:55:19 +0800 (Thu, 12 Jul 2007) | 2 lines Fixed #4768 -- Converted timesince and dateformat to use explicit floor division (pre-emptive avoidance of Python 3000 compatibility problem), and removed a redundant millisecond check. Thanks, John Shaffer <jshaffer2112@gmail.com>. ........ r5672 | russellm | 2007-07-12 22:00:13 +0800 (Thu, 12 Jul 2007) | 2 lines Fixed #4775 -- Added some missing Hungarian accents to the urlify.js LATIN_MAP. Thanks, Pistahh <szekeres@iii.hu>. ........ r5673 | russellm | 2007-07-12 22:05:16 +0800 (Thu, 12 Jul 2007) | 2 lines Fixed #4502 -- Clarified reference to view in tutorial. Thanks for the suggestion, Carl Karsten <carl@personnelware.com>. ........ r5674 | russellm | 2007-07-12 22:11:41 +0800 (Thu, 12 Jul 2007) | 2 lines Fixed #4522 -- Clarified the allowed filter arguments on the time and date filters. Thanks for the suggestion, admackin@gmail.com. ........ r5675 | russellm | 2007-07-12 22:21:51 +0800 (Thu, 12 Jul 2007) | 2 lines Fixed #4525 -- Fixed mistaken documentation on arguments to runfcgi. Thanks, Johan Bergstrom <bugs@bergstroem.nu>. ........ r5676 | russellm | 2007-07-12 22:41:32 +0800 (Thu, 12 Jul 2007) | 2 lines Fixed #4538 -- Split the installation instructions to differentiate between installing a distribution package and installing an official release. Thanks to Carl Karsten for the idea, and Paul Bissex for the patch. ........ r5677 | russellm | 2007-07-12 23:26:37 +0800 (Thu, 12 Jul 2007) | 2 lines Fixed #4526 -- Modified the test Client login method to fail when a user is inactive. Thanks, marcin@elksoft.pl. ........ r5678 | russellm | 2007-07-13 13:03:33 +0800 (Fri, 13 Jul 2007) | 2 lines Fixed #3505 -- Added handling for the error raised when the user forgets the comma in a single element tuple when defining AUTHENTICATION_BACKENDS. Thanks for the help identifying this problem, Mario Gonzalez <gonzalemario@gmail.com>. ........ r5679 | mtredinnick | 2007-07-13 16:52:07 +0800 (Fri, 13 Jul 2007) | 3 lines Fixed #2591 -- Fixed a problem with inspectdb with psycopg2 (only). Patch from Gary Wilson. ........ r5680 | mtredinnick | 2007-07-13 17:09:59 +0800 (Fri, 13 Jul 2007) | 3 lines Fixed #4807 -- Fixed a couple of corner cases in decimal form input validation. Based on a suggestion from Chriss Moffit. ........ r5681 | mtredinnick | 2007-07-13 17:14:51 +0800 (Fri, 13 Jul 2007) | 3 lines Fixed #4839 -- Added __repr__ methods to URL classes that show the pattern they contain. Thanks, Thomas G?\195?\188ttler. ........ r5682 | mtredinnick | 2007-07-13 18:56:30 +0800 (Fri, 13 Jul 2007) | 3 lines Fixed #4842 -- Added slightly more robust error reporting. Thanks, Thomas G?\195?\188ttler. ........ r5683 | mtredinnick | 2007-07-13 19:05:01 +0800 (Fri, 13 Jul 2007) | 3 lines Fixed #4846 -- Fixed some Python 2.3 encoding problems in the admin interface. Based on a patch from daybreaker12@gmail.com. ........ r5684 | mtredinnick | 2007-07-13 20:03:20 +0800 (Fri, 13 Jul 2007) | 3 lines Fixed #4861 -- Removed some duplicated logic from the newforms RegexField by making it a subclass of CharField. Thanks, Collin Grady. ........ r5685 | mtredinnick | 2007-07-13 21:15:35 +0800 (Fri, 13 Jul 2007) | 3 lines Fixed #4865 -- Replaced a stray generator comprehension with a list comprehension so that we don't break Python 2.3. ........ r5686 | mtredinnick | 2007-07-13 22:13:35 +0800 (Fri, 13 Jul 2007) | 3 lines Fixed #4469 -- Added slightly more informative error messages to max- and min-length newform validation. Based on a patch from A. Murat Eren. ........ r5687 | mtredinnick | 2007-07-13 22:14:47 +0800 (Fri, 13 Jul 2007) | 2 lines Added author credit for [5686]. Refs #4469. ........ r5688 | mtredinnick | 2007-07-13 22:33:46 +0800 (Fri, 13 Jul 2007) | 3 lines Fixed #4484 -- Fixed APPEND_SLASH handling to handle an empty path value. Thanks, VesselinK. ........ r5689 | mtredinnick | 2007-07-13 22:40:39 +0800 (Fri, 13 Jul 2007) | 2 lines Fixed #4556 -- Stylistic changes to [5500]. Thanks, glin@seznam.cz. ........ r5690 | gwilson | 2007-07-14 04:36:01 +0800 (Sat, 14 Jul 2007) | 2 lines Refs #2591 -- Removed int conversion and try/except since the value in the single-item list is already an int. I overlooked this in my original patch, which was applied in [5679]. ........ r5691 | adrian | 2007-07-14 05:20:07 +0800 (Sat, 14 Jul 2007) | 1 line Documented the 'commit' argument to save() methods on forms created via form_for_model() or form_for_instance() ........ r5692 | mtredinnick | 2007-07-14 13:27:22 +0800 (Sat, 14 Jul 2007) | 3 lines Fixed #4869 -- Added a note that syncdb does not alter existing tables. Thanks, James Bennett. ........ r5693 | mtredinnick | 2007-07-14 20:48:24 +0800 (Sat, 14 Jul 2007) | 3 lines Fixed #4863 -- Removed comment references to a no-longer present link. Pointed out by Thomas G?\195?\188ttler. ........ r5694 | mtredinnick | 2007-07-14 21:14:28 +0800 (Sat, 14 Jul 2007) | 2 lines Fixed #4862 -- Fixed invalid Javascript creation in popup windows in admin. ........ r5695 | mtredinnick | 2007-07-14 21:39:41 +0800 (Sat, 14 Jul 2007) | 2 lines Fixed a problem with translatable strings from [5686]. ........ r5696 | mtredinnick | 2007-07-14 22:47:14 +0800 (Sat, 14 Jul 2007) | 3 lines Fixed #4731 -- Changed management.setup_environ() so that it no longer assumes the settings module is called "settings". Patch from SmileyChris. ........ r5697 | mtredinnick | 2007-07-14 22:50:35 +0800 (Sat, 14 Jul 2007) | 3 lines Fixed #4870 -- Removed unneeded import and fixed a docstring in an example. Thanks, Collin Grady. ........ r5698 | adrian | 2007-07-15 00:58:54 +0800 (Sun, 15 Jul 2007) | 1 line Edited docs/db-api.txt changes from [5658] ........ r5699 | adrian | 2007-07-15 01:04:30 +0800 (Sun, 15 Jul 2007) | 1 line Negligible capitalization fix in test/client.py docstring ........ r5700 | russellm | 2007-07-15 12:41:59 +0800 (Sun, 15 Jul 2007) | 2 lines Clarified the documentation on the steps that happen during a save, and how raw save affects those steps. ........ r5701 | gwilson | 2007-07-15 13:03:28 +0800 (Sun, 15 Jul 2007) | 2 lines Fixed #4310 -- Fixed a regular expression bug in `strip_entities` function and added tests for several `django.utils.html` functions. Based on patch from Brian Harring. ........ r5702 | gwilson | 2007-07-15 13:11:06 +0800 (Sun, 15 Jul 2007) | 2 lines Fixed #4877 -- Fixed typo in testing documentation, patch from John Shaffer. ........ r5703 | gwilson | 2007-07-15 14:24:54 +0800 (Sun, 15 Jul 2007) | 2 lines Fixed #3012 -- Changed the locmem cache backend to use pickle instead of deepcopy to make it compatible with iterators (which cannot be copied). Patch from Sundance. ........ r5704 | gwilson | 2007-07-15 14:29:45 +0800 (Sun, 15 Jul 2007) | 2 lines Changed imports to adhere to PEP 8. ........ r5705 | mtredinnick | 2007-07-15 17:39:13 +0800 (Sun, 15 Jul 2007) | 3 lines Fixed #4880 -- Updated Spanish translation (includes re-encoding to UTF-8). Thanks, Jorge Gajon. ........ r5706 | mtredinnick | 2007-07-15 17:46:42 +0800 (Sun, 15 Jul 2007) | 3 lines Fixed #4882 -- Updated Argentinean Spanish translation (includes re-encoding to UTF-8). Thanks, Ramiro Morales. ........ r5707 | mtredinnick | 2007-07-15 18:08:05 +0800 (Sun, 15 Jul 2007) | 3 lines Re-encoded djangojs.po for French and German locales to UTF-8. These were the last two non-UTF-8 PO files. ........ r5708 | mtredinnick | 2007-07-15 18:10:44 +0800 (Sun, 15 Jul 2007) | 6 lines Fixed #4734 -- Changed message extraction to permit non-ACSII msgid strings. Thanks, krzysiek.pawlik@silvermedia.pl. This is slightly backwards-incompatible for translators: PO files are now assumed to be in UTF-8 encoding. ........ r5709 | adrian | 2007-07-16 03:34:21 +0800 (Mon, 16 Jul 2007) | 1 line Edited docs/db-api.txt changes from [5700] ........ r5710 | adrian | 2007-07-16 05:16:32 +0800 (Mon, 16 Jul 2007) | 1 line Improved docs/templates.txt section on the 'regroup' tag ........ r5711 | mtredinnick | 2007-07-16 11:48:03 +0800 (Mon, 16 Jul 2007) | 2 lines Updated AUTHORS for [5708]. ........ r5712 | mtredinnick | 2007-07-16 11:50:22 +0800 (Mon, 16 Jul 2007) | 3 lines Fixed #4199 -- Changed date formatting in HTTP expires header to be spec compliant. Thanks, Chris Bennett. ........ r5713 | mtredinnick | 2007-07-16 12:45:45 +0800 (Mon, 16 Jul 2007) | 3 lines Fixed #4884 -- Fixed an initialisation problem when assigned to settings before accessing them. Thanks, Noam Raphael. ........ r5714 | mtredinnick | 2007-07-16 12:47:52 +0800 (Mon, 16 Jul 2007) | 2 lines Fixed #4806 -- Updated Simplified Chinese translation. Thanks, limodou. ........ r5715 | mtredinnick | 2007-07-16 12:54:49 +0800 (Mon, 16 Jul 2007) | 3 lines Fixed #4887 -- Fixed another place where template tag arguments are used directly as function keyword args. Thanks, Brian Rosner. ........ r5716 | gwilson | 2007-07-16 13:00:18 +0800 (Mon, 16 Jul 2007) | 2 lines Refs #3012 -- Removed iterator from `test_data_types` cache test that I added in [5703]. Iterators cannot be pickled either. Left the rest of [5703] there though since it fixed another issue that was causing the `test_data_types` cache test to fail with the `locmem` cache backend, the fact that functions cannot be copied. ........ r5717 | gwilson | 2007-07-16 13:28:13 +0800 (Mon, 16 Jul 2007) | 2 lines Cleaned up a couple unused imports and fixed docstrings to follow Python Style Guide. ........ r5718 | mtredinnick | 2007-07-16 17:36:10 +0800 (Mon, 16 Jul 2007) | 3 lines Fixed #4845 -- Fixed some problems with Unicode usage and caching. Thanks, Jeremy Dunck. ........ r5719 | gwilson | 2007-07-16 21:47:43 +0800 (Mon, 16 Jul 2007) | 2 lines Removed unused variable and changed comments about `permalink` decorator into a docstring. ........ r5720 | gwilson | 2007-07-17 06:29:09 +0800 (Tue, 17 Jul 2007) | 2 lines Fixed #4851 -- Fixed description of an example query in `db-api` docs. ........ r5721 | mtredinnick | 2007-07-17 12:22:11 +0800 (Tue, 17 Jul 2007) | 2 lines Fixed #4898 -- Fixed a precendence problem when constructing HTTP Date header. ........ r5722 | mtredinnick | 2007-07-17 18:25:43 +0800 (Tue, 17 Jul 2007) | 3 lines Fixed #4899 -- Fixed a problem with PO file header generation caused by [5708]. Thanks, Ramiro Morales. ........ r5723 | mtredinnick | 2007-07-19 17:23:45 +0800 (Thu, 19 Jul 2007) | 2 lines Fixed #4917 -- Updated Swedish translation. Thanks, Pilip Lindborg. ........ r5724 | mtredinnick | 2007-07-19 17:24:36 +0800 (Thu, 19 Jul 2007) | 2 lines Fixed #3925 -- Added Slovak localflavor items. Thanks, Martin Kos?\195?\173r. ........ r5725 | adrian | 2007-07-20 14:28:56 +0800 (Fri, 20 Jul 2007) | 1 line Added a db_type() method to the database Field class. This is a hook for calculating the database column type for a given Field. Also converted all management.py CREATE TABLE statements to use db_type(), which made that code cleaner. The Field.get_internal_type() hook still exists, but we should consider removing it at some point, because db_type() is more general. Also added docs -- the beginnings of docs on how to create custom database Field classes. This is backwards-compatible. ........ r5726 | adrian | 2007-07-20 14:34:26 +0800 (Fri, 20 Jul 2007) | 1 line Simplified the indent level in management.py _get_sql_model_create() by using a 'continue' statement rather than nesting everything in an 'if' ........ r5727 | russellm | 2007-07-20 20:07:58 +0800 (Fri, 20 Jul 2007) | 2 lines Fixed #4558 -- Modified XML serializer to handle whitespace better around None tags. Thanks to Bill Fenner <fenner@gmail.com> for the report and fix. ........ r5728 | russellm | 2007-07-20 20:15:02 +0800 (Fri, 20 Jul 2007) | 2 lines Fixed #4897 -- Fixed minor typo in doctest comment. ........ r5729 | russellm | 2007-07-20 21:57:49 +0800 (Fri, 20 Jul 2007) | 2 lines Fixed #3782 -- Added support for the suite() method recommended by the Python unittest docs. Thanks for the suggestion, rene.puls@repro-mayr.de. ........ r5730 | russellm | 2007-07-20 22:07:54 +0800 (Fri, 20 Jul 2007) | 2 lines Refs #3782 -- Added documentation note that suite() handling is only in development version. ........ r5731 | russellm | 2007-07-20 22:32:20 +0800 (Fri, 20 Jul 2007) | 2 lines Fixed #4901 -- Modified assertContains to provide a default check of 'any instances of text in content'. Thanks for the suggestion, nis@superlativ.dk. ........ r5732 | russellm | 2007-07-20 22:42:57 +0800 (Fri, 20 Jul 2007) | 2 lines Fixed #4738 -- Modified the prompt that is displayed when a test database cannot be created. The existing prompt was misleading if the issue wasn't a pre-existing database. Thanks for the suggestion, John Shaffer <jshaffer2112@gmail.com>. ........ r5733 | adrian | 2007-07-20 23:40:54 +0800 (Fri, 20 Jul 2007) | 1 line Fixed negligible typo in docstring in tests/regressiontests/test_client_regress/models.py from [5731] ........ r5736 | adrian | 2007-07-21 05:24:30 +0800 (Sat, 21 Jul 2007) | 1 line Added some additional docs to docs/model-api.txt db_type() section ........ r5738 | russellm | 2007-07-21 11:30:38 +0800 (Sat, 21 Jul 2007) | 2 lines Fixed #4304 -- Modified sys.exit to os._exit to make sure development server quits when an error occurs attempting to bind to the requested port (e.g., if another server is already running). Thanks, Mario Gonzalez <gonzalemario@gmail.com>. ........ r5739 | russellm | 2007-07-21 12:36:28 +0800 (Sat, 21 Jul 2007) | 2 lines Minor fix to allow for count=0 in assertContains. ........ r5740 | russellm | 2007-07-21 13:15:19 +0800 (Sat, 21 Jul 2007) | 2 lines Added test cases for change [5739]. ........ r5741 | russellm | 2007-07-21 13:17:20 +0800 (Sat, 21 Jul 2007) | 2 lines Fixed #4402 -- Modified test client to allow multi-valued inputs on GET requests. Thanks for the suggestion, eddymul@gmail.com. ........ r5743 | gwilson | 2007-07-22 10:18:36 +0800 (Sun, 22 Jul 2007) | 2 lines Fixed #4945 -- Removed unused `GET_ITERATOR_CHUNK_SIZE` definition from manager.py. `GET_ITERATOR_CHUNK_SIZE` is already defined in query.py. Thanks zigiDev@mac.com. ........ r5744 | gwilson | 2007-07-22 11:09:24 +0800 (Sun, 22 Jul 2007) | 2 lines Added docstrings to shortcuts module and functions. ........ r5745 | gwilson | 2007-07-22 11:12:50 +0800 (Sun, 22 Jul 2007) | 2 lines Shortcut functions do not accept `QuerySet` objects, yet :) ........ r5746 | gwilson | 2007-07-22 11:41:11 +0800 (Sun, 22 Jul 2007) | 2 lines Fixed #4373 -- Modified the get_object_or_404/get_list_or_404 shortcuts to also accept `QuerySet`s. Thanks SuperJared. ........ r5747 | gwilson | 2007-07-22 11:45:03 +0800 (Sun, 22 Jul 2007) | 2 lines Corrected typo in [5746]. ........ r5750 | gwilson | 2007-07-23 12:45:01 +0800 (Mon, 23 Jul 2007) | 2 lines Fixed #4952 -- Fixed the `get_template_sources` functions of the `app_directories` and `filesystem` template loaders to not return paths outside of given template directories. Both functions now make use of a new `safe_join` utility function. Thanks to SmileyChris for help with the patch. ........ r5752 | russellm | 2007-07-23 20:14:32 +0800 (Mon, 23 Jul 2007) | 2 lines Fixed #3771 -- Modified the test runner to observe the --noinput argument controlling script interactivity. This means that test scripts can now be put in a buildbot environment. This is a backwards incompatible change for anyone that has written a custom test runner. Thanks for the suggestion, moof@metamoof.net. ........ r5753 | russellm | 2007-07-23 21:52:59 +0800 (Mon, 23 Jul 2007) | 2 lines Added documentation for a test runner argument that has always been present, but was undocumented. ........ r5756 | adrian | 2007-07-25 11:12:31 +0800 (Wed, 25 Jul 2007) | 1 line Changed docstring additions from [5744] to use active verbs ('returns' instead of 'return') ........ r5757 | adrian | 2007-07-25 11:15:05 +0800 (Wed, 25 Jul 2007) | 1 line Added 'New in Django development version' to docs/db-api.txt change from [5746] ........ r5758 | adrian | 2007-07-25 11:18:17 +0800 (Wed, 25 Jul 2007) | 1 line Changed safe_join() docstring from [5750] to use active verbs. See also [5756] ........ r5764 | gwilson | 2007-07-26 13:01:53 +0800 (Thu, 26 Jul 2007) | 2 lines Fixed #4971 -- Fixed some escaping and quoting problems in the databrowse contrib app. Based on patch from Johann Queuniet. ........ r5765 | adrian | 2007-07-27 01:16:34 +0800 (Fri, 27 Jul 2007) | 1 line Added section to docs/contributing.txt about docstring coding style ........ r5766 | mtredinnick | 2007-07-27 06:59:34 +0800 (Fri, 27 Jul 2007) | 2 lines Added support for database cache table in test database. ........ r5767 | adrian | 2007-07-28 05:53:02 +0800 (Sat, 28 Jul 2007) | 1 line Added unit test that confirms a bug in ValuesQuerySets that have extra(select) specified. If the select dictionary has several fields, Django assigns the wrong values to the select-field names ........ r5768 | adrian | 2007-07-28 06:07:42 +0800 (Sat, 28 Jul 2007) | 1 line Fixed bug with using values() and extra(select) in the same QuerySet, with a select dictionary containing more than a few elements. This bug was identified in unit test from [5767]. The problem was that we were relying on the dictionary's .items() ordering, which is undefined ........ r5769 | russellm | 2007-07-28 12:02:52 +0800 (Sat, 28 Jul 2007) | 2 lines Fixed #4460 -- Added the ability to be more specific in the test cases that are executed. This is a backwards incompatible change for any user with a custom test runner. See the wiki for details. ........ r5770 | russellm | 2007-07-28 15:27:53 +0800 (Sat, 28 Jul 2007) | 2 lines Fixed #4995 -- Fixed some problems in documentation ReST formatting. Thanks, Simon G. ........ r5771 | simon | 2007-07-29 02:30:40 +0800 (Sun, 29 Jul 2007) | 1 line After discussing with Malcolm, added set_unusable_password() and has_usable_password() methods to the User object, plus tests and updated documentation ........ r5774 | adrian | 2007-07-30 02:21:16 +0800 (Mon, 30 Jul 2007) | 1 line Added 'New in Django development version' to changes in docs/authentication.txt from [5771] ........ r5778 | gwilson | 2007-07-31 01:25:35 +0800 (Tue, 31 Jul 2007) | 4 lines Fixed call to `ugettext`, which is imported as `_`. Changed raise to conform to PEP 3109 and wrapped the long line. Added beginnings of tests for model fields. ........ r5782 | gwilson | 2007-08-01 13:41:32 +0800 (Wed, 01 Aug 2007) | 2 lines Fixed #4228 -- Removed hardcoding of `RadioFieldRenderer` in the `RadioSelect` Widget so that the display of `RadioSelect`s can be more easily customized. `BoundField.__unicode__` also no longer special cases `RadioSelect` since `RadioSelect.render()` now returns a string like every other Widget. ........ r5783 | gwilson | 2007-08-01 13:52:18 +0800 (Wed, 01 Aug 2007) | 2 lines Fixed #5037 -- Fixed use of wrong field type in a db-api docs example, thanks ubernostrum. ........ r5796 | gwilson | 2007-08-04 11:19:14 +0800 (Sat, 04 Aug 2007) | 2 lines Fixed #5078 -- Fixed several broken links to the syndication documentation. ........ r5797 | gwilson | 2007-08-04 11:36:58 +0800 (Sat, 04 Aug 2007) | 2 lines Changed the 0.95 release notes to point to the 0.95 documentation index. ........ r5798 | gwilson | 2007-08-04 11:39:24 +0800 (Sat, 04 Aug 2007) | 2 lines Changed several documentation links to be relative. ........ r5799 | gwilson | 2007-08-04 22:41:49 +0800 (Sat, 04 Aug 2007) | 2 lines Refs #3397 -- Corrected the Exception that is caught when ordering by non-fields (added in [4596]), thanks glin@seznam.cz. ........ r5800 | gwilson | 2007-08-04 22:52:13 +0800 (Sat, 04 Aug 2007) | 2 lines Fixed #5083 -- Fixed typo in newforms documentation, thanks Rik. ........ r5801 | gwilson | 2007-08-05 12:39:52 +0800 (Sun, 05 Aug 2007) | 2 lines Refs #5089 -- Added file name to poll detail template examples in the tutorial. ........ r5802 | gwilson | 2007-08-05 12:42:26 +0800 (Sun, 05 Aug 2007) | 2 lines Changed some more links to be relative in the documentation. I had a couple unsaved files that didn't get in with [5798]. ........ r5803 | gwilson | 2007-08-05 13:14:46 +0800 (Sun, 05 Aug 2007) | 2 lines Fixed #2101 -- Renamed `maxlength` argument to `max_length` for oldforms `FormField`s and db model `Field`s. This is fully backwards compatible at the moment since the legacy `maxlength` argument is still supported. Using `maxlength` will, however, issue a `PendingDeprecationWarning` when used. ........ r5804 | russellm | 2007-08-05 15:39:36 +0800 (Sun, 05 Aug 2007) | 2 lines Fixed #4001 -- Added dynamic save_m2m method() to forms created with form_for_model and form_for_instance on save(commit=False). ........ r5807 | adrian | 2007-08-06 12:36:43 +0800 (Mon, 06 Aug 2007) | 1 line Fixed #5074 -- Added link to audio clip of 'Django' pronunciation ........ r5808 | adrian | 2007-08-06 12:52:14 +0800 (Mon, 06 Aug 2007) | 1 line Edited docs/newforms.txt changes from [5804] ........ r5809 | adrian | 2007-08-06 13:04:27 +0800 (Mon, 06 Aug 2007) | 1 line Fixed #5082 -- Enabled tab completion in 'django-admin.py shell' for objects that were imported into the global namespace at runtime. Thanks, dusk@woofle.net ........ r5810 | adrian | 2007-08-06 13:06:15 +0800 (Mon, 06 Aug 2007) | 1 line Fixed #5077 -- django/utils/encoding.py no longer imports settings, as it doesn't use that module. Thanks, Collin Grady ........ r5811 | adrian | 2007-08-06 13:07:38 +0800 (Mon, 06 Aug 2007) | 1 line Fixed #5071 -- Fixed 'global name ugettext is not defined' error in django.core.validators. Thanks, Marco Bonetti ........ r5812 | adrian | 2007-08-06 13:13:06 +0800 (Mon, 06 Aug 2007) | 1 line Fixed #5064 -- Fixed potentially confusing sentence in docs/authentication.txt. Thanks, Collin Grady ........ r5813 | adrian | 2007-08-06 13:16:35 +0800 (Mon, 06 Aug 2007) | 1 line Fixed #5053 -- Added 'action' attribute to <form> tags that didn't have that attribute in docs/newforms.txt examples. Perfectionism appreciated, trickyb ........ r5814 | adrian | 2007-08-06 13:27:58 +0800 (Mon, 06 Aug 2007) | 1 line Added a closing </p>' to a code example in docs/email.txt ........ r5815 | adrian | 2007-08-06 13:28:45 +0800 (Mon, 06 Aug 2007) | 1 line Fixed #5006 -- Fixed incorrect/outdated docstring for the 'if' template tag. Thanks, Thomas Petazzoni ........ r5816 | adrian | 2007-08-06 13:33:18 +0800 (Mon, 06 Aug 2007) | 1 line Added note to docs/model-api.txt about help_text not being escaped in the admin interface ........ r5817 | adrian | 2007-08-06 13:34:45 +0800 (Mon, 06 Aug 2007) | 1 line Fixed #4985 -- Clarified location of HttpResponse in docs/request_response.txt. Thanks for raising the issue, rainer.mansfeld@romulo.de ........ r5818 | adrian | 2007-08-06 13:37:17 +0800 (Mon, 06 Aug 2007) | 1 line Fixed #4980 -- Removed 'forms' from the 'not considered stable and will be rewritten' section of docs/api_stability.txt. They've already been rewritten. ........ r5819 | russellm | 2007-08-06 21:58:56 +0800 (Mon, 06 Aug 2007) | 2 lines Fixed #3297 -- Implemented FileField and ImageField for newforms. Thanks to the many users that contributed to and tested this patch. ........ r5820 | russellm | 2007-08-06 22:17:10 +0800 (Mon, 06 Aug 2007) | 2 lines Added note that FileField and ImageField are only in development version. There are also some minor backwards compatibility issues with the changes introduced in [5819] - see the wiki for details. ........ r5823 | adrian | 2007-08-07 04:27:04 +0800 (Tue, 07 Aug 2007) | 1 line Fixed British spelling of 'customize' and 'behavior' in Manager.get_query_set() docstring ........ r5824 | adrian | 2007-08-07 10:18:36 +0800 (Tue, 07 Aug 2007) | 1 line Fixed #5105 -- Fixed two ReST errors in docs/newforms.txt. Thanks, Ramiro Morales ........ r5825 | adrian | 2007-08-07 10:33:11 +0800 (Tue, 07 Aug 2007) | 1 line Fixed #5097 -- Made various updates and corrections to the documentation. Thanks, Nicola Larosa ........ r5826 | russellm | 2007-08-07 19:20:15 +0800 (Tue, 07 Aug 2007) | 2 lines Removed a redundant directory join during FileField form saving. Thanks to David Danier's eagle eyes for picking up this one. ........ git-svn-id: http://code.djangoproject.com/svn/django/branches/newforms-admin@5828 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
a704a38292
commit
83861364dd
19
AUTHORS
19
AUTHORS
@ -57,10 +57,12 @@ answer newbie questions, and generally made Django that much better:
|
||||
Ned Batchelder <http://www.nedbatchelder.com/>
|
||||
Shannon -jj Behrens <http://jjinux.blogspot.com/>
|
||||
Esdras Beleza <linux@esdrasbeleza.com>
|
||||
Chris Bennett <chrisrbennett@yahoo.com>
|
||||
James Bennett
|
||||
Ben <afternoon@uk2.net>
|
||||
Paul Bissex <http://e-scribe.com/>
|
||||
Simon Blanchard
|
||||
Matt Boersma <ogghead@gmail.com>
|
||||
boobsd@gmail.com
|
||||
Andrew Brehaut <http://brehaut.net/blog>
|
||||
brut.alll@gmail.com
|
||||
@ -94,10 +96,12 @@ answer newbie questions, and generally made Django that much better:
|
||||
Maximillian Dornseif <md@hudora.de>
|
||||
Jeremy Dunck <http://dunck.us/>
|
||||
Andrew Durdin <adurdin@gmail.com>
|
||||
dusk@woofle.net
|
||||
Andy Dustman <farcepest@gmail.com>
|
||||
Clint Ecker
|
||||
enlight
|
||||
Enrico <rico.bl@gmail.com>
|
||||
A. Murat Eren <meren@pardus.org.tr>
|
||||
Ludvig Ericson <ludvig.ericson@gmail.com>
|
||||
Dirk Eschler <dirk.eschler@gmx.net>
|
||||
Marc Fargas <telenieko@telenieko.com>
|
||||
@ -114,7 +118,7 @@ answer newbie questions, and generally made Django that much better:
|
||||
glin@seznam.cz
|
||||
martin.glueck@gmail.com
|
||||
GomoX <gomo@datafull.com>
|
||||
Mario Gonzalez <gonzalemario @t gmail.com>
|
||||
Mario Gonzalez <gonzalemario@gmail.com>
|
||||
Simon Greenhill <dev@simon.net.nz>
|
||||
Owen Griffiths
|
||||
Espen Grindhaug <http://grindhaug.org/>
|
||||
@ -141,7 +145,8 @@ answer newbie questions, and generally made Django that much better:
|
||||
junzhang.jn@gmail.com
|
||||
Antti Kaihola <http://akaihola.blogspot.com/>
|
||||
Ben Dean Kawamura <ben.dean.kawamura@gmail.com>
|
||||
ian.g.kelly@gmail.com
|
||||
Ian G. Kelly <ian.g.kelly@gmail.com>
|
||||
Ben Khoo <khoobks@westnet.com.au>
|
||||
Garth Kidd <http://www.deadlybloodyserious.com/>
|
||||
kilian <kilian.cavalotti@lip6.fr>
|
||||
Sune Kirkeby <http://ibofobi.dk/>
|
||||
@ -153,6 +158,7 @@ answer newbie questions, and generally made Django that much better:
|
||||
Martin Kosír <martin@martinkosir.net>
|
||||
Meir Kriheli <http://mksoft.co.il/>
|
||||
Bruce Kroeze <http://coderseye.com/>
|
||||
krzysiek.pawlik@silvermedia.pl
|
||||
Joseph Kocherhans
|
||||
konrad@gwu.edu
|
||||
kurtiss@meetro.com
|
||||
@ -167,13 +173,14 @@ answer newbie questions, and generally made Django that much better:
|
||||
lerouxb@gmail.com
|
||||
Waylan Limberg <waylan@gmail.com>
|
||||
limodou
|
||||
Philip Lindborg <philip.lindborg@gmail.com>
|
||||
Matt McClanahan <http://mmcc.cx/>
|
||||
Martin Maney <http://www.chipy.org/Martin_Maney>
|
||||
masonsimon+django@gmail.com
|
||||
Manuzhai
|
||||
Petar Marić <http://www.petarmaric.com/>
|
||||
Nuno Mariz <nmariz@gmail.com>
|
||||
marijn@metronomo.cl
|
||||
Marijn Vriens <marijn@metronomo.cl>
|
||||
mark@junklight.com
|
||||
Yasushi Masuda <whosaysni@gmail.com>
|
||||
mattycakes@gmail.com
|
||||
@ -183,6 +190,7 @@ answer newbie questions, and generally made Django that much better:
|
||||
mikko@sorl.net
|
||||
mitakummaa@gmail.com
|
||||
mmarshall
|
||||
Andreas Mock <andreas.mock@web.de>
|
||||
Reza Mohammadi <reza@zeerak.ir>
|
||||
Eric Moritz <http://eric.themoritzfamily.com/>
|
||||
mrmachine <real.human@mrmachine.net>
|
||||
@ -207,6 +215,7 @@ answer newbie questions, and generally made Django that much better:
|
||||
plisk
|
||||
Daniel Poelzleithner <http://poelzi.org/>
|
||||
polpak@yahoo.com
|
||||
Johann Queuniet <johann.queuniet@adh.naellia.eu>
|
||||
J. Rademaker
|
||||
Michael Radziej <mir@noris.de>
|
||||
Ramiro Morales <rm0@gmx.net>
|
||||
@ -216,12 +225,14 @@ answer newbie questions, and generally made Django that much better:
|
||||
rhettg@gmail.com
|
||||
Henrique Romano <onaiort@gmail.com>
|
||||
Armin Ronacher
|
||||
Brian Rosner <brosner@gmail.com>
|
||||
Oliver Rutherfurd <http://rutherfurd.net/>
|
||||
Ivan Sagalaev (Maniac) <http://www.softwaremaniacs.org/>
|
||||
Vinay Sajip <vinay_sajip@yahoo.co.uk>
|
||||
David Schein
|
||||
scott@staplefish.com
|
||||
serbaut@gmail.com
|
||||
John Shaffer <jshaffer2112@gmail.com>
|
||||
Pete Shinners <pete@shinners.org>
|
||||
Jozko Skrablin <jozko.skrablin@gmail.com>
|
||||
SmileyChris <smileychris@gmail.com>
|
||||
@ -232,6 +243,8 @@ answer newbie questions, and generally made Django that much better:
|
||||
Vasiliy Stavenko <stavenko@gmail.com>
|
||||
Thomas Steinacher <http://www.eggdrop.ch/>
|
||||
nowell strite
|
||||
Sundance
|
||||
SuperJared
|
||||
Radek Švarz <http://www.svarz.cz/translate/>
|
||||
Swaroop C H <http://www.swaroopch.info>
|
||||
Aaron Swartz <http://www.aaronsw.com/>
|
||||
|
@ -9,6 +9,7 @@ import re
|
||||
import os
|
||||
import sys
|
||||
import getopt
|
||||
from itertools import dropwhile
|
||||
|
||||
pythonize_re = re.compile(r'\n\s*//')
|
||||
|
||||
@ -103,8 +104,8 @@ def make_messages():
|
||||
open(os.path.join(dirpath, '%s.py' % file), "wb").write(templatize(src))
|
||||
thefile = '%s.py' % file
|
||||
if verbose: sys.stdout.write('processing file %s in %s\n' % (file, dirpath))
|
||||
cmd = 'xgettext %s -d %s -L Python --keyword=gettext_noop --keyword=gettext_lazy --keyword=ngettext_lazy:1,2 --keyword=ugettext_noop --keyword=ugettext_lazy --keyword=ungettext_lazy:1,2 --from-code UTF-8 -o - "%s"' % (
|
||||
os.path.exists(potfile) and '--omit-header' or '', domain, os.path.join(dirpath, thefile))
|
||||
cmd = 'xgettext -d %s -L Python --keyword=gettext_noop --keyword=gettext_lazy --keyword=ngettext_lazy:1,2 --keyword=ugettext_noop --keyword=ugettext_lazy --keyword=ungettext_lazy:1,2 --from-code UTF-8 -o - "%s"' % (
|
||||
domain, os.path.join(dirpath, thefile))
|
||||
(stdin, stdout, stderr) = os.popen3(cmd, 'b')
|
||||
msgs = stdout.read()
|
||||
errors = stderr.read()
|
||||
@ -116,13 +117,18 @@ def make_messages():
|
||||
old = '#: '+os.path.join(dirpath, thefile)[2:]
|
||||
new = '#: '+os.path.join(dirpath, file)[2:]
|
||||
msgs = msgs.replace(old, new)
|
||||
if os.path.exists(potfile):
|
||||
# Strip the header
|
||||
msgs = '\n'.join(dropwhile(len, msgs.split('\n')))
|
||||
else:
|
||||
msgs = msgs.replace('charset=CHARSET', 'charset=UTF-8')
|
||||
if msgs:
|
||||
open(potfile, 'ab').write(msgs)
|
||||
if thefile != file:
|
||||
os.unlink(os.path.join(dirpath, thefile))
|
||||
|
||||
if os.path.exists(potfile):
|
||||
(stdin, stdout, stderr) = os.popen3('msguniq "%s"' % potfile, 'b')
|
||||
(stdin, stdout, stderr) = os.popen3('msguniq --to-code=utf-8 "%s"' % potfile, 'b')
|
||||
msgs = stdout.read()
|
||||
errors = stderr.read()
|
||||
if errors:
|
||||
|
@ -37,6 +37,8 @@ class LazySettings(object):
|
||||
# __setattr__(), which would be an infinite loop.
|
||||
self.__dict__['_target'] = value
|
||||
else:
|
||||
if self._target is None:
|
||||
self._import_settings()
|
||||
setattr(self._target, name, value)
|
||||
|
||||
def _import_settings(self):
|
||||
|
@ -30,7 +30,6 @@ TIME_ZONE = 'America/Chicago'
|
||||
|
||||
# Language code for this installation. All choices can be found here:
|
||||
# http://www.w3.org/TR/REC-html40/struct/dirlang.html#langcodes
|
||||
# http://blogs.law.harvard.edu/tech/stories/storyReader$15
|
||||
LANGUAGE_CODE = 'en-us'
|
||||
|
||||
# Languages we provide translations for, out of the box. The language name
|
||||
|
Binary file not shown.
@ -11,21 +11,21 @@ msgstr ""
|
||||
"PO-Revision-Date: 2005-12-04 13:21+0100\n"
|
||||
"Last-Translator: Dirk Eschler <dirk.eschler@gmx.net>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=iso-8859-1\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#: contrib/admin/media/js/SelectFilter2.js:33
|
||||
#, perl-format
|
||||
msgid "Available %s"
|
||||
msgstr "Verfügbare %s"
|
||||
msgstr "Verfügbare %s"
|
||||
|
||||
#: contrib/admin/media/js/SelectFilter2.js:41
|
||||
msgid "Choose all"
|
||||
msgstr "Alles auswählen"
|
||||
msgstr "Alles auswählen"
|
||||
|
||||
#: contrib/admin/media/js/SelectFilter2.js:46
|
||||
msgid "Add"
|
||||
msgstr "Hinzufügen"
|
||||
msgstr "Hinzufügen"
|
||||
|
||||
#: contrib/admin/media/js/SelectFilter2.js:48
|
||||
msgid "Remove"
|
||||
@ -34,15 +34,15 @@ msgstr "Entfernen"
|
||||
#: contrib/admin/media/js/SelectFilter2.js:53
|
||||
#, perl-format
|
||||
msgid "Chosen %s"
|
||||
msgstr "Ausgewählte %s"
|
||||
msgstr "Ausgewählte %s"
|
||||
|
||||
#: contrib/admin/media/js/SelectFilter2.js:54
|
||||
msgid "Select your choice(s) and click "
|
||||
msgstr "Gewünschte Auswahl treffen und "
|
||||
msgstr "Gewünschte Auswahl treffen und "
|
||||
|
||||
#: contrib/admin/media/js/SelectFilter2.js:59
|
||||
msgid "Clear all"
|
||||
msgstr "Alles abwählen"
|
||||
msgstr "Alles abwählen"
|
||||
|
||||
#: contrib/admin/media/js/dateparse.js:26
|
||||
#: contrib/admin/media/js/calendar.js:24
|
||||
@ -50,7 +50,7 @@ msgid ""
|
||||
"January February March April May June July August September October November "
|
||||
"December"
|
||||
msgstr ""
|
||||
"Januar Februar März April Mai Juni Juli August September Oktober November "
|
||||
"Januar Februar März April Mai Juni Juli August September Oktober November "
|
||||
"Dezember"
|
||||
|
||||
#: contrib/admin/media/js/dateparse.js:27
|
||||
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@ -1,26 +1,41 @@
|
||||
# Spanish translation for the django-admin JS files.
|
||||
# Copyright (C)
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
# Jorge Gajon <gajon@gajon.org>, 2005.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Django JavaScript 1.0\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2005-12-09 11:51+0100\n"
|
||||
"PO-Revision-Date: 2005-12-06 21:32+0100\n"
|
||||
"POT-Creation-Date: 2007-07-14 13:47-0500\n"
|
||||
"PO-Revision-Date: 2007-07-14 13:41-0500\n"
|
||||
"Last-Translator: Jorge Gajon <gajon@gajon.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=ISO-8859-1\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#: contrib/admin/media/js/calendar.js:24
|
||||
#: contrib/admin/media/js/dateparse.js:32
|
||||
msgid ""
|
||||
"January February March April May June July August September October November "
|
||||
"December"
|
||||
msgstr ""
|
||||
"Enero Febrero Marzo Abril Mayo Junio Julio Agosto Septiembre Octubre "
|
||||
"Noviembre Diciembre"
|
||||
|
||||
#: contrib/admin/media/js/calendar.js:25
|
||||
msgid "S M T W T F S"
|
||||
msgstr "D L M M J V S"
|
||||
|
||||
#: contrib/admin/media/js/dateparse.js:33
|
||||
msgid "Sunday Monday Tuesday Wednesday Thursday Friday Saturday"
|
||||
msgstr "Domingo Lunes Martes Miércoles Jueves Viernes Sábado"
|
||||
|
||||
#: contrib/admin/media/js/SelectFilter2.js:33
|
||||
#, perl-format
|
||||
msgid "Available %s"
|
||||
msgstr "%s Disponibles"
|
||||
|
||||
#: contrib/admin/media/js/SelectFilter2.js:41
|
||||
#, fuzzy
|
||||
msgid "Choose all"
|
||||
msgstr "Selecciona todos"
|
||||
|
||||
@ -45,66 +60,58 @@ msgstr "Haz tus elecciones y da click en "
|
||||
msgid "Clear all"
|
||||
msgstr "Elimina todos"
|
||||
|
||||
#: contrib/admin/media/js/dateparse.js:26
|
||||
#: contrib/admin/media/js/calendar.js:24
|
||||
msgid ""
|
||||
"January February March April May June July August September October November "
|
||||
"December"
|
||||
msgstr ""
|
||||
"Enero Febrero Marzo Abril Mayo Junio Julio Agosto Septiembre Octubre "
|
||||
"Noviembre Diciembre"
|
||||
|
||||
#: contrib/admin/media/js/dateparse.js:27
|
||||
msgid "Sunday Monday Tuesday Wednesday Thursday Friday Saturday"
|
||||
msgstr "Domingo Lunes Martes Miércoles Jueves Viernes Sábado"
|
||||
|
||||
#: contrib/admin/media/js/calendar.js:25
|
||||
msgid "S M T W T F S"
|
||||
msgstr "D L M M J V S"
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:45
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:80
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:47
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:81
|
||||
msgid "Now"
|
||||
msgstr "Ahora"
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:48
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:51
|
||||
msgid "Clock"
|
||||
msgstr "Reloj"
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:77
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:78
|
||||
msgid "Choose a time"
|
||||
msgstr "Elige una hora"
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:81
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:82
|
||||
msgid "Midnight"
|
||||
msgstr "Medianoche"
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:82
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:83
|
||||
msgid "6 a.m."
|
||||
msgstr "6 a.m."
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:83
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:84
|
||||
msgid "Noon"
|
||||
msgstr "Mediodía"
|
||||
msgstr "Mediodía"
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:87
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:168
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:88
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:183
|
||||
msgid "Cancel"
|
||||
msgstr "Cancelar"
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:111
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:162
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:128
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:177
|
||||
msgid "Today"
|
||||
msgstr "Hoy"
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:114
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:132
|
||||
msgid "Calendar"
|
||||
msgstr "Calendario"
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:160
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:175
|
||||
msgid "Yesterday"
|
||||
msgstr "Ayer"
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:164
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:179
|
||||
msgid "Tomorrow"
|
||||
msgstr "Mañana"
|
||||
msgstr "Mañana"
|
||||
|
||||
#: contrib/admin/media/js/admin/CollapsedFieldsets.js:34
|
||||
#: contrib/admin/media/js/admin/CollapsedFieldsets.js:72
|
||||
msgid "Show"
|
||||
msgstr "Mostrar"
|
||||
|
||||
#: contrib/admin/media/js/admin/CollapsedFieldsets.js:63
|
||||
msgid "Hide"
|
||||
msgstr "Esconder"
|
||||
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@ -1,17 +1,17 @@
|
||||
# Argentinean spanish translation for the django-admin JS files, based on
|
||||
# Spanish translation work by Jorge Gajon.
|
||||
# This file is distributed under the same license as the Django package.
|
||||
# Copyright (C) Ramiro Morales <rm0@gmx.net>, 2006,2007.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Django JavaScript 1.0\n"
|
||||
"Project-Id-Version: Django Javascript 1.0\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2007-02-25 17:48-0300\n"
|
||||
"PO-Revision-Date: 2007-02-25 17:55-0300\n"
|
||||
"POT-Creation-Date: 2007-07-14 13:45-0300\n"
|
||||
"PO-Revision-Date: 2007-07-14 14:36-0300\n"
|
||||
"Last-Translator: Ramiro Morales <rm0@gmx.net>\n"
|
||||
"Language-Team: Django-I18N <django-i18n@googlegroups.com>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=ISO-8859-1\n"
|
||||
"Content-Type: text/plain; charset=utf-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#: contrib/admin/media/js/SelectFilter2.js:33
|
||||
@ -55,7 +55,7 @@ msgstr ""
|
||||
|
||||
#: contrib/admin/media/js/dateparse.js:33
|
||||
msgid "Sunday Monday Tuesday Wednesday Thursday Friday Saturday"
|
||||
msgstr "Domingo Lunes Martes Miércoles Jueves Viernes Sábado"
|
||||
msgstr "Domingo Lunes Martes Miércoles Jueves Viernes Sábado"
|
||||
|
||||
#: contrib/admin/media/js/calendar.js:25
|
||||
msgid "S M T W T F S"
|
||||
@ -93,7 +93,7 @@ msgstr "6 a.m."
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:84
|
||||
msgid "Noon"
|
||||
msgstr "Mediodía"
|
||||
msgstr "Mediodía"
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:88
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:183
|
||||
@ -115,4 +115,4 @@ msgstr "Ayer"
|
||||
|
||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:179
|
||||
msgid "Tomorrow"
|
||||
msgstr "Mañana"
|
||||
msgstr "Mañana"
|
||||
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@ -1,7 +1,7 @@
|
||||
# French translation for js.
|
||||
# Copyright (C) 2005 Mikaël Barbero
|
||||
# Copyright (C) 2005 Mikaël Barbero
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
# Mikaël Barbero <mikael.barbero nospam at nospam free.fr>, 2005.
|
||||
# Mikaël Barbero <mikael.barbero nospam at nospam free.fr>, 2005.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
@ -9,10 +9,10 @@ msgstr ""
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2005-12-24 16:39+0100\n"
|
||||
"PO-Revision-Date: 2005-12-24 16:39+0100\n"
|
||||
"Last-Translator: Mikaël Barbero <mikael.barbero nospam at nospam free.fr>\n"
|
||||
"Last-Translator: Mikaël Barbero <mikael.barbero nospam at nospam free.fr>\n"
|
||||
"Language-Team: French <fr@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=ISO-8859-1\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#: contrib/admin/media/js/calendar.js:24
|
||||
@ -21,8 +21,8 @@ msgid ""
|
||||
"January February March April May June July August September October November "
|
||||
"December"
|
||||
msgstr ""
|
||||
"Janvier Février Mars Avril Mai Juin Juillet Août Septembre Octobre Novembre "
|
||||
"Décembre"
|
||||
"Janvier Février Mars Avril Mai Juin Juillet Août Septembre Octobre Novembre "
|
||||
"Décembre"
|
||||
|
||||
#: contrib/admin/media/js/calendar.js:25
|
||||
msgid "S M T W T F S"
|
||||
@ -56,7 +56,7 @@ msgstr "Choisi %s"
|
||||
|
||||
#: contrib/admin/media/js/SelectFilter2.js:54
|
||||
msgid "Select your choice(s) and click "
|
||||
msgstr "Sélectionnez un ou plusieurs choix et cliquez "
|
||||
msgstr "Sélectionnez un ou plusieurs choix et cliquez "
|
||||
|
||||
#: contrib/admin/media/js/SelectFilter2.js:59
|
||||
msgid "Clear all"
|
||||
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@ -25,7 +25,6 @@ TIME_ZONE = 'America/Chicago'
|
||||
|
||||
# Language code for this installation. All choices can be found here:
|
||||
# http://www.w3.org/TR/REC-html40/struct/dirlang.html#langcodes
|
||||
# http://blogs.law.harvard.edu/tech/stories/storyReader$15
|
||||
LANGUAGE_CODE = 'en-us'
|
||||
|
||||
SITE_ID = 1
|
||||
|
@ -31,10 +31,11 @@ function showAddAnotherPopup(triggeringLink) {
|
||||
var name = triggeringLink.id.replace(/^add_/, '');
|
||||
name = name.replace(/\./g, '___');
|
||||
href = triggeringLink.href
|
||||
if (href.indexOf('?') == -1)
|
||||
href += '?_popup=1';
|
||||
else
|
||||
href += '&_popup=1';
|
||||
if (href.indexOf('?') == -1) {
|
||||
href += '?_popup=1';
|
||||
} else {
|
||||
href += '&_popup=1';
|
||||
}
|
||||
var win = window.open(href, name, 'height=500,width=800,resizable=yes,scrollbars=yes');
|
||||
win.focus();
|
||||
return false;
|
||||
|
@ -2,12 +2,12 @@ var LATIN_MAP = {
|
||||
'À': 'A', 'Á': 'A', 'Â': 'A', 'Ã': 'A', 'Ä': 'A', 'Å': 'A', 'Æ': 'AE', 'Ç':
|
||||
'C', 'È': 'E', 'É': 'E', 'Ê': 'E', 'Ë': 'E', 'Ì': 'I', 'Í': 'I', 'Î': 'I',
|
||||
'Ï': 'I', 'Ð': 'D', 'Ñ': 'N', 'Ò': 'O', 'Ó': 'O', 'Ô': 'O', 'Õ': 'O', 'Ö':
|
||||
'O', 'Ø': 'O', 'Ù': 'U', 'Ú': 'U', 'Û': 'U', 'Ü': 'U', 'Ý': 'Y', 'Þ': 'TH',
|
||||
'ß': 'ss', 'à':'a', 'á':'a', 'â': 'a', 'ã': 'a', 'ä': 'a', 'å': 'a', 'æ':
|
||||
'ae', 'ç': 'c', 'è': 'e', 'é': 'e', 'ê': 'e', 'ë': 'e', 'ì': 'i', 'í': 'i',
|
||||
'î': 'i', 'ï': 'i', 'ð': 'o', 'ñ': 'n', 'ò': 'o', 'ó': 'o', 'ô': 'o', 'õ':
|
||||
'o', 'ö': 'o', 'ø': 'o', 'ù': 'u', 'ú': 'u', 'û': 'u', 'ü': 'u', 'ý': 'y',
|
||||
'þ': 'th', 'ÿ': 'y'
|
||||
'O', 'Ő': 'O', 'Ø': 'O', 'Ù': 'U', 'Ú': 'U', 'Û': 'U', 'Ü': 'U', 'Ű': 'U',
|
||||
'Ý': 'Y', 'Þ': 'TH', 'ß': 'ss', 'à':'a', 'á':'a', 'â': 'a', 'ã': 'a', 'ä':
|
||||
'a', 'å': 'a', 'æ': 'ae', 'ç': 'c', 'è': 'e', 'é': 'e', 'ê': 'e', 'ë': 'e',
|
||||
'ì': 'i', 'í': 'i', 'î': 'i', 'ï': 'i', 'ð': 'o', 'ñ': 'n', 'ò': 'o', 'ó':
|
||||
'o', 'ô': 'o', 'õ': 'o', 'ö': 'o', 'ő': 'o', 'ø': 'o', 'ù': 'u', 'ú': 'u',
|
||||
'û': 'u', 'ü': 'u', 'ű': 'u', 'ý': 'y', 'þ': 'th', 'ÿ': 'y'
|
||||
}
|
||||
var LATIN_SYMBOLS_MAP = {
|
||||
'©':'(c)'
|
||||
|
@ -18,7 +18,7 @@ class LogEntry(models.Model):
|
||||
user = models.ForeignKey(User)
|
||||
content_type = models.ForeignKey(ContentType, blank=True, null=True)
|
||||
object_id = models.TextField(_('object id'), blank=True, null=True)
|
||||
object_repr = models.CharField(_('object repr'), maxlength=200)
|
||||
object_repr = models.CharField(_('object repr'), max_length=200)
|
||||
action_flag = models.PositiveSmallIntegerField(_('action flag'))
|
||||
change_message = models.TextField(_('change message'), blank=True)
|
||||
objects = LogEntryManager()
|
||||
|
@ -190,9 +190,11 @@ def items_for_result(cl, result):
|
||||
table_tag = {True:'th', False:'td'}[first]
|
||||
first = False
|
||||
url = cl.url_for_result(result)
|
||||
result_id = smart_unicode(getattr(result, pk)) # conversion to string is needed in case of 23L (long ints)
|
||||
# Convert the pk to something that can be used in Javascript.
|
||||
# Problem cases are long ints (23L) and non-ASCII strings.
|
||||
result_id = repr(force_unicode(getattr(result, pk)))[1:]
|
||||
yield (u'<%s%s><a href="%s"%s>%s</a></%s>' % \
|
||||
(table_tag, row_class, url, (cl.is_popup and ' onclick="opener.dismissRelatedLookupPopup(window, %r); return false;"' % result_id or ''), result_repr, table_tag))
|
||||
(table_tag, row_class, url, (cl.is_popup and ' onclick="opener.dismissRelatedLookupPopup(window, %s); return false;"' % result_id or ''), result_repr, table_tag))
|
||||
else:
|
||||
yield (u'<td%s>%s</td>' % (row_class, result_repr))
|
||||
|
||||
|
@ -362,7 +362,7 @@ class ChangeList(object):
|
||||
try:
|
||||
attr = getattr(self.model, field_name)
|
||||
order_field = attr.admin_order_field
|
||||
except IndexError:
|
||||
except AttributeError:
|
||||
pass
|
||||
else:
|
||||
if not isinstance(f.rel, models.ManyToOneRel) or not f.null:
|
||||
|
@ -12,6 +12,8 @@ def load_backend(path):
|
||||
mod = __import__(module, {}, {}, [attr])
|
||||
except ImportError, e:
|
||||
raise ImproperlyConfigured, 'Error importing authentication backend %s: "%s"' % (module, e)
|
||||
except ValueError, e:
|
||||
raise ImproperlyConfigured, 'Error importing authentication backends. Is AUTHENTICATION_BACKENDS a correctly defined list or tuple?'
|
||||
try:
|
||||
cls = getattr(mod, attr)
|
||||
except AttributeError:
|
||||
|
@ -10,10 +10,10 @@ class UserCreationForm(oldforms.Manipulator):
|
||||
"A form that creates a user, with no privileges, from the given username and password."
|
||||
def __init__(self):
|
||||
self.fields = (
|
||||
oldforms.TextField(field_name='username', length=30, maxlength=30, is_required=True,
|
||||
oldforms.TextField(field_name='username', length=30, max_length=30, is_required=True,
|
||||
validator_list=[validators.isAlphaNumeric, self.isValidUsername]),
|
||||
oldforms.PasswordField(field_name='password1', length=30, maxlength=60, is_required=True),
|
||||
oldforms.PasswordField(field_name='password2', length=30, maxlength=60, is_required=True,
|
||||
oldforms.PasswordField(field_name='password1', length=30, max_length=60, is_required=True),
|
||||
oldforms.PasswordField(field_name='password2', length=30, max_length=60, is_required=True,
|
||||
validator_list=[validators.AlwaysMatchesOtherField('password1', _("The two password fields didn't match."))]),
|
||||
)
|
||||
|
||||
@ -42,9 +42,9 @@ class AuthenticationForm(oldforms.Manipulator):
|
||||
"""
|
||||
self.request = request
|
||||
self.fields = [
|
||||
oldforms.TextField(field_name="username", length=15, maxlength=30, is_required=True,
|
||||
oldforms.TextField(field_name="username", length=15, max_length=30, is_required=True,
|
||||
validator_list=[self.isValidUser, self.hasCookiesEnabled]),
|
||||
oldforms.PasswordField(field_name="password", length=15, maxlength=30, is_required=True),
|
||||
oldforms.PasswordField(field_name="password", length=15, max_length=30, is_required=True),
|
||||
]
|
||||
self.user_cache = None
|
||||
|
||||
@ -111,11 +111,11 @@ class PasswordChangeForm(oldforms.Manipulator):
|
||||
def __init__(self, user):
|
||||
self.user = user
|
||||
self.fields = (
|
||||
oldforms.PasswordField(field_name="old_password", length=30, maxlength=30, is_required=True,
|
||||
oldforms.PasswordField(field_name="old_password", length=30, max_length=30, is_required=True,
|
||||
validator_list=[self.isValidOldPassword]),
|
||||
oldforms.PasswordField(field_name="new_password1", length=30, maxlength=30, is_required=True,
|
||||
oldforms.PasswordField(field_name="new_password1", length=30, max_length=30, is_required=True,
|
||||
validator_list=[validators.AlwaysMatchesOtherField('new_password2', _("The two 'new password' fields didn't match."))]),
|
||||
oldforms.PasswordField(field_name="new_password2", length=30, maxlength=30, is_required=True),
|
||||
oldforms.PasswordField(field_name="new_password2", length=30, max_length=30, is_required=True),
|
||||
)
|
||||
|
||||
def isValidOldPassword(self, new_data, all_data):
|
||||
@ -133,8 +133,8 @@ class AdminPasswordChangeForm(oldforms.Manipulator):
|
||||
def __init__(self, user):
|
||||
self.user = user
|
||||
self.fields = (
|
||||
oldforms.PasswordField(field_name='password1', length=30, maxlength=60, is_required=True),
|
||||
oldforms.PasswordField(field_name='password2', length=30, maxlength=60, is_required=True,
|
||||
oldforms.PasswordField(field_name='password1', length=30, max_length=60, is_required=True),
|
||||
oldforms.PasswordField(field_name='password2', length=30, max_length=60, is_required=True,
|
||||
validator_list=[validators.AlwaysMatchesOtherField('password1', _("The two password fields didn't match."))]),
|
||||
)
|
||||
|
||||
|
@ -7,6 +7,8 @@ from django.utils.translation import ugettext_lazy as _
|
||||
import datetime
|
||||
import urllib
|
||||
|
||||
UNUSABLE_PASSWORD = '!' # This will never be a valid hash
|
||||
|
||||
try:
|
||||
set
|
||||
except NameError:
|
||||
@ -48,9 +50,9 @@ class Permission(models.Model):
|
||||
|
||||
Three basic permissions -- add, change and delete -- are automatically created for each Django model.
|
||||
"""
|
||||
name = models.CharField(_('name'), maxlength=50)
|
||||
name = models.CharField(_('name'), max_length=50)
|
||||
content_type = models.ForeignKey(ContentType)
|
||||
codename = models.CharField(_('codename'), maxlength=100)
|
||||
codename = models.CharField(_('codename'), max_length=100)
|
||||
|
||||
class Meta:
|
||||
verbose_name = _('permission')
|
||||
@ -68,7 +70,7 @@ class Group(models.Model):
|
||||
|
||||
Beyond permissions, groups are a convenient way to categorize users to apply some label, or extended functionality, to them. For example, you could create a group 'Special users', and you could write code that would do special things to those users -- such as giving them access to a members-only portion of your site, or sending them members-only e-mail messages.
|
||||
"""
|
||||
name = models.CharField(_('name'), maxlength=80, unique=True)
|
||||
name = models.CharField(_('name'), max_length=80, unique=True)
|
||||
permissions = models.ManyToManyField(Permission, verbose_name=_('permissions'), blank=True)
|
||||
|
||||
class Meta:
|
||||
@ -80,11 +82,14 @@ class Group(models.Model):
|
||||
return self.name
|
||||
|
||||
class UserManager(models.Manager):
|
||||
def create_user(self, username, email, password):
|
||||
def create_user(self, username, email, password=None):
|
||||
"Creates and saves a User with the given username, e-mail and password."
|
||||
now = datetime.datetime.now()
|
||||
user = self.model(None, username, '', '', email.strip().lower(), 'placeholder', False, True, False, now, now)
|
||||
user.set_password(password)
|
||||
if password:
|
||||
user.set_password(password)
|
||||
else:
|
||||
user.set_unusable_password()
|
||||
user.save()
|
||||
return user
|
||||
|
||||
@ -100,11 +105,11 @@ class User(models.Model):
|
||||
|
||||
Username and password are required. Other fields are optional.
|
||||
"""
|
||||
username = models.CharField(_('username'), maxlength=30, unique=True, validator_list=[validators.isAlphaNumeric], help_text=_("Required. 30 characters or fewer. Alphanumeric characters only (letters, digits and underscores)."))
|
||||
first_name = models.CharField(_('first name'), maxlength=30, blank=True)
|
||||
last_name = models.CharField(_('last name'), maxlength=30, blank=True)
|
||||
username = models.CharField(_('username'), max_length=30, unique=True, validator_list=[validators.isAlphaNumeric], help_text=_("Required. 30 characters or fewer. Alphanumeric characters only (letters, digits and underscores)."))
|
||||
first_name = models.CharField(_('first name'), max_length=30, blank=True)
|
||||
last_name = models.CharField(_('last name'), max_length=30, blank=True)
|
||||
email = models.EmailField(_('e-mail address'), blank=True)
|
||||
password = models.CharField(_('password'), maxlength=128, help_text=_("Use '[algo]$[salt]$[hexdigest]' or use the <a href=\"password/\">change password form</a>."))
|
||||
password = models.CharField(_('password'), max_length=128, help_text=_("Use '[algo]$[salt]$[hexdigest]' or use the <a href=\"password/\">change password form</a>."))
|
||||
is_staff = models.BooleanField(_('staff status'), default=False, help_text=_("Designates whether the user can log into this admin site."))
|
||||
is_active = models.BooleanField(_('active'), default=True, help_text=_("Designates whether this user can log into the Django admin. Unselect this instead of deleting accounts."))
|
||||
is_superuser = models.BooleanField(_('superuser status'), default=False, help_text=_("Designates that this user has all permissions without explicitly assigning them."))
|
||||
@ -164,6 +169,13 @@ class User(models.Model):
|
||||
return is_correct
|
||||
return check_password(raw_password, self.password)
|
||||
|
||||
def set_unusable_password(self):
|
||||
# Sets a value that will never be a valid hash
|
||||
self.password = UNUSABLE_PASSWORD
|
||||
|
||||
def has_usable_password(self):
|
||||
return self.password != UNUSABLE_PASSWORD
|
||||
|
||||
def get_group_permissions(self):
|
||||
"Returns a list of permission strings that this user has through his/her groups."
|
||||
if not hasattr(self, '_group_perm_cache'):
|
||||
@ -253,7 +265,8 @@ class User(models.Model):
|
||||
return self._profile_cache
|
||||
|
||||
class Message(models.Model):
|
||||
"""The message system is a lightweight way to queue messages for given users. A message is associated with a User instance (so it is only applicable for registered users). There's no concept of expiration or timestamps. Messages are created by the Django admin after successful actions. For example, "The poll Foo was created successfully." is a message.
|
||||
"""
|
||||
The message system is a lightweight way to queue messages for given users. A message is associated with a User instance (so it is only applicable for registered users). There's no concept of expiration or timestamps. Messages are created by the Django admin after successful actions. For example, "The poll Foo was created successfully." is a message.
|
||||
"""
|
||||
user = models.ForeignKey(User)
|
||||
message = models.TextField(_('message'))
|
||||
|
19
django/contrib/auth/tests.py
Normal file
19
django/contrib/auth/tests.py
Normal file
@ -0,0 +1,19 @@
|
||||
"""
|
||||
>>> from models import User
|
||||
>>> u = User.objects.create_user('testuser', 'test@example.com', 'testpw')
|
||||
>>> u.has_usable_password()
|
||||
True
|
||||
>>> u.check_password('bad')
|
||||
False
|
||||
>>> u.check_password('testpw')
|
||||
True
|
||||
>>> u.set_unusable_password()
|
||||
>>> u.save()
|
||||
>>> u.check_password('testpw')
|
||||
False
|
||||
>>> u.has_usable_password()
|
||||
False
|
||||
>>> u2 = User.objects.create_user('testuser2', 'test2@example.com')
|
||||
>>> u2.has_usable_password()
|
||||
False
|
||||
"""
|
@ -65,8 +65,8 @@ class Comment(models.Model):
|
||||
user = models.ForeignKey(User)
|
||||
content_type = models.ForeignKey(ContentType)
|
||||
object_id = models.IntegerField(_('object ID'))
|
||||
headline = models.CharField(_('headline'), maxlength=255, blank=True)
|
||||
comment = models.TextField(_('comment'), maxlength=3000)
|
||||
headline = models.CharField(_('headline'), max_length=255, blank=True)
|
||||
comment = models.TextField(_('comment'), max_length=3000)
|
||||
rating1 = models.PositiveSmallIntegerField(_('rating #1'), blank=True, null=True)
|
||||
rating2 = models.PositiveSmallIntegerField(_('rating #2'), blank=True, null=True)
|
||||
rating3 = models.PositiveSmallIntegerField(_('rating #3'), blank=True, null=True)
|
||||
@ -154,8 +154,8 @@ class FreeComment(models.Model):
|
||||
# A FreeComment is a comment by a non-registered user.
|
||||
content_type = models.ForeignKey(ContentType)
|
||||
object_id = models.IntegerField(_('object ID'))
|
||||
comment = models.TextField(_('comment'), maxlength=3000)
|
||||
person_name = models.CharField(_("person's name"), maxlength=50)
|
||||
comment = models.TextField(_('comment'), max_length=3000)
|
||||
person_name = models.CharField(_("person's name"), max_length=50)
|
||||
submit_date = models.DateTimeField(_('date/time submitted'), auto_now_add=True)
|
||||
is_public = models.BooleanField(_('is public'))
|
||||
ip_address = models.IPAddressField(_('ip address'))
|
||||
|
@ -5,6 +5,7 @@ from django import template
|
||||
from django.template import loader
|
||||
from django.core.exceptions import ObjectDoesNotExist
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.utils.encoding import smart_str
|
||||
import re
|
||||
|
||||
register = template.Library()
|
||||
@ -174,6 +175,7 @@ class DoCommentForm:
|
||||
if tokens[4] != 'with':
|
||||
raise template.TemplateSyntaxError, "Fourth argument in %r tag must be 'with'" % tokens[0]
|
||||
for option, args in zip(tokens[5::2], tokens[6::2]):
|
||||
option = smart_str(option)
|
||||
if option in ('photos_optional', 'photos_required') and not self.free:
|
||||
# VALIDATION ##############################################
|
||||
option_list = args.split(',')
|
||||
|
@ -29,7 +29,7 @@ class PublicCommentManipulator(AuthenticationForm):
|
||||
else:
|
||||
return []
|
||||
self.fields.extend([
|
||||
oldforms.LargeTextField(field_name="comment", maxlength=3000, is_required=True,
|
||||
oldforms.LargeTextField(field_name="comment", max_length=3000, is_required=True,
|
||||
validator_list=[self.hasNoProfanities]),
|
||||
oldforms.RadioSelectField(field_name="rating1", choices=choices,
|
||||
is_required=ratings_required and num_rating_choices > 0,
|
||||
@ -122,9 +122,9 @@ class PublicFreeCommentManipulator(oldforms.Manipulator):
|
||||
"Manipulator that handles public free (unregistered) comments"
|
||||
def __init__(self):
|
||||
self.fields = (
|
||||
oldforms.TextField(field_name="person_name", maxlength=50, is_required=True,
|
||||
oldforms.TextField(field_name="person_name", max_length=50, is_required=True,
|
||||
validator_list=[self.hasNoProfanities]),
|
||||
oldforms.LargeTextField(field_name="comment", maxlength=3000, is_required=True,
|
||||
oldforms.LargeTextField(field_name="comment", max_length=3000, is_required=True,
|
||||
validator_list=[self.hasNoProfanities]),
|
||||
)
|
||||
|
||||
|
@ -32,9 +32,9 @@ class ContentTypeManager(models.Manager):
|
||||
CONTENT_TYPE_CACHE = {}
|
||||
|
||||
class ContentType(models.Model):
|
||||
name = models.CharField(maxlength=100)
|
||||
app_label = models.CharField(maxlength=100)
|
||||
model = models.CharField(_('python model class name'), maxlength=100)
|
||||
name = models.CharField(max_length=100)
|
||||
app_label = models.CharField(max_length=100)
|
||||
model = models.CharField(_('python model class name'), max_length=100)
|
||||
objects = ContentTypeManager()
|
||||
class Meta:
|
||||
verbose_name = _('content type')
|
||||
|
@ -37,9 +37,10 @@ class FieldChoicePlugin(DatabrowsePlugin):
|
||||
|
||||
def urls(self, plugin_name, easy_instance_field):
|
||||
if easy_instance_field.field in self.field_dict(easy_instance_field.model.model).values():
|
||||
field_value = smart_str(easy_instance_field.raw_value)
|
||||
return [u'%s%s/%s/%s/' % (easy_instance_field.model.url(),
|
||||
plugin_name, easy_instance_field.field.name,
|
||||
urllib.quote(smart_str(easy_instance_field.raw_value)))]
|
||||
urllib.quote(field_value, safe=''))]
|
||||
|
||||
def model_view(self, request, model_databrowse, url):
|
||||
self.model, self.site = model_databrowse.model, model_databrowse.site
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
<ul class="objectlist">
|
||||
{% for object in object_list %}
|
||||
<li class="{% cycle odd,even %}"><a href="{{ object.url }}">{{ object }}</a></li>
|
||||
<li class="{% cycle odd,even %}"><a href="{{ object.url }}">{{ object|escape }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
<ul class="objectlist">
|
||||
{% for object in object_list %}
|
||||
<li class="{% cycle odd,even %}"><a href="{{ object.url }}">{{ object }}</a></li>
|
||||
<li class="{% cycle odd,even %}"><a href="{{ object.url }}">{{ object|escape }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
<ul class="objectlist">
|
||||
{% for object in object_list %}
|
||||
<li class="{% cycle odd,even %}"><a href="{{ object.url }}">{{ object }}</a></li>
|
||||
<li class="{% cycle odd,even %}"><a href="{{ object.url }}">{{ object|escape }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
<ul class="objectlist">
|
||||
{% for choice in field.choices %}
|
||||
<li class="{% cycle odd,even %}"><a href="{{ choice.url }}">{{ choice.label }}</a></li>
|
||||
<li class="{% cycle odd,even %}"><a href="{{ choice.url }}">{{ choice.label|escape }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
|
@ -11,7 +11,7 @@
|
||||
<h2><a href="{{ model.url }}">{{ model.verbose_name_plural|capfirst }}</a></h2>
|
||||
<p>
|
||||
{% for object in model.sample_objects %}
|
||||
<a href="{{ object.url }}">{{ object }}</a>,
|
||||
<a href="{{ object.url }}">{{ object|escape }}</a>,
|
||||
{% endfor %}
|
||||
<a class="more" href="{{ model.url }}">More →</a>
|
||||
</p>
|
||||
|
@ -12,7 +12,7 @@
|
||||
|
||||
<ul class="objectlist">
|
||||
{% for object in model.objects %}
|
||||
<li class="{% cycle odd,even %}"><a href="{{ object.url }}">{{ object }}</a></li>
|
||||
<li class="{% cycle odd,even %}"><a href="{{ object.url }}">{{ object|escape }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
|
@ -4,9 +4,9 @@
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div id="breadcrumbs"><a href="{{ root_url }}">Home</a> / <a href="{{ object.model.url }}">{{ object.model.verbose_name_plural|capfirst }}</a> / {{ object }}</div>
|
||||
<div id="breadcrumbs"><a href="{{ root_url }}">Home</a> / <a href="{{ object.model.url }}">{{ object.model.verbose_name_plural|capfirst }}</a> / {{ object|escape }}</div>
|
||||
|
||||
<h1>{{ object.model.verbose_name|capfirst }}: {{ object }}</h1>
|
||||
<h1>{{ object.model.verbose_name|capfirst }}: {{ object|escape }}</h1>
|
||||
|
||||
<table class="objectinfo">
|
||||
{% for field in object.fields %}
|
||||
@ -14,8 +14,8 @@
|
||||
<th>{{ field.field.verbose_name|capfirst }}</th>
|
||||
<td>
|
||||
{% if field.urls %}
|
||||
{% for urlvalue in field.urls %}
|
||||
{% if urlvalue.1 %}<a href="{{ urlvalue.1 }}">{% endif %}{{ urlvalue.0 }}{% if urlvalue.1 %}</a>{% endif %}{% if not forloop.last %}, {% endif %}
|
||||
{% for value, url in field.urls %}
|
||||
{% if url %}<a href="{{ url }}">{% endif %}{{ value|escape }}{% if url %}</a>{% endif %}{% if not forloop.last %}, {% endif %}
|
||||
{% endfor %}
|
||||
{% else %}None{% endif %}
|
||||
</td>
|
||||
@ -29,7 +29,7 @@
|
||||
{% if related_object.object_list %}
|
||||
<ul class="objectlist">
|
||||
{% for object in related_object.object_list %}
|
||||
<li class="{% cycle odd,even %}"><a href="{{ object.url }}">{{ object }}</a></li>
|
||||
<li class="{% cycle odd,even %}"><a href="{{ object.url }}">{{ object|escape }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% else %}
|
||||
|
@ -4,12 +4,12 @@ from django.contrib.sites.models import Site
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
class FlatPage(models.Model):
|
||||
url = models.CharField(_('URL'), maxlength=100, validator_list=[validators.isAlphaNumericURL], db_index=True,
|
||||
url = models.CharField(_('URL'), max_length=100, validator_list=[validators.isAlphaNumericURL], db_index=True,
|
||||
help_text=_("Example: '/about/contact/'. Make sure to have leading and trailing slashes."))
|
||||
title = models.CharField(_('title'), maxlength=200)
|
||||
title = models.CharField(_('title'), max_length=200)
|
||||
content = models.TextField(_('content'))
|
||||
enable_comments = models.BooleanField(_('enable comments'))
|
||||
template_name = models.CharField(_('template name'), maxlength=70, blank=True,
|
||||
template_name = models.CharField(_('template name'), max_length=70, blank=True,
|
||||
help_text=_("Example: 'flatpages/contact_page.html'. If this isn't provided, the system will use 'flatpages/default.html'."))
|
||||
registration_required = models.BooleanField(_('registration required'), help_text=_("If this is checked, only logged-in users will be able to view the page."))
|
||||
sites = models.ManyToManyField(Site)
|
||||
|
25
django/contrib/localflavor/cl/cl_regions.py
Normal file
25
django/contrib/localflavor/cl/cl_regions.py
Normal file
@ -0,0 +1,25 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
A list of Chilean regions as `choices` in a formfield.
|
||||
|
||||
This exists in this standalone file so that it's only imported into memory
|
||||
when explicitly needed.
|
||||
"""
|
||||
|
||||
REGION_CHOICES = (
|
||||
('RM', u'Región Metropolitana de Santiago'),
|
||||
('I', u'Región de Tarapacá'),
|
||||
('II', u'Región de Antofagasta'),
|
||||
('III', u'Región de Atacama'),
|
||||
('IV', u'Región de Coquimbo'),
|
||||
('V', u'Región de Valparaíso'),
|
||||
('VI', u'Región del Libertador Bernardo O\'Higgins'),
|
||||
('VII', u'Región del Maule'),
|
||||
('VIII',u'Región del Bío Bío'),
|
||||
('IX', u'Región de la Araucanía'),
|
||||
('X', u'Región de los Lagos'),
|
||||
('XI', u'Región de Aysén del General Carlos Ibáñez del Campo'),
|
||||
('XII', u'Región de Magallanes y la Antártica Chilena'),
|
||||
('XIV', u'Región de Los Ríos'),
|
||||
('XV', u'Región de Arica-Parinacota'),
|
||||
)
|
@ -3,10 +3,20 @@ Chile specific form helpers.
|
||||
"""
|
||||
|
||||
from django.newforms import ValidationError
|
||||
from django.newforms.fields import RegexField, EMPTY_VALUES
|
||||
from django.newforms.fields import RegexField, Select, EMPTY_VALUES
|
||||
from django.utils.translation import ugettext
|
||||
from django.utils.encoding import smart_unicode
|
||||
|
||||
|
||||
class CLRegionSelect(Select):
|
||||
"""
|
||||
A Select widget that uses a list of Chilean Regions (Regiones)
|
||||
as its choices.
|
||||
"""
|
||||
def __init__(self, attrs=None):
|
||||
from cl_regions import REGION_CHOICES
|
||||
super(CLRegionSelect, self).__init__(attrs, choices=REGION_CHOICES)
|
||||
|
||||
class CLRutField(RegexField):
|
||||
"""
|
||||
Chilean "Rol Unico Tributario" (RUT) field. This is the Chilean national
|
||||
|
@ -1,4 +1,3 @@
|
||||
# -*- coding: iso-8859-1 -*-
|
||||
"""
|
||||
Norwegian-specific Form helpers
|
||||
"""
|
||||
@ -66,7 +65,7 @@ class NOSocialSecurityNumber(Field):
|
||||
weight_2 = [5, 4, 3, 2, 7, 6, 5, 4, 3, 2, 1]
|
||||
|
||||
def multiply_reduce(aval, bval):
|
||||
return sum((a * b) for (a, b) in zip(aval, bval))
|
||||
return sum([(a * b) for (a, b) in zip(aval, bval)])
|
||||
|
||||
if multiply_reduce(digits, weight_1) % 11 != 0:
|
||||
raise ValidationError(msg)
|
||||
|
0
django/contrib/localflavor/sk/__init__.py
Normal file
0
django/contrib/localflavor/sk/__init__.py
Normal file
41
django/contrib/localflavor/sk/forms.py
Normal file
41
django/contrib/localflavor/sk/forms.py
Normal file
@ -0,0 +1,41 @@
|
||||
"""
|
||||
Slovak-specific form helpers
|
||||
"""
|
||||
|
||||
from django.newforms.fields import Select, RegexField
|
||||
from django.utils.translation import ugettext
|
||||
|
||||
class SKRegionSelect(Select):
|
||||
"""
|
||||
A select widget widget with list of Slovak regions as choices.
|
||||
"""
|
||||
def __init__(self, attrs=None):
|
||||
from sk_regions import REGION_CHOICES
|
||||
super(SKRegionSelect, self).__init__(attrs, choices=REGION_CHOICES)
|
||||
|
||||
class SKDistrictSelect(Select):
|
||||
"""
|
||||
A select widget with list of Slovak districts as choices.
|
||||
"""
|
||||
def __init__(self, attrs=None):
|
||||
from sk_districts import DISTRICT_CHOICES
|
||||
super(SKDistrictSelect, self).__init__(attrs, choices=DISTRICT_CHOICES)
|
||||
|
||||
class SKPostalCodeField(RegexField):
|
||||
"""
|
||||
A form field that validates its input as Slovak postal code.
|
||||
Valid form is XXXXX or XXX XX, where X represents integer.
|
||||
"""
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(SKPostalCodeField, self).__init__(r'^\d{5}$|^\d{3} \d{2}$',
|
||||
max_length=None, min_length=None,
|
||||
error_message=ugettext(u'Enter a postal code in the format XXXXX or XXX XX.'),
|
||||
*args, **kwargs)
|
||||
|
||||
def clean(self, value):
|
||||
"""
|
||||
Validates the input and returns a string that contains only numbers.
|
||||
Returns an empty string for empty values.
|
||||
"""
|
||||
v = super(SKPostalCodeField, self).clean(value)
|
||||
return v.replace(' ', '')
|
87
django/contrib/localflavor/sk/sk_districts.py
Normal file
87
django/contrib/localflavor/sk/sk_districts.py
Normal file
@ -0,0 +1,87 @@
|
||||
"""
|
||||
Slovak districts according to http://sk.wikipedia.org/wiki/Administrat%C3%ADvne_%C4%8Dlenenie_Slovenska
|
||||
"""
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
DISTRICT_CHOICES = (
|
||||
('BB', _('Banska Bystrica')),
|
||||
('BS', _('Banska Stiavnica')),
|
||||
('BJ', _('Bardejov')),
|
||||
('BN', _('Banovce nad Bebravou')),
|
||||
('BR', _('Brezno')),
|
||||
('BA1', _('Bratislava I')),
|
||||
('BA2', _('Bratislava II')),
|
||||
('BA3', _('Bratislava III')),
|
||||
('BA4', _('Bratislava IV')),
|
||||
('BA5', _('Bratislava V')),
|
||||
('BY', _('Bytca')),
|
||||
('CA', _('Cadca')),
|
||||
('DT', _('Detva')),
|
||||
('DK', _('Dolny Kubin')),
|
||||
('DS', _('Dunajska Streda')),
|
||||
('GA', _('Galanta')),
|
||||
('GL', _('Gelnica')),
|
||||
('HC', _('Hlohovec')),
|
||||
('HE', _('Humenne')),
|
||||
('IL', _('Ilava')),
|
||||
('KK', _('Kezmarok')),
|
||||
('KN', _('Komarno')),
|
||||
('KE1', _('Kosice I')),
|
||||
('KE2', _('Kosice II')),
|
||||
('KE3', _('Kosice III')),
|
||||
('KE4', _('Kosice IV')),
|
||||
('KEO', _('Kosice - okolie')),
|
||||
('KA', _('Krupina')),
|
||||
('KM', _('Kysucke Nove Mesto')),
|
||||
('LV', _('Levice')),
|
||||
('LE', _('Levoca')),
|
||||
('LM', _('Liptovsky Mikulas')),
|
||||
('LC', _('Lucenec')),
|
||||
('MA', _('Malacky')),
|
||||
('MT', _('Martin')),
|
||||
('ML', _('Medzilaborce')),
|
||||
('MI', _('Michalovce')),
|
||||
('MY', _('Myjava')),
|
||||
('NO', _('Namestovo')),
|
||||
('NR', _('Nitra')),
|
||||
('NM', _('Nove Mesto nad Vahom')),
|
||||
('NZ', _('Nove Zamky')),
|
||||
('PE', _('Partizanske')),
|
||||
('PK', _('Pezinok')),
|
||||
('PN', _('Piestany')),
|
||||
('PT', _('Poltar')),
|
||||
('PP', _('Poprad')),
|
||||
('PB', _('Povazska Bystrica')),
|
||||
('PO', _('Presov')),
|
||||
('PD', _('Prievidza')),
|
||||
('PU', _('Puchov')),
|
||||
('RA', _('Revuca')),
|
||||
('RS', _('Rimavska Sobota')),
|
||||
('RV', _('Roznava')),
|
||||
('RK', _('Ruzomberok')),
|
||||
('SB', _('Sabinov')),
|
||||
('SC', _('Senec')),
|
||||
('SE', _('Senica')),
|
||||
('SI', _('Skalica')),
|
||||
('SV', _('Snina')),
|
||||
('SO', _('Sobrance')),
|
||||
('SN', _('Spisska Nova Ves')),
|
||||
('SL', _('Stara Lubovna')),
|
||||
('SP', _('Stropkov')),
|
||||
('SK', _('Svidnik')),
|
||||
('SA', _('Sala')),
|
||||
('TO', _('Topolcany')),
|
||||
('TV', _('Trebisov')),
|
||||
('TN', _('Trencin')),
|
||||
('TT', _('Trnava')),
|
||||
('TR', _('Turcianske Teplice')),
|
||||
('TS', _('Tvrdosin')),
|
||||
('VK', _('Velky Krtis')),
|
||||
('VT', _('Vranov nad Toplou')),
|
||||
('ZM', _('Zlate Moravce')),
|
||||
('ZV', _('Zvolen')),
|
||||
('ZC', _('Zarnovica')),
|
||||
('ZH', _('Ziar nad Hronom')),
|
||||
('ZA', _('Zilina')),
|
||||
)
|
16
django/contrib/localflavor/sk/sk_regions.py
Normal file
16
django/contrib/localflavor/sk/sk_regions.py
Normal file
@ -0,0 +1,16 @@
|
||||
"""
|
||||
Slovak regions according to http://sk.wikipedia.org/wiki/Administrat%C3%ADvne_%C4%8Dlenenie_Slovenska
|
||||
"""
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
REGION_CHOICES = (
|
||||
('BB', _('Banska Bystrica region')),
|
||||
('BA', _('Bratislava region')),
|
||||
('KE', _('Kosice region')),
|
||||
('NR', _('Nitra region')),
|
||||
('PO', _('Presov region')),
|
||||
('TN', _('Trencin region')),
|
||||
('TT', _('Trnava region')),
|
||||
('ZA', _('Zilina region')),
|
||||
)
|
@ -4,9 +4,9 @@ from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
class Redirect(models.Model):
|
||||
site = models.ForeignKey(Site, radio_admin=models.VERTICAL)
|
||||
old_path = models.CharField(_('redirect from'), maxlength=200, db_index=True,
|
||||
old_path = models.CharField(_('redirect from'), max_length=200, db_index=True,
|
||||
help_text=_("This should be an absolute path, excluding the domain name. Example: '/events/search/'."))
|
||||
new_path = models.CharField(_('redirect to'), maxlength=200, blank=True,
|
||||
new_path = models.CharField(_('redirect to'), max_length=200, blank=True,
|
||||
help_text=_("This can be either an absolute path (as above) or a full URL starting with 'http://'."))
|
||||
|
||||
class Meta:
|
||||
|
@ -2,7 +2,9 @@ from django.conf import settings
|
||||
from django.contrib.sessions.models import Session
|
||||
from django.core.exceptions import SuspiciousOperation
|
||||
from django.utils.cache import patch_vary_headers
|
||||
from email.Utils import formatdate
|
||||
import datetime
|
||||
import time
|
||||
|
||||
TEST_COOKIE_NAME = 'testcookie'
|
||||
TEST_COOKIE_VALUE = 'worked'
|
||||
@ -37,7 +39,7 @@ class SessionWrapper(object):
|
||||
return self._session.get(key, default)
|
||||
|
||||
def pop(self, key, *args):
|
||||
self.modified = self.modified or key in self._session
|
||||
self.modified = self.modified or key in self._session
|
||||
return self._session.pop(key, *args)
|
||||
|
||||
def set_test_cookie(self):
|
||||
@ -98,7 +100,11 @@ class SessionMiddleware(object):
|
||||
expires = None
|
||||
else:
|
||||
max_age = settings.SESSION_COOKIE_AGE
|
||||
expires = datetime.datetime.strftime(datetime.datetime.utcnow() + datetime.timedelta(seconds=settings.SESSION_COOKIE_AGE), "%a, %d-%b-%Y %H:%M:%S GMT")
|
||||
rfcdate = formatdate(time.time() + settings.SESSION_COOKIE_AGE)
|
||||
# Fixed length date must have '-' separation in the format
|
||||
# DD-MMM-YYYY for compliance with Netscape cookie standard
|
||||
expires = (rfcdate[:7] + "-" + rfcdate[8:11]
|
||||
+ "-" + rfcdate[12:26] + "GMT")
|
||||
new_session = Session.objects.save(session_key, request.session._session,
|
||||
datetime.datetime.now() + datetime.timedelta(seconds=settings.SESSION_COOKIE_AGE))
|
||||
response.set_cookie(settings.SESSION_COOKIE_NAME, session_key,
|
||||
|
@ -65,7 +65,7 @@ class Session(models.Model):
|
||||
the sessions documentation that is shipped with Django (also available
|
||||
on the Django website).
|
||||
"""
|
||||
session_key = models.CharField(_('session key'), maxlength=40, primary_key=True)
|
||||
session_key = models.CharField(_('session key'), max_length=40, primary_key=True)
|
||||
session_data = models.TextField(_('session data'))
|
||||
expire_date = models.DateTimeField(_('expire date'))
|
||||
objects = SessionManager()
|
||||
|
@ -4,11 +4,16 @@ from django.utils.translation import ugettext_lazy as _
|
||||
class SiteManager(models.Manager):
|
||||
def get_current(self):
|
||||
from django.conf import settings
|
||||
return self.get(pk=settings.SITE_ID)
|
||||
try:
|
||||
sid = settings.SITE_ID
|
||||
except AttributeError:
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
raise ImproperlyConfigured("You're using the Django \"sites framework\" without having set the SITE_ID setting. Create a site in your database and set the SITE_ID setting to fix this error.")
|
||||
return self.get(pk=sid)
|
||||
|
||||
class Site(models.Model):
|
||||
domain = models.CharField(_('domain name'), maxlength=100)
|
||||
name = models.CharField(_('display name'), maxlength=50)
|
||||
domain = models.CharField(_('domain name'), max_length=100)
|
||||
name = models.CharField(_('display name'), max_length=50)
|
||||
objects = SiteManager()
|
||||
|
||||
class Meta:
|
||||
@ -31,3 +36,20 @@ class SiteAdmin(admin.ModelAdmin):
|
||||
search_fields = ('domain', 'name')
|
||||
|
||||
admin.site.register(Site, SiteAdmin)
|
||||
|
||||
class RequestSite(object):
|
||||
"""
|
||||
A class that shares the primary interface of Site (i.e., it has
|
||||
``domain`` and ``name`` attributes) but gets its data from a Django
|
||||
HttpRequest object rather than from a database.
|
||||
|
||||
The save() and delete() methods raise NotImplementedError.
|
||||
"""
|
||||
def __init__(self, request):
|
||||
self.domain = self.name = request.META['SERVER_NAME']
|
||||
|
||||
def save(self):
|
||||
raise NotImplementedError('RequestSite cannot be saved.')
|
||||
|
||||
def delete(self):
|
||||
raise NotImplementedError('RequestSite cannot be deleted.')
|
||||
|
@ -1,15 +1,15 @@
|
||||
from django.core.exceptions import ImproperlyConfigured, ObjectDoesNotExist
|
||||
from django.template import Context, loader, Template, TemplateDoesNotExist
|
||||
from django.contrib.sites.models import Site
|
||||
from django.contrib.sites.models import Site, RequestSite
|
||||
from django.utils import feedgenerator
|
||||
from django.utils.encoding import smart_unicode
|
||||
from django.utils.encoding import smart_unicode, iri_to_uri
|
||||
from django.conf import settings
|
||||
|
||||
def add_domain(domain, url):
|
||||
if not url.startswith('http://'):
|
||||
# 'url' must already be ASCII and URL-quoted, so no need for encoding
|
||||
# conversions here.
|
||||
url = u'http://%s%s' % (domain, url)
|
||||
url = iri_to_uri(u'http://%s%s' % (domain, url))
|
||||
return url
|
||||
|
||||
class FeedDoesNotExist(ObjectDoesNotExist):
|
||||
@ -22,9 +22,10 @@ class Feed(object):
|
||||
title_template = None
|
||||
description_template = None
|
||||
|
||||
def __init__(self, slug, feed_url):
|
||||
def __init__(self, slug, request):
|
||||
self.slug = slug
|
||||
self.feed_url = feed_url
|
||||
self.request = request
|
||||
self.feed_url = request.path
|
||||
self.title_template_name = self.title_template or ('feeds/%s_title.html' % slug)
|
||||
self.description_template_name = self.description_template or ('feeds/%s_description.html' % slug)
|
||||
|
||||
@ -67,7 +68,11 @@ class Feed(object):
|
||||
else:
|
||||
obj = None
|
||||
|
||||
current_site = Site.objects.get_current()
|
||||
if Site._meta.installed:
|
||||
current_site = Site.objects.get_current()
|
||||
else:
|
||||
current_site = RequestSite(self.request)
|
||||
|
||||
link = self.__get_dynamic_attr('link', obj)
|
||||
link = add_domain(current_site.domain, link)
|
||||
|
||||
@ -83,6 +88,7 @@ class Feed(object):
|
||||
author_email = self.__get_dynamic_attr('author_email', obj),
|
||||
categories = self.__get_dynamic_attr('categories', obj),
|
||||
feed_copyright = self.__get_dynamic_attr('feed_copyright', obj),
|
||||
feed_guid = self.__get_dynamic_attr('feed_guid', obj),
|
||||
)
|
||||
|
||||
try:
|
||||
@ -114,7 +120,7 @@ class Feed(object):
|
||||
title = title_tmp.render(Context({'obj': item, 'site': current_site})),
|
||||
link = link,
|
||||
description = description_tmp.render(Context({'obj': item, 'site': current_site})),
|
||||
unique_id = link,
|
||||
unique_id = self.__get_dynamic_attr('item_guid', item, link),
|
||||
enclosure = enc,
|
||||
pubdate = self.__get_dynamic_attr('item_pubdate', item),
|
||||
author_name = author_name,
|
||||
|
@ -16,7 +16,7 @@ def feed(request, url, feed_dict=None):
|
||||
raise Http404, "Slug %r isn't registered." % slug
|
||||
|
||||
try:
|
||||
feedgen = f(slug, request.path).get_feed(param)
|
||||
feedgen = f(slug, request).get_feed(param)
|
||||
except feeds.FeedDoesNotExist:
|
||||
raise Http404, "Invalid feed parameters. Slug %r is valid, but other parameters, or lack thereof, are not." % slug
|
||||
|
||||
|
5
django/core/cache/backends/filebased.py
vendored
5
django/core/cache/backends/filebased.py
vendored
@ -1,7 +1,8 @@
|
||||
"File-based cache backend"
|
||||
|
||||
from django.core.cache.backends.simple import CacheClass as SimpleCacheClass
|
||||
import os, time, urllib
|
||||
from django.utils.http import urlquote_plus
|
||||
import os, time
|
||||
try:
|
||||
import cPickle as pickle
|
||||
except ImportError:
|
||||
@ -77,4 +78,4 @@ class CacheClass(SimpleCacheClass):
|
||||
raise EnvironmentError, "Cache directory '%s' does not exist and could not be created'" % self._dir
|
||||
|
||||
def _key_to_file(self, key):
|
||||
return os.path.join(self._dir, urllib.quote_plus(key))
|
||||
return os.path.join(self._dir, urlquote_plus(key))
|
||||
|
17
django/core/cache/backends/locmem.py
vendored
17
django/core/cache/backends/locmem.py
vendored
@ -1,8 +1,13 @@
|
||||
"Thread-safe in-memory cache backend."
|
||||
|
||||
import time
|
||||
try:
|
||||
import cPickle as pickle
|
||||
except ImportError:
|
||||
import pickle
|
||||
|
||||
from django.core.cache.backends.simple import CacheClass as SimpleCacheClass
|
||||
from django.utils.synch import RWLock
|
||||
import copy, time
|
||||
|
||||
class CacheClass(SimpleCacheClass):
|
||||
def __init__(self, host, params):
|
||||
@ -20,7 +25,10 @@ class CacheClass(SimpleCacheClass):
|
||||
elif exp < now:
|
||||
should_delete = True
|
||||
else:
|
||||
return copy.deepcopy(self._cache[key])
|
||||
try:
|
||||
return pickle.loads(self._cache[key])
|
||||
except pickle.PickleError:
|
||||
return default
|
||||
finally:
|
||||
self._lock.reader_leaves()
|
||||
if should_delete:
|
||||
@ -35,7 +43,10 @@ class CacheClass(SimpleCacheClass):
|
||||
def set(self, key, value, timeout=None):
|
||||
self._lock.writer_enters()
|
||||
try:
|
||||
SimpleCacheClass.set(self, key, value, timeout)
|
||||
try:
|
||||
super(CacheClass, self).set(key, pickle.dumps(value), timeout)
|
||||
except pickle.PickleError:
|
||||
pass
|
||||
finally:
|
||||
self._lock.writer_leaves()
|
||||
|
||||
|
16
django/core/cache/backends/memcached.py
vendored
16
django/core/cache/backends/memcached.py
vendored
@ -1,6 +1,7 @@
|
||||
"Memcached cache backend"
|
||||
|
||||
from django.core.cache.backends.base import BaseCache, InvalidCacheBackendError
|
||||
from django.utils.encoding import smart_unicode, smart_str
|
||||
|
||||
try:
|
||||
import cmemcache as memcache
|
||||
@ -16,17 +17,22 @@ class CacheClass(BaseCache):
|
||||
self._cache = memcache.Client(server.split(';'))
|
||||
|
||||
def get(self, key, default=None):
|
||||
val = self._cache.get(key)
|
||||
val = self._cache.get(smart_str(key))
|
||||
if val is None:
|
||||
return default
|
||||
else:
|
||||
return val
|
||||
if isinstance(val, basestring):
|
||||
return smart_unicode(val)
|
||||
else:
|
||||
return val
|
||||
|
||||
def set(self, key, value, timeout=0):
|
||||
self._cache.set(key, value, timeout or self.default_timeout)
|
||||
if isinstance(value, unicode):
|
||||
value = value.encode('utf-8')
|
||||
self._cache.set(smart_str(key), value, timeout or self.default_timeout)
|
||||
|
||||
def delete(self, key):
|
||||
self._cache.delete(key)
|
||||
self._cache.delete(smart_str(key))
|
||||
|
||||
def get_many(self, keys):
|
||||
return self._cache.get_multi(keys)
|
||||
return self._cache.get_multi(map(smart_str,keys))
|
||||
|
@ -2,6 +2,7 @@ from django.core.handlers.base import BaseHandler
|
||||
from django.core import signals
|
||||
from django.dispatch import dispatcher
|
||||
from django.utils import datastructures
|
||||
from django.utils.encoding import force_unicode
|
||||
from django import http
|
||||
from pprint import pformat
|
||||
import os
|
||||
@ -13,7 +14,7 @@ import os
|
||||
class ModPythonRequest(http.HttpRequest):
|
||||
def __init__(self, req):
|
||||
self._req = req
|
||||
self.path = req.uri
|
||||
self.path = force_unicode(req.uri)
|
||||
|
||||
def __repr__(self):
|
||||
# Since this is called as part of error handling, we need to be very
|
||||
|
@ -2,6 +2,7 @@ from django.core.handlers.base import BaseHandler
|
||||
from django.core import signals
|
||||
from django.dispatch import dispatcher
|
||||
from django.utils import datastructures
|
||||
from django.utils.encoding import force_unicode
|
||||
from django import http
|
||||
from pprint import pformat
|
||||
from shutil import copyfileobj
|
||||
@ -73,7 +74,7 @@ def safe_copyfileobj(fsrc, fdst, length=16*1024, size=0):
|
||||
class WSGIRequest(http.HttpRequest):
|
||||
def __init__(self, environ):
|
||||
self.environ = environ
|
||||
self.path = environ['PATH_INFO']
|
||||
self.path = force_unicode(environ['PATH_INFO'])
|
||||
self.META = environ
|
||||
self.method = environ['REQUEST_METHOD'].upper()
|
||||
|
||||
|
@ -95,19 +95,12 @@ def _get_sequence_list():
|
||||
|
||||
return sequence_list
|
||||
|
||||
# If the foreign key points to an AutoField, a PositiveIntegerField or a
|
||||
# PositiveSmallIntegerField, the foreign key should be an IntegerField, not the
|
||||
# referred field type. Otherwise, the foreign key should be the same type of
|
||||
# field as the field to which it points.
|
||||
get_rel_data_type = lambda f: (f.get_internal_type() in ('AutoField', 'PositiveIntegerField', 'PositiveSmallIntegerField')) and 'IntegerField' or f.get_internal_type()
|
||||
|
||||
def get_sql_create(app):
|
||||
"Returns a list of the CREATE TABLE SQL statements for the given app."
|
||||
from django.db import get_creation_module, models
|
||||
from django.db import models
|
||||
from django.conf import settings
|
||||
|
||||
data_types = get_creation_module().DATA_TYPES
|
||||
|
||||
if not data_types:
|
||||
if settings.DATABASE_ENGINE == 'dummy':
|
||||
# This must be the "dummy" database backend, which means the user
|
||||
# hasn't set DATABASE_ENGINE.
|
||||
sys.stderr.write(style.ERROR("Error: Django doesn't know which syntax to use for your SQL statements,\n" +
|
||||
@ -159,52 +152,46 @@ def _get_sql_model_create(model, known_models=set()):
|
||||
|
||||
Returns list_of_sql, pending_references_dict
|
||||
"""
|
||||
from django.db import backend, get_creation_module, models
|
||||
data_types = get_creation_module().DATA_TYPES
|
||||
from django.db import backend, models
|
||||
|
||||
opts = model._meta
|
||||
final_output = []
|
||||
table_output = []
|
||||
pending_references = {}
|
||||
for f in opts.fields:
|
||||
if isinstance(f, (models.ForeignKey, models.OneToOneField)):
|
||||
rel_field = f.rel.get_related_field()
|
||||
while isinstance(rel_field, (models.ForeignKey, models.OneToOneField)):
|
||||
rel_field = rel_field.rel.get_related_field()
|
||||
data_type = get_rel_data_type(rel_field)
|
||||
else:
|
||||
rel_field = f
|
||||
data_type = f.get_internal_type()
|
||||
col_type = data_types[data_type]
|
||||
col_type = f.db_type()
|
||||
tablespace = f.db_tablespace or opts.db_tablespace
|
||||
if col_type is not None:
|
||||
# Make the definition (e.g. 'foo VARCHAR(30)') for this field.
|
||||
field_output = [style.SQL_FIELD(backend.quote_name(f.column)),
|
||||
style.SQL_COLTYPE(col_type % rel_field.__dict__)]
|
||||
field_output.append(style.SQL_KEYWORD('%sNULL' % (not f.null and 'NOT ' or '')))
|
||||
if f.unique and (not f.primary_key or backend.allows_unique_and_pk):
|
||||
field_output.append(style.SQL_KEYWORD('UNIQUE'))
|
||||
if f.primary_key:
|
||||
field_output.append(style.SQL_KEYWORD('PRIMARY KEY'))
|
||||
if tablespace and backend.supports_tablespaces and (f.unique or f.primary_key) and backend.autoindexes_primary_keys:
|
||||
# We must specify the index tablespace inline, because we
|
||||
# won't be generating a CREATE INDEX statement for this field.
|
||||
field_output.append(backend.get_tablespace_sql(tablespace, inline=True))
|
||||
if f.rel:
|
||||
if f.rel.to in known_models:
|
||||
field_output.append(style.SQL_KEYWORD('REFERENCES') + ' ' + \
|
||||
style.SQL_TABLE(backend.quote_name(f.rel.to._meta.db_table)) + ' (' + \
|
||||
style.SQL_FIELD(backend.quote_name(f.rel.to._meta.get_field(f.rel.field_name).column)) + ')' +
|
||||
backend.get_deferrable_sql()
|
||||
)
|
||||
else:
|
||||
# We haven't yet created the table to which this field
|
||||
# is related, so save it for later.
|
||||
pr = pending_references.setdefault(f.rel.to, []).append((model, f))
|
||||
table_output.append(' '.join(field_output))
|
||||
if col_type is None:
|
||||
# Skip ManyToManyFields, because they're not represented as
|
||||
# database columns in this table.
|
||||
continue
|
||||
# Make the definition (e.g. 'foo VARCHAR(30)') for this field.
|
||||
field_output = [style.SQL_FIELD(backend.quote_name(f.column)),
|
||||
style.SQL_COLTYPE(col_type)]
|
||||
field_output.append(style.SQL_KEYWORD('%sNULL' % (not f.null and 'NOT ' or '')))
|
||||
if f.unique and (not f.primary_key or backend.allows_unique_and_pk):
|
||||
field_output.append(style.SQL_KEYWORD('UNIQUE'))
|
||||
if f.primary_key:
|
||||
field_output.append(style.SQL_KEYWORD('PRIMARY KEY'))
|
||||
if tablespace and backend.supports_tablespaces and (f.unique or f.primary_key) and backend.autoindexes_primary_keys:
|
||||
# We must specify the index tablespace inline, because we
|
||||
# won't be generating a CREATE INDEX statement for this field.
|
||||
field_output.append(backend.get_tablespace_sql(tablespace, inline=True))
|
||||
if f.rel:
|
||||
if f.rel.to in known_models:
|
||||
field_output.append(style.SQL_KEYWORD('REFERENCES') + ' ' + \
|
||||
style.SQL_TABLE(backend.quote_name(f.rel.to._meta.db_table)) + ' (' + \
|
||||
style.SQL_FIELD(backend.quote_name(f.rel.to._meta.get_field(f.rel.field_name).column)) + ')' +
|
||||
backend.get_deferrable_sql()
|
||||
)
|
||||
else:
|
||||
# We haven't yet created the table to which this field
|
||||
# is related, so save it for later.
|
||||
pr = pending_references.setdefault(f.rel.to, []).append((model, f))
|
||||
table_output.append(' '.join(field_output))
|
||||
if opts.order_with_respect_to:
|
||||
table_output.append(style.SQL_FIELD(backend.quote_name('_order')) + ' ' + \
|
||||
style.SQL_COLTYPE(data_types['IntegerField']) + ' ' + \
|
||||
style.SQL_COLTYPE(models.IntegerField().db_type()) + ' ' + \
|
||||
style.SQL_KEYWORD('NULL'))
|
||||
for field_constraints in opts.unique_together:
|
||||
table_output.append(style.SQL_KEYWORD('UNIQUE') + ' (%s)' % \
|
||||
@ -232,9 +219,8 @@ def _get_sql_for_pending_references(model, pending_references):
|
||||
"""
|
||||
Get any ALTER TABLE statements to add constraints after the fact.
|
||||
"""
|
||||
from django.db import backend, get_creation_module
|
||||
from django.db import backend
|
||||
from django.db.backends.util import truncate_name
|
||||
data_types = get_creation_module().DATA_TYPES
|
||||
|
||||
final_output = []
|
||||
if backend.supports_constraints:
|
||||
@ -257,11 +243,9 @@ def _get_sql_for_pending_references(model, pending_references):
|
||||
return final_output
|
||||
|
||||
def _get_many_to_many_sql_for_model(model):
|
||||
from django.db import backend, get_creation_module
|
||||
from django.db import backend, models
|
||||
from django.contrib.contenttypes import generic
|
||||
|
||||
data_types = get_creation_module().DATA_TYPES
|
||||
|
||||
opts = model._meta
|
||||
final_output = []
|
||||
for f in opts.many_to_many:
|
||||
@ -275,19 +259,19 @@ def _get_many_to_many_sql_for_model(model):
|
||||
style.SQL_TABLE(backend.quote_name(f.m2m_db_table())) + ' (']
|
||||
table_output.append(' %s %s %s%s,' % \
|
||||
(style.SQL_FIELD(backend.quote_name('id')),
|
||||
style.SQL_COLTYPE(data_types['AutoField']),
|
||||
style.SQL_COLTYPE(models.AutoField(primary_key=True).db_type()),
|
||||
style.SQL_KEYWORD('NOT NULL PRIMARY KEY'),
|
||||
tablespace_sql))
|
||||
table_output.append(' %s %s %s %s (%s)%s,' % \
|
||||
(style.SQL_FIELD(backend.quote_name(f.m2m_column_name())),
|
||||
style.SQL_COLTYPE(data_types[get_rel_data_type(opts.pk)] % opts.pk.__dict__),
|
||||
style.SQL_COLTYPE(models.ForeignKey(model).db_type()),
|
||||
style.SQL_KEYWORD('NOT NULL REFERENCES'),
|
||||
style.SQL_TABLE(backend.quote_name(opts.db_table)),
|
||||
style.SQL_FIELD(backend.quote_name(opts.pk.column)),
|
||||
backend.get_deferrable_sql()))
|
||||
table_output.append(' %s %s %s %s (%s)%s,' % \
|
||||
(style.SQL_FIELD(backend.quote_name(f.m2m_reverse_name())),
|
||||
style.SQL_COLTYPE(data_types[get_rel_data_type(f.rel.to._meta.pk)] % f.rel.to._meta.pk.__dict__),
|
||||
style.SQL_COLTYPE(models.ForeignKey(f.rel.to).db_type()),
|
||||
style.SQL_KEYWORD('NOT NULL REFERENCES'),
|
||||
style.SQL_TABLE(backend.quote_name(f.rel.to._meta.db_table)),
|
||||
style.SQL_FIELD(backend.quote_name(f.rel.to._meta.pk.column)),
|
||||
@ -517,7 +501,7 @@ def _emit_post_sync_signal(created_models, verbosity, interactive):
|
||||
|
||||
def syncdb(verbosity=1, interactive=True):
|
||||
"Creates the database tables for all apps in INSTALLED_APPS whose tables haven't already been created."
|
||||
from django.db import backend, connection, transaction, models, get_creation_module
|
||||
from django.db import backend, connection, transaction, models
|
||||
from django.conf import settings
|
||||
|
||||
disable_termcolors()
|
||||
@ -533,8 +517,6 @@ def syncdb(verbosity=1, interactive=True):
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
data_types = get_creation_module().DATA_TYPES
|
||||
|
||||
cursor = connection.cursor()
|
||||
|
||||
# Get a list of all existing database tables,
|
||||
@ -928,9 +910,9 @@ def inspectdb():
|
||||
field_type, new_params = field_type
|
||||
extra_params.update(new_params)
|
||||
|
||||
# Add maxlength for all CharFields.
|
||||
# Add max_length for all CharFields.
|
||||
if field_type == 'CharField' and row[3]:
|
||||
extra_params['maxlength'] = row[3]
|
||||
extra_params['max_length'] = row[3]
|
||||
|
||||
if field_type == 'DecimalField':
|
||||
extra_params['max_digits'] = row[4]
|
||||
@ -1005,8 +987,8 @@ def get_validation_errors(outfile, app=None):
|
||||
for f in opts.fields:
|
||||
if f.name == 'id' and not f.primary_key and opts.pk.name == 'id':
|
||||
e.add(opts, '"%s": You can\'t use "id" as a field name, because each model automatically gets an "id" field if none of the fields have primary_key=True. You need to either remove/rename your "id" field or add primary_key=True to a field.' % f.name)
|
||||
if isinstance(f, models.CharField) and f.maxlength in (None, 0):
|
||||
e.add(opts, '"%s": CharFields require a "maxlength" attribute.' % f.name)
|
||||
if isinstance(f, models.CharField) and f.max_length in (None, 0):
|
||||
e.add(opts, '"%s": CharFields require a "max_length" attribute.' % f.name)
|
||||
if isinstance(f, models.DecimalField):
|
||||
if f.decimal_places is None:
|
||||
e.add(opts, '"%s": DecimalFields require a "decimal_places" attribute.' % f.name)
|
||||
@ -1029,11 +1011,11 @@ def get_validation_errors(outfile, app=None):
|
||||
if f.db_index not in (None, True, False):
|
||||
e.add(opts, '"%s": "db_index" should be either None, True or False.' % f.name)
|
||||
|
||||
# Check that maxlength <= 255 if using older MySQL versions.
|
||||
# Check that max_length <= 255 if using older MySQL versions.
|
||||
if settings.DATABASE_ENGINE == 'mysql':
|
||||
db_version = connection.get_server_version()
|
||||
if db_version < (5, 0, 3) and isinstance(f, (models.CharField, models.CommaSeparatedIntegerField, models.SlugField)) and f.maxlength > 255:
|
||||
e.add(opts, '"%s": %s cannot have a "maxlength" greater than 255 when you are using a version of MySQL prior to 5.0.3 (you are using %s).' % (f.name, f.__class__.__name__, '.'.join([str(n) for n in db_version[:3]])))
|
||||
if db_version < (5, 0, 3) and isinstance(f, (models.CharField, models.CommaSeparatedIntegerField, models.SlugField)) and f.max_length > 255:
|
||||
e.add(opts, '"%s": %s cannot have a "max_length" greater than 255 when you are using a version of MySQL prior to 5.0.3 (you are using %s).' % (f.name, f.__class__.__name__, '.'.join([str(n) for n in db_version[:3]])))
|
||||
|
||||
# Check to see if the related field will clash with any
|
||||
# existing fields, m2m fields, m2m related objects or related objects
|
||||
@ -1257,7 +1239,8 @@ def runserver(addr, port, use_reloader=True, admin_media_dir=''):
|
||||
except (AttributeError, KeyError):
|
||||
error_text = str(e)
|
||||
sys.stderr.write(style.ERROR("Error: %s" % error_text) + '\n')
|
||||
sys.exit(1)
|
||||
# Need to use an OS exit because sys.exit doesn't work in a thread
|
||||
os._exit(1)
|
||||
except KeyboardInterrupt:
|
||||
sys.exit(0)
|
||||
if use_reloader:
|
||||
@ -1269,18 +1252,17 @@ runserver.args = '[--noreload] [--adminmedia=ADMIN_MEDIA_PATH] [optional port nu
|
||||
|
||||
def createcachetable(tablename):
|
||||
"Creates the table needed to use the SQL cache backend"
|
||||
from django.db import backend, connection, transaction, get_creation_module, models
|
||||
data_types = get_creation_module().DATA_TYPES
|
||||
from django.db import backend, connection, transaction, models
|
||||
fields = (
|
||||
# "key" is a reserved word in MySQL, so use "cache_key" instead.
|
||||
models.CharField(name='cache_key', maxlength=255, unique=True, primary_key=True),
|
||||
models.CharField(name='cache_key', max_length=255, unique=True, primary_key=True),
|
||||
models.TextField(name='value'),
|
||||
models.DateTimeField(name='expires', db_index=True),
|
||||
)
|
||||
table_output = []
|
||||
index_output = []
|
||||
for f in fields:
|
||||
field_output = [backend.quote_name(f.name), data_types[f.get_internal_type()] % f.__dict__]
|
||||
field_output = [backend.quote_name(f.name), f.db_type()]
|
||||
field_output.append("%sNULL" % (not f.null and "NOT " or ""))
|
||||
if f.unique:
|
||||
field_output.append("UNIQUE")
|
||||
@ -1321,6 +1303,10 @@ def run_shell(use_plain=False):
|
||||
shell.mainloop()
|
||||
except ImportError:
|
||||
import code
|
||||
# Set up a dictionary to serve as the environment for the shell, so
|
||||
# that tab completion works on objects that are imported at runtime.
|
||||
# See ticket 5082.
|
||||
imported_objects = {}
|
||||
try: # Try activating rlcompleter, because it's handy.
|
||||
import readline
|
||||
except ImportError:
|
||||
@ -1329,8 +1315,9 @@ def run_shell(use_plain=False):
|
||||
# We don't have to wrap the following import in a 'try', because
|
||||
# we already know 'readline' was imported successfully.
|
||||
import rlcompleter
|
||||
readline.set_completer(rlcompleter.Completer(imported_objects).complete)
|
||||
readline.parse_and_bind("tab:complete")
|
||||
code.interact()
|
||||
code.interact(local=imported_objects)
|
||||
run_shell.args = '[--plain]'
|
||||
|
||||
def dbshell():
|
||||
@ -1352,16 +1339,11 @@ def runfcgi(args):
|
||||
runfastcgi(args)
|
||||
runfcgi.args = '[various KEY=val options, use `runfcgi help` for help]'
|
||||
|
||||
def test(app_labels, verbosity=1):
|
||||
def test(test_labels, verbosity=1, interactive=True):
|
||||
"Runs the test suite for the specified applications"
|
||||
from django.conf import settings
|
||||
from django.db.models import get_app, get_apps
|
||||
|
||||
if len(app_labels) == 0:
|
||||
app_list = get_apps()
|
||||
else:
|
||||
app_list = [get_app(app_label) for app_label in app_labels]
|
||||
|
||||
|
||||
test_path = settings.TEST_RUNNER.split('.')
|
||||
# Allow for Python 2.5 relative paths
|
||||
if len(test_path) > 1:
|
||||
@ -1371,12 +1353,12 @@ def test(app_labels, verbosity=1):
|
||||
test_module = __import__(test_module_name, {}, {}, test_path[-1])
|
||||
test_runner = getattr(test_module, test_path[-1])
|
||||
|
||||
failures = test_runner(app_list, verbosity)
|
||||
failures = test_runner(test_labels, verbosity=verbosity, interactive=interactive)
|
||||
if failures:
|
||||
sys.exit(failures)
|
||||
|
||||
test.help_doc = 'Runs the test suite for the specified applications, or the entire site if no apps are specified'
|
||||
test.args = '[--verbosity] ' + APP_ARGS
|
||||
test.args = '[--verbosity] [--noinput]' + APP_ARGS
|
||||
|
||||
def load_data(fixture_labels, verbosity=1):
|
||||
"Installs the provided fixture file(s) as data in the database."
|
||||
@ -1450,7 +1432,7 @@ def load_data(fixture_labels, verbosity=1):
|
||||
print "Installing %s fixture '%s' from %s." % \
|
||||
(format, fixture_name, humanize(fixture_dir))
|
||||
try:
|
||||
objects = serializers.deserialize(format, fixture)
|
||||
objects = serializers.deserialize(format, fixture)
|
||||
for obj in objects:
|
||||
count[0] += 1
|
||||
models.add(obj.object.__class__)
|
||||
@ -1652,7 +1634,12 @@ def execute_from_command_line(action_mapping=DEFAULT_ACTION_MAPPING, argv=None):
|
||||
action_mapping[action](args[1])
|
||||
except IndexError:
|
||||
parser.print_usage_and_exit()
|
||||
elif action in ('test', 'loaddata'):
|
||||
elif action == 'test':
|
||||
try:
|
||||
action_mapping[action](args[1:], int(options.verbosity), options.interactive)
|
||||
except IndexError:
|
||||
parser.print_usage_and_exit()
|
||||
elif action == 'loaddata':
|
||||
try:
|
||||
action_mapping[action](args[1:], int(options.verbosity))
|
||||
except IndexError:
|
||||
@ -1716,14 +1703,15 @@ def setup_environ(settings_mod):
|
||||
# Add this project to sys.path so that it's importable in the conventional
|
||||
# way. For example, if this file (manage.py) lives in a directory
|
||||
# "myproject", this code would add "/path/to/myproject" to sys.path.
|
||||
project_directory = os.path.dirname(settings_mod.__file__)
|
||||
project_directory, settings_filename = os.path.split(settings_mod.__file__)
|
||||
project_name = os.path.basename(project_directory)
|
||||
settings_name = os.path.splitext(settings_filename)[0]
|
||||
sys.path.append(os.path.join(project_directory, '..'))
|
||||
project_module = __import__(project_name, {}, {}, [''])
|
||||
sys.path.pop()
|
||||
|
||||
# Set DJANGO_SETTINGS_MODULE appropriately.
|
||||
os.environ['DJANGO_SETTINGS_MODULE'] = '%s.settings' % project_name
|
||||
os.environ['DJANGO_SETTINGS_MODULE'] = '%s.%s' % (project_name, settings_name)
|
||||
return project_directory
|
||||
|
||||
def execute_manager(settings_mod, argv=None):
|
||||
|
@ -158,7 +158,12 @@ class DeserializedObject(object):
|
||||
return "<DeserializedObject: %s>" % smart_str(self.object)
|
||||
|
||||
def save(self, save_m2m=True):
|
||||
self.object.save()
|
||||
# Call save on the Model baseclass directly. This bypasses any
|
||||
# model-defined save. The save is also forced to be raw.
|
||||
# This ensures that the data that is deserialized is literally
|
||||
# what came from the file, not post-processed by pre_save/save
|
||||
# methods.
|
||||
models.Model.save(self.object, raw=True)
|
||||
if self.m2m_data and save_m2m:
|
||||
for accessor_name, object_list in self.m2m_data.items():
|
||||
setattr(self.object, accessor_name, object_list)
|
||||
|
@ -171,7 +171,7 @@ class Deserializer(base.Deserializer):
|
||||
elif field.rel and isinstance(field.rel, models.ManyToOneRel):
|
||||
data[field.attname] = self._handle_fk_field_node(field_node, field)
|
||||
else:
|
||||
if len(field_node.childNodes) == 1 and field_node.childNodes[0].nodeName == 'None':
|
||||
if field_node.getElementsByTagName('None'):
|
||||
value = None
|
||||
else:
|
||||
value = field.to_python(getInnerText(field_node).strip())
|
||||
@ -185,7 +185,7 @@ class Deserializer(base.Deserializer):
|
||||
Handle a <field> node for a ForeignKey
|
||||
"""
|
||||
# Check if there is a child node named 'None', returning None if so.
|
||||
if len(node.childNodes) == 1 and node.childNodes[0].nodeName == 'None':
|
||||
if node.getElementsByTagName('None'):
|
||||
return None
|
||||
else:
|
||||
return field.rel.to._meta.get_field(field.rel.field_name).to_python(
|
||||
|
@ -9,7 +9,13 @@ been reviewed for security issues. Don't use it for production use.
|
||||
|
||||
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
|
||||
from types import ListType, StringType
|
||||
import os, re, sys, time, urllib, mimetypes
|
||||
from email.Utils import formatdate
|
||||
import mimetypes
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import time
|
||||
import urllib
|
||||
|
||||
__version__ = "0.1"
|
||||
__all__ = ['WSGIServer','WSGIRequestHandler','demo_app']
|
||||
@ -370,7 +376,7 @@ class ServerHandler(object):
|
||||
self._write('HTTP/%s %s\r\n' % (self.http_version,self.status))
|
||||
if 'Date' not in self.headers:
|
||||
self._write(
|
||||
'Date: %s\r\n' % time.asctime(time.gmtime(time.time()))
|
||||
'Date: %s\r\n' % (formatdate()[:26] + "GMT")
|
||||
)
|
||||
if self.server_software and 'Server' not in self.headers:
|
||||
self._write('Server: %s\r\n' % self.server_software)
|
||||
|
@ -9,7 +9,7 @@ a string) and returns a tuple in this format:
|
||||
|
||||
from django.http import Http404
|
||||
from django.core.exceptions import ImproperlyConfigured, ViewDoesNotExist
|
||||
from django.utils.encoding import iri_to_uri
|
||||
from django.utils.encoding import iri_to_uri, force_unicode, smart_str
|
||||
from django.utils.functional import memoize
|
||||
import re
|
||||
|
||||
@ -38,29 +38,27 @@ def get_callable(lookup_view, can_fail=False):
|
||||
If can_fail is True, lookup_view might be a URL pattern label, so errors
|
||||
during the import fail and the string is returned.
|
||||
"""
|
||||
try:
|
||||
# Bail out early if lookup_view is not ASCII. This can't be a function.
|
||||
lookup_view = lookup_view.encode('ascii')
|
||||
|
||||
if not callable(lookup_view):
|
||||
if not callable(lookup_view):
|
||||
try:
|
||||
# Bail early for non-ASCII strings (they can't be functions).
|
||||
lookup_view = lookup_view.encode('ascii')
|
||||
mod_name, func_name = get_mod_func(lookup_view)
|
||||
try:
|
||||
if func_name != '':
|
||||
lookup_view = getattr(__import__(mod_name, {}, {}, ['']), func_name)
|
||||
except (ImportError, AttributeError):
|
||||
if not can_fail:
|
||||
raise
|
||||
except UnicodeEncodeError:
|
||||
pass
|
||||
if func_name != '':
|
||||
lookup_view = getattr(__import__(mod_name, {}, {}, ['']), func_name)
|
||||
except (ImportError, AttributeError):
|
||||
if not can_fail:
|
||||
raise
|
||||
except UnicodeEncodeError:
|
||||
pass
|
||||
return lookup_view
|
||||
get_callable = memoize(get_callable, _callable_cache)
|
||||
get_callable = memoize(get_callable, _callable_cache, 1)
|
||||
|
||||
def get_resolver(urlconf):
|
||||
if urlconf is None:
|
||||
from django.conf import settings
|
||||
urlconf = settings.ROOT_URLCONF
|
||||
return RegexURLResolver(r'^/', urlconf)
|
||||
get_resolver = memoize(get_resolver, _resolver_cache)
|
||||
get_resolver = memoize(get_resolver, _resolver_cache, 1)
|
||||
|
||||
def get_mod_func(callback):
|
||||
# Converts 'django.views.news.stories.story_detail' to
|
||||
@ -101,7 +99,7 @@ class MatchChecker(object):
|
||||
# First we need to figure out whether it's a named or unnamed group.
|
||||
#
|
||||
grouped = match_obj.group(1)
|
||||
m = re.search(r'^\?P<(\w+)>(.*?)$', grouped)
|
||||
m = re.search(r'^\?P<(\w+)>(.*?)$', grouped, re.UNICODE)
|
||||
if m: # If this was a named group...
|
||||
# m.group(1) is the name of the group
|
||||
# m.group(2) is the regex.
|
||||
@ -127,9 +125,9 @@ class MatchChecker(object):
|
||||
test_regex = grouped
|
||||
# Note we're using re.match here on purpose because the start of
|
||||
# to string needs to match.
|
||||
if not re.match(test_regex + '$', str(value)): # TODO: Unicode?
|
||||
if not re.match(test_regex + '$', force_unicode(value), re.UNICODE):
|
||||
raise NoReverseMatch("Value %r didn't match regular expression %r" % (value, test_regex))
|
||||
return str(value) # TODO: Unicode?
|
||||
return force_unicode(value)
|
||||
|
||||
class RegexURLPattern(object):
|
||||
def __init__(self, regex, callback, default_args=None, name=None):
|
||||
@ -137,7 +135,7 @@ class RegexURLPattern(object):
|
||||
# callback is either a string like 'foo.views.news.stories.story_detail'
|
||||
# which represents the path to a module and a view function name, or a
|
||||
# callable object (view).
|
||||
self.regex = re.compile(regex)
|
||||
self.regex = re.compile(regex, re.UNICODE)
|
||||
if callable(callback):
|
||||
self._callback = callback
|
||||
else:
|
||||
@ -146,6 +144,9 @@ class RegexURLPattern(object):
|
||||
self.default_args = default_args or {}
|
||||
self.name = name
|
||||
|
||||
def __repr__(self):
|
||||
return '<%s %s %s>' % (self.__class__.__name__, self.name, self.regex.pattern)
|
||||
|
||||
def add_prefix(self, prefix):
|
||||
"""
|
||||
Adds the prefix string to a string-based callback.
|
||||
@ -201,12 +202,15 @@ class RegexURLResolver(object):
|
||||
def __init__(self, regex, urlconf_name, default_kwargs=None):
|
||||
# regex is a string representing a regular expression.
|
||||
# urlconf_name is a string representing the module containing urlconfs.
|
||||
self.regex = re.compile(regex)
|
||||
self.regex = re.compile(regex, re.UNICODE)
|
||||
self.urlconf_name = urlconf_name
|
||||
self.callback = None
|
||||
self.default_kwargs = default_kwargs or {}
|
||||
self._reverse_dict = {}
|
||||
|
||||
def __repr__(self):
|
||||
return '<%s %s %s>' % (self.__class__.__name__, self.urlconf_name, self.regex.pattern)
|
||||
|
||||
def _get_reverse_dict(self):
|
||||
if not self._reverse_dict and hasattr(self.urlconf_module, 'urlpatterns'):
|
||||
for pattern in reversed(self.urlconf_module.urlpatterns):
|
||||
@ -231,8 +235,11 @@ class RegexURLResolver(object):
|
||||
tried.extend([(pattern.regex.pattern + ' ' + t) for t in e.args[0]['tried']])
|
||||
else:
|
||||
if sub_match:
|
||||
sub_match_dict = dict(self.default_kwargs, **sub_match[2])
|
||||
return sub_match[0], sub_match[1], dict(match.groupdict(), **sub_match_dict)
|
||||
sub_match_dict = dict([(smart_str(k), v) for k, v in match.groupdict().items()])
|
||||
sub_match_dict.update(self.default_kwargs)
|
||||
for k, v in sub_match[2].iteritems():
|
||||
sub_match_dict[smart_str(k)] = v
|
||||
return sub_match[0], sub_match[1], sub_match_dict
|
||||
tried.append(pattern.regex.pattern)
|
||||
raise Resolver404, {'tried': tried, 'path': new_path}
|
||||
|
||||
|
@ -14,6 +14,10 @@ from django.utils.translation import ugettext as _, ugettext_lazy, ungettext
|
||||
from django.utils.functional import Promise, lazy
|
||||
from django.utils.encoding import force_unicode
|
||||
import re
|
||||
try:
|
||||
from decimal import Decimal, DecimalException
|
||||
except ImportError:
|
||||
from django.utils._decimal import Decimal, DecimalException # Python 2.3
|
||||
|
||||
_datere = r'\d{4}-\d{1,2}-\d{1,2}'
|
||||
_timere = r'(?:[01]?[0-9]|2[0-3]):[0-5][0-9](?::[0-5][0-9])?'
|
||||
@ -24,9 +28,8 @@ ansi_time_re = re.compile('^%s$' % _timere)
|
||||
ansi_datetime_re = re.compile('^%s %s$' % (_datere, _timere))
|
||||
email_re = re.compile(
|
||||
r"(^[-!#$%&'*+/=?^_`{}|~0-9A-Z]+(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*" # dot-atom
|
||||
r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-011\013\014\016-\177])*"' # quoted-string
|
||||
r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-\011\013\014\016-\177])*"' # quoted-string
|
||||
r')@(?:[A-Z0-9-]+\.)+[A-Z]{2,6}$', re.IGNORECASE) # domain
|
||||
decimal_re = re.compile(r'^-?(?P<digits>\d+)(\.(?P<decimals>\d+))?$')
|
||||
integer_re = re.compile(r'^-?\d+$')
|
||||
ip4_re = re.compile(r'^(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$')
|
||||
phone_re = re.compile(r'^[A-PR-Y0-9]{3}-[A-PR-Y0-9]{3}-[A-PR-Y0-9]{4}$', re.IGNORECASE)
|
||||
@ -415,13 +418,15 @@ class IsValidDecimal(object):
|
||||
self.max_digits, self.decimal_places = max_digits, decimal_places
|
||||
|
||||
def __call__(self, field_data, all_data):
|
||||
match = decimal_re.search(str(field_data))
|
||||
if not match:
|
||||
try:
|
||||
val = Decimal(field_data)
|
||||
except DecimalException:
|
||||
raise ValidationError, _("Please enter a valid decimal number.")
|
||||
|
||||
digits = len(match.group('digits') or '')
|
||||
decimals = len(match.group('decimals') or '')
|
||||
|
||||
|
||||
pieces = str(val).split('.')
|
||||
decimals = (len(pieces) == 2) and len(pieces[1]) or 0
|
||||
digits = len(pieces[0])
|
||||
|
||||
if digits + decimals > self.max_digits:
|
||||
raise ValidationError, ungettext("Please enter a valid decimal number with at most %s total digit.",
|
||||
"Please enter a valid decimal number with at most %s total digits.", self.max_digits) % self.max_digits
|
||||
@ -437,7 +442,7 @@ def isValidFloat(field_data, all_data):
|
||||
try:
|
||||
float(data)
|
||||
except ValueError:
|
||||
raise ValidationError, ugettext("Please enter a valid floating point number.")
|
||||
raise ValidationError, _("Please enter a valid floating point number.")
|
||||
|
||||
class HasAllowableSize(object):
|
||||
"""
|
||||
|
@ -1,8 +1,8 @@
|
||||
DATA_TYPES = {
|
||||
'AutoField': 'int IDENTITY (1, 1)',
|
||||
'BooleanField': 'bit',
|
||||
'CharField': 'varchar(%(maxlength)s)',
|
||||
'CommaSeparatedIntegerField': 'varchar(%(maxlength)s)',
|
||||
'CharField': 'varchar(%(max_length)s)',
|
||||
'CommaSeparatedIntegerField': 'varchar(%(max_length)s)',
|
||||
'DateField': 'smalldatetime',
|
||||
'DateTimeField': 'smalldatetime',
|
||||
'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)',
|
||||
@ -12,13 +12,12 @@ DATA_TYPES = {
|
||||
'ImageField': 'varchar(100)',
|
||||
'IntegerField': 'int',
|
||||
'IPAddressField': 'char(15)',
|
||||
'ManyToManyField': None,
|
||||
'NullBooleanField': 'bit',
|
||||
'OneToOneField': 'int',
|
||||
'PhoneNumberField': 'varchar(20)',
|
||||
'PositiveIntegerField': 'int CONSTRAINT [CK_int_pos_%(column)s] CHECK ([%(column)s] > 0)',
|
||||
'PositiveSmallIntegerField': 'smallint CONSTRAINT [CK_smallint_pos_%(column)s] CHECK ([%(column)s] > 0)',
|
||||
'SlugField': 'varchar(%(maxlength)s)',
|
||||
'SlugField': 'varchar(%(max_length)s)',
|
||||
'SmallIntegerField': 'smallint',
|
||||
'TextField': 'text',
|
||||
'TimeField': 'time',
|
||||
|
@ -5,8 +5,8 @@
|
||||
DATA_TYPES = {
|
||||
'AutoField': 'integer AUTO_INCREMENT',
|
||||
'BooleanField': 'bool',
|
||||
'CharField': 'varchar(%(maxlength)s)',
|
||||
'CommaSeparatedIntegerField': 'varchar(%(maxlength)s)',
|
||||
'CharField': 'varchar(%(max_length)s)',
|
||||
'CommaSeparatedIntegerField': 'varchar(%(max_length)s)',
|
||||
'DateField': 'date',
|
||||
'DateTimeField': 'datetime',
|
||||
'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)',
|
||||
@ -16,13 +16,12 @@ DATA_TYPES = {
|
||||
'ImageField': 'varchar(100)',
|
||||
'IntegerField': 'integer',
|
||||
'IPAddressField': 'char(15)',
|
||||
'ManyToManyField': None,
|
||||
'NullBooleanField': 'bool',
|
||||
'OneToOneField': 'integer',
|
||||
'PhoneNumberField': 'varchar(20)',
|
||||
'PositiveIntegerField': 'integer UNSIGNED',
|
||||
'PositiveSmallIntegerField': 'smallint UNSIGNED',
|
||||
'SlugField': 'varchar(%(maxlength)s)',
|
||||
'SlugField': 'varchar(%(max_length)s)',
|
||||
'SmallIntegerField': 'smallint',
|
||||
'TextField': 'longtext',
|
||||
'TimeField': 'time',
|
||||
|
@ -5,8 +5,8 @@
|
||||
DATA_TYPES = {
|
||||
'AutoField': 'integer AUTO_INCREMENT',
|
||||
'BooleanField': 'bool',
|
||||
'CharField': 'varchar(%(maxlength)s)',
|
||||
'CommaSeparatedIntegerField': 'varchar(%(maxlength)s)',
|
||||
'CharField': 'varchar(%(max_length)s)',
|
||||
'CommaSeparatedIntegerField': 'varchar(%(max_length)s)',
|
||||
'DateField': 'date',
|
||||
'DateTimeField': 'datetime',
|
||||
'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)',
|
||||
@ -16,13 +16,12 @@ DATA_TYPES = {
|
||||
'ImageField': 'varchar(100)',
|
||||
'IntegerField': 'integer',
|
||||
'IPAddressField': 'char(15)',
|
||||
'ManyToManyField': None,
|
||||
'NullBooleanField': 'bool',
|
||||
'OneToOneField': 'integer',
|
||||
'PhoneNumberField': 'varchar(20)',
|
||||
'PositiveIntegerField': 'integer UNSIGNED',
|
||||
'PositiveSmallIntegerField': 'smallint UNSIGNED',
|
||||
'SlugField': 'varchar(%(maxlength)s)',
|
||||
'SlugField': 'varchar(%(max_length)s)',
|
||||
'SmallIntegerField': 'smallint',
|
||||
'TextField': 'longtext',
|
||||
'TimeField': 'time',
|
||||
|
@ -8,8 +8,8 @@ from django.core import management
|
||||
DATA_TYPES = {
|
||||
'AutoField': 'NUMBER(11)',
|
||||
'BooleanField': 'NUMBER(1) CHECK (%(column)s IN (0,1))',
|
||||
'CharField': 'NVARCHAR2(%(maxlength)s)',
|
||||
'CommaSeparatedIntegerField': 'VARCHAR2(%(maxlength)s)',
|
||||
'CharField': 'NVARCHAR2(%(max_length)s)',
|
||||
'CommaSeparatedIntegerField': 'VARCHAR2(%(max_length)s)',
|
||||
'DateField': 'DATE',
|
||||
'DateTimeField': 'TIMESTAMP',
|
||||
'DecimalField': 'NUMBER(%(max_digits)s, %(decimal_places)s)',
|
||||
@ -19,7 +19,6 @@ DATA_TYPES = {
|
||||
'ImageField': 'NVARCHAR2(100)',
|
||||
'IntegerField': 'NUMBER(11)',
|
||||
'IPAddressField': 'VARCHAR2(15)',
|
||||
'ManyToManyField': None,
|
||||
'NullBooleanField': 'NUMBER(1) CHECK ((%(column)s IN (0,1)) OR (%(column)s IS NULL))',
|
||||
'OneToOneField': 'NUMBER(11)',
|
||||
'PhoneNumberField': 'VARCHAR2(20)',
|
||||
|
@ -5,8 +5,8 @@
|
||||
DATA_TYPES = {
|
||||
'AutoField': 'serial',
|
||||
'BooleanField': 'boolean',
|
||||
'CharField': 'varchar(%(maxlength)s)',
|
||||
'CommaSeparatedIntegerField': 'varchar(%(maxlength)s)',
|
||||
'CharField': 'varchar(%(max_length)s)',
|
||||
'CommaSeparatedIntegerField': 'varchar(%(max_length)s)',
|
||||
'DateField': 'date',
|
||||
'DateTimeField': 'timestamp with time zone',
|
||||
'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)',
|
||||
@ -16,13 +16,12 @@ DATA_TYPES = {
|
||||
'ImageField': 'varchar(100)',
|
||||
'IntegerField': 'integer',
|
||||
'IPAddressField': 'inet',
|
||||
'ManyToManyField': None,
|
||||
'NullBooleanField': 'boolean',
|
||||
'OneToOneField': 'integer',
|
||||
'PhoneNumberField': 'varchar(20)',
|
||||
'PositiveIntegerField': 'integer CHECK ("%(column)s" >= 0)',
|
||||
'PositiveSmallIntegerField': 'smallint CHECK ("%(column)s" >= 0)',
|
||||
'SlugField': 'varchar(%(maxlength)s)',
|
||||
'SlugField': 'varchar(%(max_length)s)',
|
||||
'SmallIntegerField': 'smallint',
|
||||
'TextField': 'text',
|
||||
'TimeField': 'time',
|
||||
|
@ -30,11 +30,8 @@ def get_relations(cursor, table_name):
|
||||
AND con.contype = 'f'""", [table_name])
|
||||
relations = {}
|
||||
for row in cursor.fetchall():
|
||||
try:
|
||||
# row[0] and row[1] are like "{2}", so strip the curly braces.
|
||||
relations[int(row[0][1:-1]) - 1] = (int(row[1][1:-1]) - 1, row[2])
|
||||
except ValueError:
|
||||
continue
|
||||
# row[0] and row[1] are single-item lists, so grab the single item.
|
||||
relations[row[0][0] - 1] = (row[1][0] - 1, row[2])
|
||||
return relations
|
||||
|
||||
def get_indexes(cursor, table_name):
|
||||
|
@ -4,8 +4,8 @@
|
||||
DATA_TYPES = {
|
||||
'AutoField': 'integer',
|
||||
'BooleanField': 'bool',
|
||||
'CharField': 'varchar(%(maxlength)s)',
|
||||
'CommaSeparatedIntegerField': 'varchar(%(maxlength)s)',
|
||||
'CharField': 'varchar(%(max_length)s)',
|
||||
'CommaSeparatedIntegerField': 'varchar(%(max_length)s)',
|
||||
'DateField': 'date',
|
||||
'DateTimeField': 'datetime',
|
||||
'DecimalField': 'decimal',
|
||||
@ -15,13 +15,12 @@ DATA_TYPES = {
|
||||
'ImageField': 'varchar(100)',
|
||||
'IntegerField': 'integer',
|
||||
'IPAddressField': 'char(15)',
|
||||
'ManyToManyField': None,
|
||||
'NullBooleanField': 'bool',
|
||||
'OneToOneField': 'integer',
|
||||
'PhoneNumberField': 'varchar(20)',
|
||||
'PositiveIntegerField': 'integer unsigned',
|
||||
'PositiveSmallIntegerField': 'smallint unsigned',
|
||||
'SlugField': 'varchar(%(maxlength)s)',
|
||||
'SlugField': 'varchar(%(max_length)s)',
|
||||
'SmallIntegerField': 'smallint',
|
||||
'TextField': 'text',
|
||||
'TimeField': 'time',
|
||||
|
@ -81,7 +81,7 @@ class FlexibleFieldLookupDict:
|
||||
import re
|
||||
m = re.search(r'^\s*(?:var)?char\s*\(\s*(\d+)\s*\)\s*$', key)
|
||||
if m:
|
||||
return ('CharField', {'maxlength': int(m.group(1))})
|
||||
return ('CharField', {'max_length': int(m.group(1))})
|
||||
raise KeyError
|
||||
|
||||
DATA_TYPES_REVERSE = FlexibleFieldLookupDict()
|
||||
|
@ -15,14 +15,18 @@ from django.utils.text import capfirst
|
||||
# Admin stages.
|
||||
ADD, CHANGE, BOTH = 1, 2, 3
|
||||
|
||||
# Decorator. Takes a function that returns a tuple in this format:
|
||||
# (viewname, viewargs, viewkwargs)
|
||||
# Returns a function that calls urlresolvers.reverse() on that data, to return
|
||||
# the URL for those parameters.
|
||||
def permalink(func):
|
||||
"""
|
||||
Decorator that calls urlresolvers.reverse() to return a URL using
|
||||
parameters returned by the decorated function "func".
|
||||
|
||||
"func" should be a function that returns a tuple in one of the
|
||||
following formats:
|
||||
(viewname, viewargs)
|
||||
(viewname, viewargs, viewkwargs)
|
||||
"""
|
||||
from django.core.urlresolvers import reverse
|
||||
def inner(*args, **kwargs):
|
||||
bits = func(*args, **kwargs)
|
||||
viewname = bits[0]
|
||||
return reverse(bits[0], None, *bits[1:3])
|
||||
return inner
|
||||
|
@ -206,7 +206,7 @@ class Model(object):
|
||||
|
||||
_prepare = classmethod(_prepare)
|
||||
|
||||
def save(self):
|
||||
def save(self, raw=False):
|
||||
dispatcher.send(signal=signals.pre_save, sender=self.__class__, instance=self)
|
||||
|
||||
non_pks = [f for f in self._meta.fields if not f.primary_key]
|
||||
@ -223,7 +223,7 @@ class Model(object):
|
||||
self._meta.pk.get_db_prep_lookup('exact', pk_val))
|
||||
# If it does already exist, do an UPDATE.
|
||||
if cursor.fetchone()[0] > 0:
|
||||
db_values = [f.get_db_prep_save(f.pre_save(self, False)) for f in non_pks]
|
||||
db_values = [f.get_db_prep_save(raw and getattr(self, f.attname) or f.pre_save(self, False)) for f in non_pks]
|
||||
if db_values:
|
||||
cursor.execute("UPDATE %s SET %s WHERE %s=%%s" % \
|
||||
(backend.quote_name(self._meta.db_table),
|
||||
@ -234,11 +234,11 @@ class Model(object):
|
||||
record_exists = False
|
||||
if not pk_set or not record_exists:
|
||||
field_names = [backend.quote_name(f.column) for f in self._meta.fields if not isinstance(f, AutoField)]
|
||||
db_values = [f.get_db_prep_save(f.pre_save(self, True)) for f in self._meta.fields if not isinstance(f, AutoField)]
|
||||
db_values = [f.get_db_prep_save(raw and getattr(self, f.attname) or f.pre_save(self, True)) for f in self._meta.fields if not isinstance(f, AutoField)]
|
||||
# If the PK has been manually set, respect that.
|
||||
if pk_set:
|
||||
field_names += [f.column for f in self._meta.fields if isinstance(f, AutoField)]
|
||||
db_values += [f.get_db_prep_save(f.pre_save(self, True)) for f in self._meta.fields if isinstance(f, AutoField)]
|
||||
db_values += [f.get_db_prep_save(raw and getattr(self, f.attname) or f.pre_save(self, True)) for f in self._meta.fields if isinstance(f, AutoField)]
|
||||
placeholders = ['%s'] * len(field_names)
|
||||
if self._meta.order_with_respect_to:
|
||||
field_names.append(backend.quote_name('_order'))
|
||||
|
@ -1,3 +1,4 @@
|
||||
from django.db import get_creation_module
|
||||
from django.db.models import signals
|
||||
from django.dispatch import dispatcher
|
||||
from django.conf import settings
|
||||
@ -10,6 +11,7 @@ from django.utils.itercompat import tee
|
||||
from django.utils.text import capfirst
|
||||
from django.utils.translation import ugettext_lazy, ugettext as _
|
||||
from django.utils.encoding import smart_unicode, force_unicode, smart_str
|
||||
from django.utils.maxlength import LegacyMaxlength
|
||||
import datetime, os, time
|
||||
try:
|
||||
import decimal
|
||||
@ -61,6 +63,9 @@ def manipulator_validator_unique(f, opts, self, field_data, all_data):
|
||||
# getattr(obj, opts.pk.attname)
|
||||
|
||||
class Field(object):
|
||||
# Provide backwards compatibility for the maxlength attribute and
|
||||
# argument for this class and all subclasses.
|
||||
__metaclass__ = LegacyMaxlength
|
||||
|
||||
# Designates whether empty strings fundamentally are allowed at the
|
||||
# database level.
|
||||
@ -70,7 +75,7 @@ class Field(object):
|
||||
creation_counter = 0
|
||||
|
||||
def __init__(self, verbose_name=None, name=None, primary_key=False,
|
||||
maxlength=None, unique=False, blank=False, null=False, db_index=False,
|
||||
max_length=None, unique=False, blank=False, null=False, db_index=False,
|
||||
core=False, rel=None, default=NOT_PROVIDED, editable=True, serialize=True,
|
||||
unique_for_date=None, unique_for_month=None, unique_for_year=None,
|
||||
validator_list=None, choices=None, radio_admin=None, help_text='', db_column=None,
|
||||
@ -78,7 +83,7 @@ class Field(object):
|
||||
self.name = name
|
||||
self.verbose_name = verbose_name
|
||||
self.primary_key = primary_key
|
||||
self.maxlength, self.unique = maxlength, unique
|
||||
self.max_length, self.unique = max_length, unique
|
||||
self.blank, self.null = blank, null
|
||||
# Oracle treats the empty string ('') as null, so coerce the null
|
||||
# option whenever '' is a possible value.
|
||||
@ -115,6 +120,30 @@ class Field(object):
|
||||
"""
|
||||
return value
|
||||
|
||||
def db_type(self):
|
||||
"""
|
||||
Returns the database column data type for this field, taking into
|
||||
account the DATABASE_ENGINE setting.
|
||||
"""
|
||||
# The default implementation of this method looks at the
|
||||
# backend-specific DATA_TYPES dictionary, looking up the field by its
|
||||
# "internal type".
|
||||
#
|
||||
# A Field class can implement the get_internal_type() method to specify
|
||||
# which *preexisting* Django Field class it's most similar to -- i.e.,
|
||||
# an XMLField is represented by a TEXT column type, which is the same
|
||||
# as the TextField Django field type, which means XMLField's
|
||||
# get_internal_type() returns 'TextField'.
|
||||
#
|
||||
# But the limitation of the get_internal_type() / DATA_TYPES approach
|
||||
# is that it cannot handle database column types that aren't already
|
||||
# mapped to one of the built-in Django field types. In this case, you
|
||||
# can implement db_type() instead of get_internal_type() to specify
|
||||
# exactly which wacky database column type you want to use.
|
||||
data_types = get_creation_module().DATA_TYPES
|
||||
internal_type = self.get_internal_type()
|
||||
return data_types[internal_type] % self.__dict__
|
||||
|
||||
def validate_full(self, field_data, all_data):
|
||||
"""
|
||||
Returns a list of errors for this field. This is the main interface,
|
||||
@ -217,8 +246,8 @@ class Field(object):
|
||||
|
||||
def prepare_field_objs_and_params(self, manipulator, name_prefix):
|
||||
params = {'validator_list': self.validator_list[:]}
|
||||
if self.maxlength and not self.choices: # Don't give SelectFields a maxlength parameter.
|
||||
params['maxlength'] = self.maxlength
|
||||
if self.max_length and not self.choices: # Don't give SelectFields a max_length parameter.
|
||||
params['max_length'] = self.max_length
|
||||
|
||||
if self.choices:
|
||||
if self.radio_admin:
|
||||
@ -349,6 +378,9 @@ class Field(object):
|
||||
return self._choices
|
||||
choices = property(_get_choices)
|
||||
|
||||
def save_form_data(self, instance, data):
|
||||
setattr(instance, self.name, data)
|
||||
|
||||
def formfield(self, form_class=forms.CharField, **kwargs):
|
||||
"Returns a django.newforms.Field instance for this database Field."
|
||||
defaults = {'required': not self.blank, 'label': capfirst(self.verbose_name), 'help_text': self.help_text}
|
||||
@ -434,7 +466,7 @@ class CharField(Field):
|
||||
return smart_unicode(value)
|
||||
|
||||
def formfield(self, **kwargs):
|
||||
defaults = {'max_length': self.maxlength}
|
||||
defaults = {'max_length': self.max_length}
|
||||
defaults.update(kwargs)
|
||||
return super(CharField, self).formfield(**defaults)
|
||||
|
||||
@ -593,7 +625,8 @@ class DecimalField(Field):
|
||||
try:
|
||||
return decimal.Decimal(value)
|
||||
except decimal.InvalidOperation:
|
||||
raise validators.ValidationError, ugettext("This value must be a decimal number.")
|
||||
raise validators.ValidationError(
|
||||
_("This value must be a decimal number."))
|
||||
|
||||
def _format(self, value):
|
||||
if isinstance(value, basestring):
|
||||
@ -642,7 +675,7 @@ class DecimalField(Field):
|
||||
|
||||
class EmailField(CharField):
|
||||
def __init__(self, *args, **kwargs):
|
||||
kwargs['maxlength'] = 75
|
||||
kwargs['max_length'] = 75
|
||||
CharField.__init__(self, *args, **kwargs)
|
||||
|
||||
def get_internal_type(self):
|
||||
@ -664,6 +697,13 @@ class FileField(Field):
|
||||
self.upload_to = upload_to
|
||||
Field.__init__(self, verbose_name, name, **kwargs)
|
||||
|
||||
def get_db_prep_save(self, value):
|
||||
"Returns field's value prepared for saving into a database."
|
||||
# Need to convert UploadedFile objects provided via a form to unicode for database insertion
|
||||
if value is None:
|
||||
return None
|
||||
return unicode(value)
|
||||
|
||||
def get_manipulator_fields(self, opts, manipulator, change, name_prefix='', rel=False, follow=True):
|
||||
field_list = Field.get_manipulator_fields(self, opts, manipulator, change, name_prefix, rel, follow)
|
||||
if not self.blank:
|
||||
@ -740,6 +780,19 @@ class FileField(Field):
|
||||
f = os.path.join(self.get_directory_name(), get_valid_filename(os.path.basename(filename)))
|
||||
return os.path.normpath(f)
|
||||
|
||||
def save_form_data(self, instance, data):
|
||||
if data:
|
||||
getattr(instance, "save_%s_file" % self.name)(data.filename, data.content, save=False)
|
||||
|
||||
def formfield(self, **kwargs):
|
||||
defaults = {'form_class': forms.FileField}
|
||||
# If a file has been provided previously, then the form doesn't require
|
||||
# that a new file is provided this time.
|
||||
if 'initial' in kwargs:
|
||||
defaults['required'] = False
|
||||
defaults.update(kwargs)
|
||||
return super(FileField, self).formfield(**defaults)
|
||||
|
||||
class FilePathField(Field):
|
||||
def __init__(self, verbose_name=None, name=None, path='', match=None, recursive=False, **kwargs):
|
||||
self.path, self.match, self.recursive = path, match, recursive
|
||||
@ -788,6 +841,10 @@ class ImageField(FileField):
|
||||
setattr(new_object, self.height_field, getattr(original_object, self.height_field))
|
||||
new_object.save()
|
||||
|
||||
def formfield(self, **kwargs):
|
||||
defaults = {'form_class': forms.ImageField}
|
||||
return super(ImageField, self).formfield(**defaults)
|
||||
|
||||
class IntegerField(Field):
|
||||
empty_strings_allowed = False
|
||||
def get_manipulator_field_objs(self):
|
||||
@ -801,7 +858,7 @@ class IntegerField(Field):
|
||||
class IPAddressField(Field):
|
||||
empty_strings_allowed = False
|
||||
def __init__(self, *args, **kwargs):
|
||||
kwargs['maxlength'] = 15
|
||||
kwargs['max_length'] = 15
|
||||
Field.__init__(self, *args, **kwargs)
|
||||
|
||||
def get_manipulator_field_objs(self):
|
||||
@ -854,7 +911,7 @@ class PositiveSmallIntegerField(IntegerField):
|
||||
|
||||
class SlugField(Field):
|
||||
def __init__(self, *args, **kwargs):
|
||||
kwargs['maxlength'] = kwargs.get('maxlength', 50)
|
||||
kwargs['max_length'] = kwargs.get('max_length', 50)
|
||||
kwargs.setdefault('validator_list', []).append(validators.isSlug)
|
||||
# Set db_index=True unless it's been set manually.
|
||||
if 'db_index' not in kwargs:
|
||||
@ -940,7 +997,7 @@ class TimeField(Field):
|
||||
|
||||
class URLField(CharField):
|
||||
def __init__(self, verbose_name=None, name=None, verify_exists=True, **kwargs):
|
||||
kwargs['maxlength'] = kwargs.get('maxlength', 200)
|
||||
kwargs['max_length'] = kwargs.get('max_length', 200)
|
||||
if verify_exists:
|
||||
kwargs.setdefault('validator_list', []).append(validators.isExistingURL)
|
||||
self.verify_exists = verify_exists
|
||||
|
@ -1,6 +1,6 @@
|
||||
from django.db import backend, transaction
|
||||
from django.db.models import signals, get_model
|
||||
from django.db.models.fields import AutoField, Field, IntegerField, get_ul_class
|
||||
from django.db.models.fields import AutoField, Field, IntegerField, PositiveIntegerField, PositiveSmallIntegerField, get_ul_class
|
||||
from django.db.models.related import RelatedObject
|
||||
from django.utils.text import capfirst
|
||||
from django.utils.translation import ugettext_lazy, string_concat, ungettext, ugettext as _
|
||||
@ -548,6 +548,16 @@ class ForeignKey(RelatedField, Field):
|
||||
defaults.update(kwargs)
|
||||
return super(ForeignKey, self).formfield(**defaults)
|
||||
|
||||
def db_type(self):
|
||||
# The database column type of a ForeignKey is the column type
|
||||
# of the field to which it points. An exception is if the ForeignKey
|
||||
# points to an AutoField/PositiveIntegerField/PositiveSmallIntegerField,
|
||||
# in which case the column type is simply that of an IntegerField.
|
||||
rel_field = self.rel.get_related_field()
|
||||
if isinstance(rel_field, (AutoField, PositiveIntegerField, PositiveSmallIntegerField)):
|
||||
return IntegerField().db_type()
|
||||
return rel_field.db_type()
|
||||
|
||||
class OneToOneField(RelatedField, IntegerField):
|
||||
def __init__(self, to, to_field=None, **kwargs):
|
||||
try:
|
||||
@ -609,6 +619,16 @@ class OneToOneField(RelatedField, IntegerField):
|
||||
defaults.update(kwargs)
|
||||
return super(OneToOneField, self).formfield(**defaults)
|
||||
|
||||
def db_type(self):
|
||||
# The database column type of a OneToOneField is the column type
|
||||
# of the field to which it points. An exception is if the OneToOneField
|
||||
# points to an AutoField/PositiveIntegerField/PositiveSmallIntegerField,
|
||||
# in which case the column type is simply that of an IntegerField.
|
||||
rel_field = self.rel.get_related_field()
|
||||
if isinstance(rel_field, (AutoField, PositiveIntegerField, PositiveSmallIntegerField)):
|
||||
return IntegerField().db_type()
|
||||
return rel_field.db_type()
|
||||
|
||||
class ManyToManyField(RelatedField, Field):
|
||||
def __init__(self, to, **kwargs):
|
||||
kwargs['verbose_name'] = kwargs.get('verbose_name', None)
|
||||
@ -710,6 +730,9 @@ class ManyToManyField(RelatedField, Field):
|
||||
"Returns the value of this field in the given model instance."
|
||||
return getattr(obj, self.attname).all()
|
||||
|
||||
def save_form_data(self, instance, data):
|
||||
setattr(instance, self.attname, data)
|
||||
|
||||
def formfield(self, **kwargs):
|
||||
defaults = {'form_class': forms.ModelMultipleChoiceField, 'queryset': self.rel.to._default_manager.all()}
|
||||
defaults.update(kwargs)
|
||||
@ -719,6 +742,11 @@ class ManyToManyField(RelatedField, Field):
|
||||
defaults['initial'] = [i._get_pk_val() for i in defaults['initial']]
|
||||
return super(ManyToManyField, self).formfield(**defaults)
|
||||
|
||||
def db_type(self):
|
||||
# A ManyToManyField is not represented by a single column,
|
||||
# so return None.
|
||||
return None
|
||||
|
||||
class ManyToOneRel(object):
|
||||
def __init__(self, to, field_name, num_in_admin=3, min_num_in_admin=None,
|
||||
max_num_in_admin=None, num_extra_on_change=1, edit_inline=False,
|
||||
|
@ -3,10 +3,6 @@ from django.dispatch import dispatcher
|
||||
from django.db.models import signals
|
||||
from django.db.models.fields import FieldDoesNotExist
|
||||
|
||||
# Size of each "chunk" for get_iterator calls.
|
||||
# Larger values are slightly faster at the expense of more storage space.
|
||||
GET_ITERATOR_CHUNK_SIZE = 100
|
||||
|
||||
def ensure_default_manager(sender):
|
||||
cls = sender
|
||||
if not hasattr(cls, '_default_manager'):
|
||||
@ -47,7 +43,7 @@ class Manager(object):
|
||||
|
||||
def get_query_set(self):
|
||||
"""Returns a new QuerySet object. Subclasses can override this method
|
||||
to easily customise the behaviour of the Manager.
|
||||
to easily customize the behavior of the Manager.
|
||||
"""
|
||||
return QuerySet(self.model)
|
||||
|
||||
|
@ -579,28 +579,36 @@ class ValuesQuerySet(QuerySet):
|
||||
except EmptyResultSet:
|
||||
raise StopIteration
|
||||
|
||||
# self._fields is a list of field names to fetch.
|
||||
# self._select is a dictionary, and dictionaries' key order is
|
||||
# undefined, so we convert it to a list of tuples.
|
||||
extra_select = self._select.items()
|
||||
|
||||
# Construct two objects -- fields and field_names.
|
||||
# fields is a list of Field objects to fetch.
|
||||
# field_names is a list of field names, which will be the keys in the
|
||||
# resulting dictionaries.
|
||||
if self._fields:
|
||||
if not self._select:
|
||||
if not extra_select:
|
||||
fields = [self.model._meta.get_field(f, many_to_many=False) for f in self._fields]
|
||||
field_names = self._fields
|
||||
else:
|
||||
fields = []
|
||||
field_names = []
|
||||
for f in self._fields:
|
||||
if f in [field.name for field in self.model._meta.fields]:
|
||||
fields.append(self.model._meta.get_field(f, many_to_many=False))
|
||||
elif not self._select.has_key( f ):
|
||||
raise FieldDoesNotExist, '%s has no field named %r' % ( self.model._meta.object_name, f )
|
||||
|
||||
field_names = self._fields
|
||||
field_names.append(f)
|
||||
elif not self._select.has_key(f):
|
||||
raise FieldDoesNotExist('%s has no field named %r' % (self.model._meta.object_name, f))
|
||||
else: # Default to all fields.
|
||||
fields = self.model._meta.fields
|
||||
field_names = [f.attname for f in fields]
|
||||
|
||||
columns = [f.column for f in fields]
|
||||
select = ['%s.%s' % (backend.quote_name(self.model._meta.db_table), backend.quote_name(c)) for c in columns]
|
||||
# Add any additional SELECTs.
|
||||
if self._select:
|
||||
select.extend(['(%s) AS %s' % (quote_only_if_word(s[1]), backend.quote_name(s[0])) for s in self._select.items()])
|
||||
if extra_select:
|
||||
select.extend(['(%s) AS %s' % (quote_only_if_word(s[1]), backend.quote_name(s[0])) for s in extra_select])
|
||||
field_names.extend([f[0] for f in extra_select])
|
||||
|
||||
cursor = connection.cursor()
|
||||
cursor.execute("SELECT " + (self._distinct and "DISTINCT " or "") + ",".join(select) + sql, params)
|
||||
|
@ -109,12 +109,11 @@ class QueryDict(MultiValueDict):
|
||||
# *Important*: do not import settings any earlier because of note
|
||||
# in core.handlers.modpython.
|
||||
from django.conf import settings
|
||||
self.encoding = settings.DEFAULT_CHARSET
|
||||
else:
|
||||
self.encoding = encoding
|
||||
encoding = settings.DEFAULT_CHARSET
|
||||
self.encoding = encoding
|
||||
self._mutable = True
|
||||
for key, value in parse_qsl((query_string or ''), True): # keep_blank_values=True
|
||||
self.appendlist(force_unicode(key, errors='replace'), force_unicode(value, errors='replace'))
|
||||
self.appendlist(force_unicode(key, encoding, errors='replace'), force_unicode(value, encoding, errors='replace'))
|
||||
self._mutable = mutable
|
||||
|
||||
def _assert_mutable(self):
|
||||
|
@ -39,7 +39,7 @@ class CommonMiddleware(object):
|
||||
new_url[0] = 'www.' + old_url[0]
|
||||
# Append a slash if append_slash is set and the URL doesn't have a
|
||||
# trailing slash or a file extension.
|
||||
if settings.APPEND_SLASH and (old_url[1][-1] != '/') and ('.' not in old_url[1].split('/')[-1]):
|
||||
if settings.APPEND_SLASH and (not old_url[1].endswith('/')) and ('.' not in old_url[1].split('/')[-1]):
|
||||
new_url[1] = new_url[1] + '/'
|
||||
if settings.DEBUG and request.method == 'POST':
|
||||
raise RuntimeError, "You called this URL via POST, but the URL doesn't end in a slash and you have APPEND_SLASH set. Django can't redirect to the slash URL while maintaining POST data. Change your form to point to %s%s (note the trailing slash), or set APPEND_SLASH=False in your Django settings." % (new_url[0], new_url[1])
|
||||
|
@ -1,4 +1,4 @@
|
||||
import datetime
|
||||
from email.Utils import formatdate
|
||||
|
||||
class ConditionalGetMiddleware(object):
|
||||
"""
|
||||
@ -11,8 +11,7 @@ class ConditionalGetMiddleware(object):
|
||||
Also sets the Date and Content-Length response-headers.
|
||||
"""
|
||||
def process_response(self, request, response):
|
||||
now = datetime.datetime.utcnow()
|
||||
response['Date'] = now.strftime('%a, %d %b %Y %H:%M:%S GMT')
|
||||
response['Date'] = formatdate()[:26] + "GMT"
|
||||
if not response.has_header('Content-Length'):
|
||||
response['Content-Length'] = str(len(response.content))
|
||||
|
||||
|
@ -53,7 +53,7 @@ class SelectDateWidget(Widget):
|
||||
|
||||
return u'\n'.join(output)
|
||||
|
||||
def value_from_datadict(self, data, name):
|
||||
def value_from_datadict(self, data, files, name):
|
||||
y, m, d = data.get(self.year_field % name), data.get(self.month_field % name), data.get(self.day_field % name)
|
||||
if y and m and d:
|
||||
return '%s-%s-%s' % (y, m, d)
|
||||
|
@ -7,17 +7,22 @@ import re
|
||||
import time
|
||||
|
||||
from django.utils.translation import ugettext
|
||||
from django.utils.encoding import smart_unicode
|
||||
from django.utils.encoding import StrAndUnicode, smart_unicode
|
||||
|
||||
from util import ErrorList, ValidationError
|
||||
from widgets import TextInput, PasswordInput, HiddenInput, MultipleHiddenInput, CheckboxInput, Select, NullBooleanSelect, SelectMultiple
|
||||
from widgets import TextInput, PasswordInput, HiddenInput, MultipleHiddenInput, FileInput, CheckboxInput, Select, NullBooleanSelect, SelectMultiple
|
||||
|
||||
try:
|
||||
from decimal import Decimal, DecimalException
|
||||
except ImportError:
|
||||
from django.utils._decimal import Decimal, DecimalException
|
||||
|
||||
__all__ = (
|
||||
'Field', 'CharField', 'IntegerField',
|
||||
'DEFAULT_DATE_INPUT_FORMATS', 'DateField',
|
||||
'DEFAULT_TIME_INPUT_FORMATS', 'TimeField',
|
||||
'DEFAULT_DATETIME_INPUT_FORMATS', 'DateTimeField',
|
||||
'RegexField', 'EmailField', 'URLField', 'BooleanField',
|
||||
'RegexField', 'EmailField', 'FileField', 'ImageField', 'URLField', 'BooleanField',
|
||||
'ChoiceField', 'NullBooleanField', 'MultipleChoiceField',
|
||||
'ComboField', 'MultiValueField', 'FloatField', 'DecimalField',
|
||||
'SplitDateTimeField',
|
||||
@ -106,14 +111,16 @@ class CharField(Field):
|
||||
if value in EMPTY_VALUES:
|
||||
return u''
|
||||
value = smart_unicode(value)
|
||||
if self.max_length is not None and len(value) > self.max_length:
|
||||
raise ValidationError(ugettext(u'Ensure this value has at most %d characters.') % self.max_length)
|
||||
if self.min_length is not None and len(value) < self.min_length:
|
||||
raise ValidationError(ugettext(u'Ensure this value has at least %d characters.') % self.min_length)
|
||||
value_length = len(value)
|
||||
if self.max_length is not None and value_length > self.max_length:
|
||||
raise ValidationError(ugettext(u'Ensure this value has at most %(max)d characters (it has %(length)d).') % {'max': self.max_length, 'length': value_length})
|
||||
if self.min_length is not None and value_length < self.min_length:
|
||||
raise ValidationError(ugettext(u'Ensure this value has at least %(min)d characters (it has %(length)d).') % {'min': self.min_length, 'length': value_length})
|
||||
return value
|
||||
|
||||
def widget_attrs(self, widget):
|
||||
if self.max_length is not None and isinstance(widget, (TextInput, PasswordInput)):
|
||||
# The HTML attribute is maxlength, not max_length.
|
||||
return {'maxlength': str(self.max_length)}
|
||||
|
||||
class IntegerField(Field):
|
||||
@ -162,8 +169,6 @@ class FloatField(Field):
|
||||
raise ValidationError(ugettext('Ensure this value is greater than or equal to %s.') % self.min_value)
|
||||
return value
|
||||
|
||||
decimal_re = re.compile(r'^-?(?P<digits>\d+)(\.(?P<decimals>\d+))?$')
|
||||
|
||||
class DecimalField(Field):
|
||||
def __init__(self, max_value=None, min_value=None, max_digits=None, decimal_places=None, *args, **kwargs):
|
||||
self.max_value, self.min_value = max_value, min_value
|
||||
@ -181,13 +186,13 @@ class DecimalField(Field):
|
||||
if not self.required and value in EMPTY_VALUES:
|
||||
return None
|
||||
value = value.strip()
|
||||
match = decimal_re.search(value)
|
||||
if not match:
|
||||
raise ValidationError(ugettext('Enter a number.'))
|
||||
else:
|
||||
try:
|
||||
value = Decimal(value)
|
||||
digits = len(match.group('digits') or '')
|
||||
decimals = len(match.group('decimals') or '')
|
||||
except DecimalException:
|
||||
raise ValidationError(ugettext('Enter a number.'))
|
||||
pieces = str(value).split('.')
|
||||
decimals = (len(pieces) == 2) and len(pieces[1]) or 0
|
||||
digits = len(pieces[0])
|
||||
if self.max_value is not None and value > self.max_value:
|
||||
raise ValidationError(ugettext('Ensure this value is less than or equal to %s.') % self.max_value)
|
||||
if self.min_value is not None and value < self.min_value:
|
||||
@ -295,18 +300,17 @@ class DateTimeField(Field):
|
||||
continue
|
||||
raise ValidationError(ugettext(u'Enter a valid date/time.'))
|
||||
|
||||
class RegexField(Field):
|
||||
class RegexField(CharField):
|
||||
def __init__(self, regex, max_length=None, min_length=None, error_message=None, *args, **kwargs):
|
||||
"""
|
||||
regex can be either a string or a compiled regular expression object.
|
||||
error_message is an optional error message to use, if
|
||||
'Enter a valid value' is too generic for you.
|
||||
"""
|
||||
super(RegexField, self).__init__(*args, **kwargs)
|
||||
super(RegexField, self).__init__(max_length, min_length, *args, **kwargs)
|
||||
if isinstance(regex, basestring):
|
||||
regex = re.compile(regex)
|
||||
self.regex = regex
|
||||
self.max_length, self.min_length = max_length, min_length
|
||||
self.error_message = error_message or ugettext(u'Enter a valid value.')
|
||||
|
||||
def clean(self, value):
|
||||
@ -314,16 +318,9 @@ class RegexField(Field):
|
||||
Validates that the input matches the regular expression. Returns a
|
||||
Unicode object.
|
||||
"""
|
||||
super(RegexField, self).clean(value)
|
||||
if value in EMPTY_VALUES:
|
||||
value = u''
|
||||
value = smart_unicode(value)
|
||||
value = super(RegexField, self).clean(value)
|
||||
if value == u'':
|
||||
return value
|
||||
if self.max_length is not None and len(value) > self.max_length:
|
||||
raise ValidationError(ugettext(u'Ensure this value has at most %d characters.') % self.max_length)
|
||||
if self.min_length is not None and len(value) < self.min_length:
|
||||
raise ValidationError(ugettext(u'Ensure this value has at least %d characters.') % self.min_length)
|
||||
if not self.regex.search(value):
|
||||
raise ValidationError(self.error_message)
|
||||
return value
|
||||
@ -351,6 +348,55 @@ except ImportError:
|
||||
# It's OK if Django settings aren't configured.
|
||||
URL_VALIDATOR_USER_AGENT = 'Django (http://www.djangoproject.com/)'
|
||||
|
||||
class UploadedFile(StrAndUnicode):
|
||||
"A wrapper for files uploaded in a FileField"
|
||||
def __init__(self, filename, content):
|
||||
self.filename = filename
|
||||
self.content = content
|
||||
|
||||
def __unicode__(self):
|
||||
"""
|
||||
The unicode representation is the filename, so that the pre-database-insertion
|
||||
logic can use UploadedFile objects
|
||||
"""
|
||||
return self.filename
|
||||
|
||||
class FileField(Field):
|
||||
widget = FileInput
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(FileField, self).__init__(*args, **kwargs)
|
||||
|
||||
def clean(self, data):
|
||||
super(FileField, self).clean(data)
|
||||
if not self.required and data in EMPTY_VALUES:
|
||||
return None
|
||||
try:
|
||||
f = UploadedFile(data['filename'], data['content'])
|
||||
except TypeError:
|
||||
raise ValidationError(ugettext(u"No file was submitted. Check the encoding type on the form."))
|
||||
except KeyError:
|
||||
raise ValidationError(ugettext(u"No file was submitted."))
|
||||
if not f.content:
|
||||
raise ValidationError(ugettext(u"The submitted file is empty."))
|
||||
return f
|
||||
|
||||
class ImageField(FileField):
|
||||
def clean(self, data):
|
||||
"""
|
||||
Checks that the file-upload field data contains a valid image (GIF, JPG,
|
||||
PNG, possibly others -- whatever the Python Imaging Library supports).
|
||||
"""
|
||||
f = super(ImageField, self).clean(data)
|
||||
if f is None:
|
||||
return None
|
||||
from PIL import Image
|
||||
from cStringIO import StringIO
|
||||
try:
|
||||
Image.open(StringIO(f.content))
|
||||
except IOError: # Python Imaging Library doesn't recognize it as an image
|
||||
raise ValidationError(ugettext(u"Upload a valid image. The file you uploaded was either not an image or a corrupted image."))
|
||||
return f
|
||||
|
||||
class URLField(RegexField):
|
||||
def __init__(self, max_length=None, min_length=None, verify_exists=False,
|
||||
validator_user_agent=URL_VALIDATOR_USER_AGENT, *args, **kwargs):
|
||||
@ -446,10 +492,7 @@ class MultipleChoiceField(ChoiceField):
|
||||
return []
|
||||
if not isinstance(value, (list, tuple)):
|
||||
raise ValidationError(ugettext(u'Enter a list of values.'))
|
||||
new_value = []
|
||||
for val in value:
|
||||
val = smart_unicode(val)
|
||||
new_value.append(val)
|
||||
new_value = [smart_unicode(val) for val in value]
|
||||
# Validate that each value in the value list is in self.choices.
|
||||
valid_values = set([smart_unicode(k) for k, v in self.choices])
|
||||
for val in new_value:
|
||||
|
@ -57,9 +57,10 @@ class BaseForm(StrAndUnicode):
|
||||
# class is different than Form. See the comments by the Form class for more
|
||||
# information. Any improvements to the form API should be made to *this*
|
||||
# class, not to the Form class.
|
||||
def __init__(self, data=None, auto_id='id_%s', prefix=None, initial=None):
|
||||
self.is_bound = data is not None
|
||||
def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None, initial=None):
|
||||
self.is_bound = data is not None or files is not None
|
||||
self.data = data or {}
|
||||
self.files = files or {}
|
||||
self.auto_id = auto_id
|
||||
self.prefix = prefix
|
||||
self.initial = initial or {}
|
||||
@ -88,7 +89,7 @@ class BaseForm(StrAndUnicode):
|
||||
return BoundField(self, field, name)
|
||||
|
||||
def _get_errors(self):
|
||||
"Returns an ErrorDict for self.data"
|
||||
"Returns an ErrorDict for the data provided for the form"
|
||||
if self._errors is None:
|
||||
self.full_clean()
|
||||
return self._errors
|
||||
@ -182,7 +183,7 @@ class BaseForm(StrAndUnicode):
|
||||
# value_from_datadict() gets the data from the dictionary.
|
||||
# Each widget type knows how to retrieve its own data, because some
|
||||
# widgets split data over several HTML fields.
|
||||
value = field.widget.value_from_datadict(self.data, self.add_prefix(name))
|
||||
value = field.widget.value_from_datadict(self.data, self.files, self.add_prefix(name))
|
||||
# HACK: ['', ''] and [None, None] deal with SplitDateTimeWidget. This should be more robust.
|
||||
if value not in (None, '', ['', ''], [None, None]):
|
||||
return False
|
||||
@ -198,10 +199,10 @@ class BaseForm(StrAndUnicode):
|
||||
return
|
||||
self.cleaned_data = {}
|
||||
for name, field in self.fields.items():
|
||||
# value_from_datadict() gets the data from the dictionary.
|
||||
# value_from_datadict() gets the data from the data dictionaries.
|
||||
# Each widget type knows how to retrieve its own data, because some
|
||||
# widgets split data over several HTML fields.
|
||||
value = field.widget.value_from_datadict(self.data, self.add_prefix(name))
|
||||
value = field.widget.value_from_datadict(self.data, self.files, self.add_prefix(name))
|
||||
try:
|
||||
value = field.clean(value)
|
||||
self.cleaned_data[name] = value
|
||||
@ -257,16 +258,8 @@ class BoundField(StrAndUnicode):
|
||||
self.help_text = field.help_text or ''
|
||||
|
||||
def __unicode__(self):
|
||||
"Renders this field as an HTML widget."
|
||||
# Use the 'widget' attribute on the field to determine which type
|
||||
# of HTML widget to use.
|
||||
value = self.as_widget(self.field.widget)
|
||||
if not isinstance(value, basestring):
|
||||
# Some Widget render() methods -- notably RadioSelect -- return a
|
||||
# "special" object rather than a string. Call __unicode__() on that
|
||||
# object to get its rendered value.
|
||||
value = unicode(value)
|
||||
return value
|
||||
"""Renders this field as an HTML widget."""
|
||||
return self.as_widget()
|
||||
|
||||
def _errors(self):
|
||||
"""
|
||||
@ -276,7 +269,14 @@ class BoundField(StrAndUnicode):
|
||||
return self.form.errors.get(self.name, ErrorList())
|
||||
errors = property(_errors)
|
||||
|
||||
def as_widget(self, widget, attrs=None):
|
||||
def as_widget(self, widget=None, attrs=None):
|
||||
"""
|
||||
Renders the field by rendering the passed widget, adding any HTML
|
||||
attributes passed as attrs. If no widget is specified, then the
|
||||
field's default widget will be used.
|
||||
"""
|
||||
if not widget:
|
||||
widget = self.field.widget
|
||||
attrs = attrs or {}
|
||||
auto_id = self.auto_id
|
||||
if auto_id and 'id' not in attrs and 'id' not in widget.attrs:
|
||||
@ -309,7 +309,7 @@ class BoundField(StrAndUnicode):
|
||||
"""
|
||||
Returns the data for this BoundField, or None if it wasn't given.
|
||||
"""
|
||||
return self.field.widget.value_from_datadict(self.form.data, self.html_name)
|
||||
return self.field.widget.value_from_datadict(self.form.data, self.form.files, self.html_name)
|
||||
data = property(_data)
|
||||
|
||||
def label_tag(self, contents=None, attrs=None):
|
||||
|
@ -35,18 +35,24 @@ def save_instance(form, instance, fields=None, fail_message='saved', commit=True
|
||||
continue
|
||||
if fields and f.name not in fields:
|
||||
continue
|
||||
setattr(instance, f.name, cleaned_data[f.name])
|
||||
if commit:
|
||||
instance.save()
|
||||
f.save_form_data(instance, cleaned_data[f.name])
|
||||
# Wrap up the saving of m2m data as a function
|
||||
def save_m2m():
|
||||
opts = instance.__class__._meta
|
||||
cleaned_data = form.cleaned_data
|
||||
for f in opts.many_to_many:
|
||||
if fields and f.name not in fields:
|
||||
continue
|
||||
if f.name in cleaned_data:
|
||||
setattr(instance, f.attname, cleaned_data[f.name])
|
||||
# GOTCHA: If many-to-many data is given and commit=False, the many-to-many
|
||||
# data will be lost. This happens because a many-to-many options cannot be
|
||||
# set on an object until after it's saved. Maybe we should raise an
|
||||
# exception in that case.
|
||||
f.save_form_data(instance, cleaned_data[f.name])
|
||||
if commit:
|
||||
# If we are committing, save the instance and the m2m data immediately
|
||||
instance.save()
|
||||
save_m2m()
|
||||
else:
|
||||
# We're not committing. Add a method to the form to allow deferred
|
||||
# saving of m2m data
|
||||
form.save_m2m = save_m2m
|
||||
return instance
|
||||
|
||||
def make_model_save(model, fields, fail_message):
|
||||
|
@ -47,7 +47,7 @@ class Widget(object):
|
||||
attrs.update(extra_attrs)
|
||||
return attrs
|
||||
|
||||
def value_from_datadict(self, data, name):
|
||||
def value_from_datadict(self, data, files, name):
|
||||
"""
|
||||
Given a dictionary of data and this widget's name, returns the value
|
||||
of this widget. Returns None if it's not provided.
|
||||
@ -113,7 +113,7 @@ class MultipleHiddenInput(HiddenInput):
|
||||
final_attrs = self.build_attrs(attrs, type=self.input_type, name=name)
|
||||
return u'\n'.join([(u'<input%s />' % flatatt(dict(value=force_unicode(v), **final_attrs))) for v in value])
|
||||
|
||||
def value_from_datadict(self, data, name):
|
||||
def value_from_datadict(self, data, files, name):
|
||||
if isinstance(data, MultiValueDict):
|
||||
return data.getlist(name)
|
||||
return data.get(name, None)
|
||||
@ -121,6 +121,13 @@ class MultipleHiddenInput(HiddenInput):
|
||||
class FileInput(Input):
|
||||
input_type = 'file'
|
||||
|
||||
def render(self, name, value, attrs=None):
|
||||
return super(FileInput, self).render(name, None, attrs=attrs)
|
||||
|
||||
def value_from_datadict(self, data, files, name):
|
||||
"File widgets take data from FILES, not POST"
|
||||
return files.get(name, None)
|
||||
|
||||
class Textarea(Widget):
|
||||
def __init__(self, attrs=None):
|
||||
# The 'rows' and 'cols' attributes are required for HTML correctness.
|
||||
@ -188,7 +195,7 @@ class NullBooleanSelect(Select):
|
||||
value = u'1'
|
||||
return super(NullBooleanSelect, self).render(name, value, attrs, choices)
|
||||
|
||||
def value_from_datadict(self, data, name):
|
||||
def value_from_datadict(self, data, files, name):
|
||||
value = data.get(name, None)
|
||||
return {u'2': True, u'3': False, True: True, False: False}.get(value, None)
|
||||
|
||||
@ -210,13 +217,17 @@ class SelectMultiple(Widget):
|
||||
output.append(u'</select>')
|
||||
return u'\n'.join(output)
|
||||
|
||||
def value_from_datadict(self, data, name):
|
||||
def value_from_datadict(self, data, files, name):
|
||||
if isinstance(data, MultiValueDict):
|
||||
return data.getlist(name)
|
||||
return data.get(name, None)
|
||||
|
||||
class RadioInput(StrAndUnicode):
|
||||
"An object used by RadioFieldRenderer that represents a single <input type='radio'>."
|
||||
"""
|
||||
An object used by RadioFieldRenderer that represents a single
|
||||
<input type='radio'>.
|
||||
"""
|
||||
|
||||
def __init__(self, name, value, attrs, choice, index):
|
||||
self.name, self.value = name, value
|
||||
self.attrs = attrs
|
||||
@ -239,7 +250,10 @@ class RadioInput(StrAndUnicode):
|
||||
return u'<input%s />' % flatatt(final_attrs)
|
||||
|
||||
class RadioFieldRenderer(StrAndUnicode):
|
||||
"An object used by RadioSelect to enable customization of radio widgets."
|
||||
"""
|
||||
An object used by RadioSelect to enable customization of radio widgets.
|
||||
"""
|
||||
|
||||
def __init__(self, name, value, attrs, choices):
|
||||
self.name, self.value, self.attrs = name, value, attrs
|
||||
self.choices = choices
|
||||
@ -253,16 +267,30 @@ class RadioFieldRenderer(StrAndUnicode):
|
||||
return RadioInput(self.name, self.value, self.attrs.copy(), choice, idx)
|
||||
|
||||
def __unicode__(self):
|
||||
"Outputs a <ul> for this set of radio fields."
|
||||
return self.render()
|
||||
|
||||
def render(self):
|
||||
"""Outputs a <ul> for this set of radio fields."""
|
||||
return u'<ul>\n%s\n</ul>' % u'\n'.join([u'<li>%s</li>' % force_unicode(w) for w in self])
|
||||
|
||||
class RadioSelect(Select):
|
||||
def render(self, name, value, attrs=None, choices=()):
|
||||
"Returns a RadioFieldRenderer instance rather than a Unicode string."
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.renderer = kwargs.pop('renderer', None)
|
||||
if not self.renderer:
|
||||
self.renderer = RadioFieldRenderer
|
||||
super(RadioSelect, self).__init__(*args, **kwargs)
|
||||
|
||||
def get_renderer(self, name, value, attrs=None, choices=()):
|
||||
"""Returns an instance of the renderer."""
|
||||
if value is None: value = ''
|
||||
str_value = force_unicode(value) # Normalize to string.
|
||||
final_attrs = self.build_attrs(attrs)
|
||||
return RadioFieldRenderer(name, str_value, final_attrs, list(chain(self.choices, choices)))
|
||||
choices = list(chain(self.choices, choices))
|
||||
return self.renderer(name, str_value, final_attrs, choices)
|
||||
|
||||
def render(self, name, value, attrs=None, choices=()):
|
||||
return self.get_renderer(name, value, attrs, choices).render()
|
||||
|
||||
def id_for_label(self, id_):
|
||||
# RadioSelect is represented by multiple <input type="radio"> fields,
|
||||
@ -356,8 +384,8 @@ class MultiWidget(Widget):
|
||||
return id_
|
||||
id_for_label = classmethod(id_for_label)
|
||||
|
||||
def value_from_datadict(self, data, name):
|
||||
return [widget.value_from_datadict(data, name + '_%s' % i) for i, widget in enumerate(self.widgets)]
|
||||
def value_from_datadict(self, data, files, name):
|
||||
return [widget.value_from_datadict(data, files, name + '_%s' % i) for i, widget in enumerate(self.widgets)]
|
||||
|
||||
def format_output(self, rendered_widgets):
|
||||
"""
|
||||
|
@ -3,7 +3,8 @@ from django.core.exceptions import PermissionDenied
|
||||
from django.utils.html import escape
|
||||
from django.conf import settings
|
||||
from django.utils.translation import ugettext, ungettext
|
||||
from django.utils.encoding import smart_unicode, force_unicode, smart_str
|
||||
from django.utils.encoding import smart_unicode, force_unicode
|
||||
from django.utils.maxlength import LegacyMaxlength
|
||||
|
||||
FORM_FIELD_ID_PREFIX = 'id_'
|
||||
|
||||
@ -302,6 +303,9 @@ class FormField(object):
|
||||
Subclasses should also implement a render(data) method, which is responsible
|
||||
for rending the form field in XHTML.
|
||||
"""
|
||||
# Provide backwards compatibility for the maxlength attribute and
|
||||
# argument for this class and all subclasses.
|
||||
__metaclass__ = LegacyMaxlength
|
||||
|
||||
def __str__(self):
|
||||
return unicode(self).encode('utf-8')
|
||||
@ -390,19 +394,19 @@ class FormField(object):
|
||||
|
||||
class TextField(FormField):
|
||||
input_type = "text"
|
||||
def __init__(self, field_name, length=30, maxlength=None, is_required=False, validator_list=None, member_name=None):
|
||||
def __init__(self, field_name, length=30, max_length=None, is_required=False, validator_list=None, member_name=None):
|
||||
if validator_list is None: validator_list = []
|
||||
self.field_name = field_name
|
||||
self.length, self.maxlength = length, maxlength
|
||||
self.length, self.max_length = length, max_length
|
||||
self.is_required = is_required
|
||||
self.validator_list = [self.isValidLength, self.hasNoNewlines] + validator_list
|
||||
if member_name != None:
|
||||
self.member_name = member_name
|
||||
|
||||
def isValidLength(self, data, form):
|
||||
if data and self.maxlength and len(smart_unicode(data)) > self.maxlength:
|
||||
if data and self.max_length and len(smart_unicode(data)) > self.max_length:
|
||||
raise validators.ValidationError, ungettext("Ensure your text is less than %s character.",
|
||||
"Ensure your text is less than %s characters.", self.maxlength) % self.maxlength
|
||||
"Ensure your text is less than %s characters.", self.max_length) % self.max_length
|
||||
|
||||
def hasNoNewlines(self, data, form):
|
||||
if data and '\n' in data:
|
||||
@ -411,12 +415,12 @@ class TextField(FormField):
|
||||
def render(self, data):
|
||||
if data is None:
|
||||
data = u''
|
||||
maxlength = u''
|
||||
if self.maxlength:
|
||||
maxlength = u'maxlength="%s" ' % self.maxlength
|
||||
max_length = u''
|
||||
if self.max_length:
|
||||
max_length = u'maxlength="%s" ' % self.max_length
|
||||
return u'<input type="%s" id="%s" class="v%s%s" name="%s" size="%s" value="%s" %s/>' % \
|
||||
(self.input_type, self.get_id(), self.__class__.__name__, self.is_required and u' required' or '',
|
||||
self.field_name, self.length, escape(data), maxlength)
|
||||
self.field_name, self.length, escape(data), max_length)
|
||||
|
||||
def html2python(data):
|
||||
return data
|
||||
@ -426,14 +430,14 @@ class PasswordField(TextField):
|
||||
input_type = "password"
|
||||
|
||||
class LargeTextField(TextField):
|
||||
def __init__(self, field_name, rows=10, cols=40, is_required=False, validator_list=None, maxlength=None):
|
||||
def __init__(self, field_name, rows=10, cols=40, is_required=False, validator_list=None, max_length=None):
|
||||
if validator_list is None: validator_list = []
|
||||
self.field_name = field_name
|
||||
self.rows, self.cols, self.is_required = rows, cols, is_required
|
||||
self.validator_list = validator_list[:]
|
||||
if maxlength:
|
||||
if max_length:
|
||||
self.validator_list.append(self.isValidLength)
|
||||
self.maxlength = maxlength
|
||||
self.max_length = max_length
|
||||
|
||||
def render(self, data):
|
||||
if data is None:
|
||||
@ -502,7 +506,7 @@ class SelectField(FormField):
|
||||
|
||||
def isValidChoice(self, data, form):
|
||||
str_data = smart_unicode(data)
|
||||
str_choices = [smart_str(item[0]) for item in self.choices]
|
||||
str_choices = [smart_unicode(item[0]) for item in self.choices]
|
||||
if str_data not in str_choices:
|
||||
raise validators.ValidationError, ugettext("Select a valid choice; '%(data)s' is not in %(choices)s.") % {'data': str_data, 'choices': str_choices}
|
||||
|
||||
@ -710,12 +714,12 @@ class ImageUploadField(FileUploadField):
|
||||
####################
|
||||
|
||||
class IntegerField(TextField):
|
||||
def __init__(self, field_name, length=10, maxlength=None, is_required=False, validator_list=None, member_name=None):
|
||||
def __init__(self, field_name, length=10, max_length=None, is_required=False, validator_list=None, member_name=None):
|
||||
if validator_list is None: validator_list = []
|
||||
validator_list = [self.isInteger] + validator_list
|
||||
if member_name is not None:
|
||||
self.member_name = member_name
|
||||
TextField.__init__(self, field_name, length, maxlength, is_required, validator_list)
|
||||
TextField.__init__(self, field_name, length, max_length, is_required, validator_list)
|
||||
|
||||
def isInteger(self, field_data, all_data):
|
||||
try:
|
||||
@ -730,57 +734,57 @@ class IntegerField(TextField):
|
||||
html2python = staticmethod(html2python)
|
||||
|
||||
class SmallIntegerField(IntegerField):
|
||||
def __init__(self, field_name, length=5, maxlength=5, is_required=False, validator_list=None):
|
||||
def __init__(self, field_name, length=5, max_length=5, is_required=False, validator_list=None):
|
||||
if validator_list is None: validator_list = []
|
||||
validator_list = [self.isSmallInteger] + validator_list
|
||||
IntegerField.__init__(self, field_name, length, maxlength, is_required, validator_list)
|
||||
IntegerField.__init__(self, field_name, length, max_length, is_required, validator_list)
|
||||
|
||||
def isSmallInteger(self, field_data, all_data):
|
||||
if not -32768 <= int(field_data) <= 32767:
|
||||
raise validators.CriticalValidationError, ugettext("Enter a whole number between -32,768 and 32,767.")
|
||||
|
||||
class PositiveIntegerField(IntegerField):
|
||||
def __init__(self, field_name, length=10, maxlength=None, is_required=False, validator_list=None):
|
||||
def __init__(self, field_name, length=10, max_length=None, is_required=False, validator_list=None):
|
||||
if validator_list is None: validator_list = []
|
||||
validator_list = [self.isPositive] + validator_list
|
||||
IntegerField.__init__(self, field_name, length, maxlength, is_required, validator_list)
|
||||
IntegerField.__init__(self, field_name, length, max_length, is_required, validator_list)
|
||||
|
||||
def isPositive(self, field_data, all_data):
|
||||
if int(field_data) < 0:
|
||||
raise validators.CriticalValidationError, ugettext("Enter a positive number.")
|
||||
|
||||
class PositiveSmallIntegerField(IntegerField):
|
||||
def __init__(self, field_name, length=5, maxlength=None, is_required=False, validator_list=None):
|
||||
def __init__(self, field_name, length=5, max_length=None, is_required=False, validator_list=None):
|
||||
if validator_list is None: validator_list = []
|
||||
validator_list = [self.isPositiveSmall] + validator_list
|
||||
IntegerField.__init__(self, field_name, length, maxlength, is_required, validator_list)
|
||||
IntegerField.__init__(self, field_name, length, max_length, is_required, validator_list)
|
||||
|
||||
def isPositiveSmall(self, field_data, all_data):
|
||||
if not 0 <= int(field_data) <= 32767:
|
||||
raise validators.CriticalValidationError, ugettext("Enter a whole number between 0 and 32,767.")
|
||||
|
||||
class FloatField(TextField):
|
||||
def __init__(self, field_name, is_required=False, validator_list=None):
|
||||
if validator_list is None: validator_list = []
|
||||
validator_list = [validators.isValidFloat] + validator_list
|
||||
TextField.__init__(self, field_name, is_required=is_required, validator_list=validator_list)
|
||||
|
||||
def html2python(data):
|
||||
if data == '' or data is None:
|
||||
return None
|
||||
return float(data)
|
||||
html2python = staticmethod(html2python)
|
||||
|
||||
class DecimalField(TextField):
|
||||
def __init__(self, field_name, is_required=False, validator_list=None):
|
||||
if validator_list is None: validator_list = []
|
||||
validator_list = [validators.isValidFloat] + validator_list
|
||||
TextField.__init__(self, field_name, is_required=is_required, validator_list=validator_list)
|
||||
|
||||
def html2python(data):
|
||||
if data == '' or data is None:
|
||||
return None
|
||||
return float(data)
|
||||
html2python = staticmethod(html2python)
|
||||
|
||||
class DecimalField(TextField):
|
||||
def __init__(self, field_name, max_digits, decimal_places, is_required=False, validator_list=None):
|
||||
if validator_list is None: validator_list = []
|
||||
self.max_digits, self.decimal_places = max_digits, decimal_places
|
||||
validator_list = [self.isValidDecimal] + validator_list
|
||||
# Initialise the TextField, making sure it's large enough to fit the number with a - sign and a decimal point.
|
||||
super(DecimalField, self).__init__(field_name, max_digits+2, max_digits+2, is_required, validator_list)
|
||||
validator_list = [self.isValidDecimal] + validator_list
|
||||
# Initialise the TextField, making sure it's large enough to fit the number with a - sign and a decimal point.
|
||||
super(DecimalField, self).__init__(field_name, max_digits+2, max_digits+2, is_required, validator_list)
|
||||
|
||||
def isValidDecimal(self, field_data, all_data):
|
||||
v = validators.IsValidDecimal(self.max_digits, self.decimal_places)
|
||||
def isValidDecimal(self, field_data, all_data):
|
||||
v = validators.IsValidDecimal(self.max_digits, self.decimal_places)
|
||||
try:
|
||||
v(field_data, all_data)
|
||||
except validators.ValidationError, e:
|
||||
@ -789,14 +793,14 @@ class DecimalField(TextField):
|
||||
def html2python(data):
|
||||
if data == '' or data is None:
|
||||
return None
|
||||
try:
|
||||
import decimal
|
||||
try:
|
||||
import decimal
|
||||
except ImportError:
|
||||
from django.utils import _decimal as decimal
|
||||
try:
|
||||
return decimal.Decimal(data)
|
||||
except decimal.InvalidOperation, e:
|
||||
raise ValueError, e
|
||||
try:
|
||||
return decimal.Decimal(data)
|
||||
except decimal.InvalidOperation, e:
|
||||
raise ValueError, e
|
||||
html2python = staticmethod(html2python)
|
||||
|
||||
####################
|
||||
@ -806,10 +810,10 @@ class DecimalField(TextField):
|
||||
class DatetimeField(TextField):
|
||||
"""A FormField that automatically converts its data to a datetime.datetime object.
|
||||
The data should be in the format YYYY-MM-DD HH:MM:SS."""
|
||||
def __init__(self, field_name, length=30, maxlength=None, is_required=False, validator_list=None):
|
||||
def __init__(self, field_name, length=30, max_length=None, is_required=False, validator_list=None):
|
||||
if validator_list is None: validator_list = []
|
||||
self.field_name = field_name
|
||||
self.length, self.maxlength = length, maxlength
|
||||
self.length, self.max_length = length, max_length
|
||||
self.is_required = is_required
|
||||
self.validator_list = [validators.isValidANSIDatetime] + validator_list
|
||||
|
||||
@ -836,7 +840,7 @@ class DateField(TextField):
|
||||
def __init__(self, field_name, is_required=False, validator_list=None):
|
||||
if validator_list is None: validator_list = []
|
||||
validator_list = [self.isValidDate] + validator_list
|
||||
TextField.__init__(self, field_name, length=10, maxlength=10,
|
||||
TextField.__init__(self, field_name, length=10, max_length=10,
|
||||
is_required=is_required, validator_list=validator_list)
|
||||
|
||||
def isValidDate(self, field_data, all_data):
|
||||
@ -861,7 +865,7 @@ class TimeField(TextField):
|
||||
def __init__(self, field_name, is_required=False, validator_list=None):
|
||||
if validator_list is None: validator_list = []
|
||||
validator_list = [self.isValidTime] + validator_list
|
||||
TextField.__init__(self, field_name, length=8, maxlength=8,
|
||||
TextField.__init__(self, field_name, length=8, max_length=8,
|
||||
is_required=is_required, validator_list=validator_list)
|
||||
|
||||
def isValidTime(self, field_data, all_data):
|
||||
@ -893,10 +897,10 @@ class TimeField(TextField):
|
||||
|
||||
class EmailField(TextField):
|
||||
"A convenience FormField for validating e-mail addresses"
|
||||
def __init__(self, field_name, length=50, maxlength=75, is_required=False, validator_list=None):
|
||||
def __init__(self, field_name, length=50, max_length=75, is_required=False, validator_list=None):
|
||||
if validator_list is None: validator_list = []
|
||||
validator_list = [self.isValidEmail] + validator_list
|
||||
TextField.__init__(self, field_name, length, maxlength=maxlength,
|
||||
TextField.__init__(self, field_name, length, max_length=max_length,
|
||||
is_required=is_required, validator_list=validator_list)
|
||||
|
||||
def isValidEmail(self, field_data, all_data):
|
||||
@ -907,10 +911,10 @@ class EmailField(TextField):
|
||||
|
||||
class URLField(TextField):
|
||||
"A convenience FormField for validating URLs"
|
||||
def __init__(self, field_name, length=50, maxlength=200, is_required=False, validator_list=None):
|
||||
def __init__(self, field_name, length=50, max_length=200, is_required=False, validator_list=None):
|
||||
if validator_list is None: validator_list = []
|
||||
validator_list = [self.isValidURL] + validator_list
|
||||
TextField.__init__(self, field_name, length=length, maxlength=maxlength,
|
||||
TextField.__init__(self, field_name, length=length, max_length=max_length,
|
||||
is_required=is_required, validator_list=validator_list)
|
||||
|
||||
def isValidURL(self, field_data, all_data):
|
||||
@ -920,10 +924,10 @@ class URLField(TextField):
|
||||
raise validators.CriticalValidationError, e.messages
|
||||
|
||||
class IPAddressField(TextField):
|
||||
def __init__(self, field_name, length=15, maxlength=15, is_required=False, validator_list=None):
|
||||
def __init__(self, field_name, length=15, max_length=15, is_required=False, validator_list=None):
|
||||
if validator_list is None: validator_list = []
|
||||
validator_list = [self.isValidIPAddress] + validator_list
|
||||
TextField.__init__(self, field_name, length=length, maxlength=maxlength,
|
||||
TextField.__init__(self, field_name, length=length, max_length=max_length,
|
||||
is_required=is_required, validator_list=validator_list)
|
||||
|
||||
def isValidIPAddress(self, field_data, all_data):
|
||||
@ -970,7 +974,7 @@ class PhoneNumberField(TextField):
|
||||
def __init__(self, field_name, is_required=False, validator_list=None):
|
||||
if validator_list is None: validator_list = []
|
||||
validator_list = [self.isValidPhone] + validator_list
|
||||
TextField.__init__(self, field_name, length=12, maxlength=12,
|
||||
TextField.__init__(self, field_name, length=12, max_length=12,
|
||||
is_required=is_required, validator_list=validator_list)
|
||||
|
||||
def isValidPhone(self, field_data, all_data):
|
||||
@ -984,7 +988,7 @@ class USStateField(TextField):
|
||||
def __init__(self, field_name, is_required=False, validator_list=None):
|
||||
if validator_list is None: validator_list = []
|
||||
validator_list = [self.isValidUSState] + validator_list
|
||||
TextField.__init__(self, field_name, length=2, maxlength=2,
|
||||
TextField.__init__(self, field_name, length=2, max_length=2,
|
||||
is_required=is_required, validator_list=validator_list)
|
||||
|
||||
def isValidUSState(self, field_data, all_data):
|
||||
@ -1001,10 +1005,10 @@ class USStateField(TextField):
|
||||
|
||||
class CommaSeparatedIntegerField(TextField):
|
||||
"A convenience FormField for validating comma-separated integer fields"
|
||||
def __init__(self, field_name, maxlength=None, is_required=False, validator_list=None):
|
||||
def __init__(self, field_name, max_length=None, is_required=False, validator_list=None):
|
||||
if validator_list is None: validator_list = []
|
||||
validator_list = [self.isCommaSeparatedIntegerList] + validator_list
|
||||
TextField.__init__(self, field_name, length=20, maxlength=maxlength,
|
||||
TextField.__init__(self, field_name, length=20, max_length=max_length,
|
||||
is_required=is_required, validator_list=validator_list)
|
||||
|
||||
def isCommaSeparatedIntegerList(self, field_data, all_data):
|
||||
|
@ -1,32 +1,62 @@
|
||||
# This module collects helper functions and classes that "span" multiple levels
|
||||
# of MVC. In other words, these functions/classes introduce controlled coupling
|
||||
# for convenience's sake.
|
||||
"""
|
||||
This module collects helper functions and classes that "span" multiple levels
|
||||
of MVC. In other words, these functions/classes introduce controlled coupling
|
||||
for convenience's sake.
|
||||
"""
|
||||
|
||||
from django.template import loader
|
||||
from django.http import HttpResponse, Http404
|
||||
from django.db.models.manager import Manager
|
||||
from django.db.models.query import QuerySet
|
||||
|
||||
def render_to_response(*args, **kwargs):
|
||||
"""
|
||||
Returns a HttpResponse whose content is filled with the result of calling
|
||||
django.template.loader.render_to_string() with the passed arguments.
|
||||
"""
|
||||
return HttpResponse(loader.render_to_string(*args, **kwargs))
|
||||
load_and_render = render_to_response # For backwards compatibility.
|
||||
|
||||
def get_object_or_404(klass, *args, **kwargs):
|
||||
if isinstance(klass, Manager):
|
||||
def _get_queryset(klass):
|
||||
"""
|
||||
Returns a QuerySet from a Model, Manager, or QuerySet. Created to make
|
||||
get_object_or_404 and get_list_or_404 more DRY.
|
||||
"""
|
||||
if isinstance(klass, QuerySet):
|
||||
return klass
|
||||
elif isinstance(klass, Manager):
|
||||
manager = klass
|
||||
klass = manager.model
|
||||
else:
|
||||
manager = klass._default_manager
|
||||
return manager.all()
|
||||
|
||||
def get_object_or_404(klass, *args, **kwargs):
|
||||
"""
|
||||
Uses get() to return an object, or raises a Http404 exception if the object
|
||||
does not exist.
|
||||
|
||||
klass may be a Model, Manager, or QuerySet object. All other passed
|
||||
arguments and keyword arguments are used in the get() query.
|
||||
|
||||
Note: Like with get(), an AssertionError will be raised if more than one
|
||||
object is found.
|
||||
"""
|
||||
queryset = _get_queryset(klass)
|
||||
try:
|
||||
return manager.get(*args, **kwargs)
|
||||
except klass.DoesNotExist:
|
||||
raise Http404('No %s matches the given query.' % klass._meta.object_name)
|
||||
return queryset.get(*args, **kwargs)
|
||||
except queryset.model.DoesNotExist:
|
||||
raise Http404('No %s matches the given query.' % queryset.model._meta.object_name)
|
||||
|
||||
def get_list_or_404(klass, *args, **kwargs):
|
||||
if isinstance(klass, Manager):
|
||||
manager = klass
|
||||
else:
|
||||
manager = klass._default_manager
|
||||
obj_list = list(manager.filter(*args, **kwargs))
|
||||
"""
|
||||
Uses filter() to return a list of objects, or raise a Http404 exception if
|
||||
the list is empty.
|
||||
|
||||
klass may be a Model, Manager, or QuerySet object. All other passed
|
||||
arguments and keyword arguments are used in the filter() query.
|
||||
"""
|
||||
queryset = _get_queryset(klass)
|
||||
obj_list = list(queryset.filter(*args, **kwargs))
|
||||
if not obj_list:
|
||||
raise Http404('No %s matches the given query.' % manager.model._meta.object_name)
|
||||
raise Http404('No %s matches the given query.' % queryset.model._meta.object_name)
|
||||
return obj_list
|
||||
|
@ -512,7 +512,7 @@ filter_raw_string = r"""
|
||||
)?
|
||||
)""" % {
|
||||
'str': r"""[^"\\]*(?:\\.[^"\\]*)*""",
|
||||
'var_chars': "A-Za-z0-9\_\." ,
|
||||
'var_chars': "\w\." ,
|
||||
'filter_sep': re.escape(FILTER_SEPARATOR),
|
||||
'arg_sep': re.escape(FILTER_ARGUMENT_SEPARATOR),
|
||||
'i18n_open' : re.escape("_("),
|
||||
@ -520,7 +520,7 @@ filter_raw_string = r"""
|
||||
}
|
||||
|
||||
filter_raw_string = filter_raw_string.replace("\n", "").replace(" ", "")
|
||||
filter_re = re.compile(filter_raw_string)
|
||||
filter_re = re.compile(filter_raw_string, re.UNICODE)
|
||||
|
||||
class FilterExpression(object):
|
||||
"""
|
||||
|
@ -556,7 +556,7 @@ def pprint(value):
|
||||
try:
|
||||
return pformat(value)
|
||||
except Exception, e:
|
||||
return u"Error in formatting:%s" % force_unicode(e)
|
||||
return u"Error in formatting: %s" % force_unicode(e, errors="replace")
|
||||
|
||||
# Syntax: register.filter(name of filter, callback)
|
||||
register.filter(add)
|
||||
|
@ -649,8 +649,8 @@ def do_if(parser, token):
|
||||
As you can see, the ``if`` tag can take an option ``{% else %}`` clause that
|
||||
will be displayed if the test fails.
|
||||
|
||||
``if`` tags may use ``or`` or ``not`` to test a number of variables or to
|
||||
negate a given variable::
|
||||
``if`` tags may use ``or``, ``and`` or ``not`` to test a number of
|
||||
variables or to negate a given variable::
|
||||
|
||||
{% if not athlete_list %}
|
||||
There are no athletes.
|
||||
@ -660,19 +660,32 @@ def do_if(parser, token):
|
||||
There are some athletes or some coaches.
|
||||
{% endif %}
|
||||
|
||||
{% if athlete_list and coach_list %}
|
||||
Both atheletes and coaches are available.
|
||||
{% endif %}
|
||||
|
||||
{% if not athlete_list or coach_list %}
|
||||
There are no athletes, or there are some coaches.
|
||||
{% endif %}
|
||||
|
||||
For simplicity, ``if`` tags do not allow ``and`` clauses. Use nested ``if``
|
||||
tags instead::
|
||||
|
||||
{% if athlete_list %}
|
||||
{% if coach_list %}
|
||||
Number of athletes: {{ athlete_list|count }}.
|
||||
Number of coaches: {{ coach_list|count }}.
|
||||
{% endif %}
|
||||
{% if athlete_list and not coach_list %}
|
||||
There are some athletes and absolutely no coaches.
|
||||
{% endif %}
|
||||
|
||||
``if`` tags do not allow ``and`` and ``or`` clauses with the same
|
||||
tag, because the order of logic would be ambigous. For example,
|
||||
this is invalid::
|
||||
|
||||
{% if athlete_list and coach_list or cheerleader_list %}
|
||||
|
||||
If you need to combine and and or to do advanced logic, just use
|
||||
nested if tags. For example:
|
||||
|
||||
{% if athlete_list %}
|
||||
{% if coach_list or cheerleader_list %}
|
||||
We have athletes, and either coaches or cheerleaders!
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
"""
|
||||
bits = token.contents.split()
|
||||
del bits[0]
|
||||
|
@ -1,9 +1,14 @@
|
||||
# Wrapper for loading templates from "template" directories in installed app packages.
|
||||
"""
|
||||
Wrapper for loading templates from "template" directories in INSTALLED_APPS
|
||||
packages.
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
from django.conf import settings
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
from django.template import TemplateDoesNotExist
|
||||
import os
|
||||
from django.utils._os import safe_join
|
||||
|
||||
# At compile time, cache the directories to search.
|
||||
app_template_dirs = []
|
||||
@ -28,8 +33,14 @@ for app in settings.INSTALLED_APPS:
|
||||
app_template_dirs = tuple(app_template_dirs)
|
||||
|
||||
def get_template_sources(template_name, template_dirs=None):
|
||||
for template_dir in app_template_dirs:
|
||||
yield os.path.join(template_dir, template_name)
|
||||
if not template_dirs:
|
||||
template_dirs = app_template_dirs
|
||||
for template_dir in template_dirs:
|
||||
try:
|
||||
yield safe_join(template_dir, template_name)
|
||||
except ValueError:
|
||||
# The joined path was located outside of template_dir.
|
||||
pass
|
||||
|
||||
def load_template_source(template_name, template_dirs=None):
|
||||
for filepath in get_template_sources(template_name, template_dirs):
|
||||
|
@ -1,14 +1,20 @@
|
||||
# Wrapper for loading templates from the filesystem.
|
||||
"""
|
||||
Wrapper for loading templates from the filesystem.
|
||||
"""
|
||||
|
||||
from django.conf import settings
|
||||
from django.template import TemplateDoesNotExist
|
||||
import os
|
||||
from django.utils._os import safe_join
|
||||
|
||||
def get_template_sources(template_name, template_dirs=None):
|
||||
if not template_dirs:
|
||||
template_dirs = settings.TEMPLATE_DIRS
|
||||
for template_dir in template_dirs:
|
||||
yield os.path.join(template_dir, template_name)
|
||||
try:
|
||||
yield safe_join(template_dir, template_name)
|
||||
except ValueError:
|
||||
# The joined path was located outside of template_dir.
|
||||
pass
|
||||
|
||||
def load_template_source(template_name, template_dirs=None):
|
||||
tried = []
|
||||
|
@ -195,7 +195,7 @@ class Client:
|
||||
'CONTENT_LENGTH': None,
|
||||
'CONTENT_TYPE': 'text/html; charset=utf-8',
|
||||
'PATH_INFO': path,
|
||||
'QUERY_STRING': urlencode(data),
|
||||
'QUERY_STRING': urlencode(data, doseq=True),
|
||||
'REQUEST_METHOD': 'GET',
|
||||
}
|
||||
r.update(extra)
|
||||
@ -225,10 +225,11 @@ class Client:
|
||||
"""Set the Client to appear as if it has sucessfully logged into a site.
|
||||
|
||||
Returns True if login is possible; False if the provided credentials
|
||||
are incorrect, or if the Sessions framework is not available.
|
||||
are incorrect, or the user is inactive, or if the sessions framework is
|
||||
not available.
|
||||
"""
|
||||
user = authenticate(**credentials)
|
||||
if user and 'django.contrib.sessions' in settings.INSTALLED_APPS:
|
||||
if user and user.is_active and 'django.contrib.sessions' in settings.INSTALLED_APPS:
|
||||
obj = Session.objects.get_new_session_object()
|
||||
|
||||
# Create a fake request to store login details
|
||||
|
@ -1,5 +1,6 @@
|
||||
import unittest
|
||||
from django.conf import settings
|
||||
from django.db.models import get_app, get_apps
|
||||
from django.test import _doctest as doctest
|
||||
from django.test.utils import setup_test_environment, teardown_test_environment
|
||||
from django.test.utils import create_test_db, destroy_test_db
|
||||
@ -10,34 +11,10 @@ TEST_MODULE = 'tests'
|
||||
|
||||
doctestOutputChecker = OutputChecker()
|
||||
|
||||
def build_suite(app_module):
|
||||
"Create a complete Django test suite for the provided application module"
|
||||
suite = unittest.TestSuite()
|
||||
|
||||
# Load unit and doctests in the models.py file
|
||||
suite.addTest(unittest.defaultTestLoader.loadTestsFromModule(app_module))
|
||||
try:
|
||||
suite.addTest(doctest.DocTestSuite(app_module,
|
||||
checker=doctestOutputChecker,
|
||||
runner=DocTestRunner))
|
||||
except ValueError:
|
||||
# No doc tests in models.py
|
||||
pass
|
||||
|
||||
# Check to see if a separate 'tests' module exists parallel to the
|
||||
# models module
|
||||
def get_tests(app_module):
|
||||
try:
|
||||
app_path = app_module.__name__.split('.')[:-1]
|
||||
test_module = __import__('.'.join(app_path + [TEST_MODULE]), {}, {}, TEST_MODULE)
|
||||
|
||||
suite.addTest(unittest.defaultTestLoader.loadTestsFromModule(test_module))
|
||||
try:
|
||||
suite.addTest(doctest.DocTestSuite(test_module,
|
||||
checker=doctestOutputChecker,
|
||||
runner=DocTestRunner))
|
||||
except ValueError:
|
||||
# No doc tests in tests.py
|
||||
pass
|
||||
except ImportError, e:
|
||||
# Couldn't import tests.py. Was it due to a missing file, or
|
||||
# due to an import error in a tests.py that actually exists?
|
||||
@ -47,7 +24,7 @@ def build_suite(app_module):
|
||||
mod = find_module(TEST_MODULE, [os.path.dirname(app_module.__file__)])
|
||||
except ImportError:
|
||||
# 'tests' module doesn't exist. Move on.
|
||||
pass
|
||||
test_module = None
|
||||
else:
|
||||
# The module exists, so there must be an import error in the
|
||||
# test module itself. We don't need the module; so if the
|
||||
@ -57,15 +34,87 @@ def build_suite(app_module):
|
||||
if mod[0]:
|
||||
mod[0].close()
|
||||
raise
|
||||
|
||||
return test_module
|
||||
|
||||
def build_suite(app_module):
|
||||
"Create a complete Django test suite for the provided application module"
|
||||
suite = unittest.TestSuite()
|
||||
|
||||
# Load unit and doctests in the models.py module. If module has
|
||||
# a suite() method, use it. Otherwise build the test suite ourselves.
|
||||
if hasattr(app_module, 'suite'):
|
||||
suite.addTest(app_module.suite())
|
||||
else:
|
||||
suite.addTest(unittest.defaultTestLoader.loadTestsFromModule(app_module))
|
||||
try:
|
||||
suite.addTest(doctest.DocTestSuite(app_module,
|
||||
checker=doctestOutputChecker,
|
||||
runner=DocTestRunner))
|
||||
except ValueError:
|
||||
# No doc tests in models.py
|
||||
pass
|
||||
|
||||
# Check to see if a separate 'tests' module exists parallel to the
|
||||
# models module
|
||||
test_module = get_tests(app_module)
|
||||
if test_module:
|
||||
# Load unit and doctests in the tests.py module. If module has
|
||||
# a suite() method, use it. Otherwise build the test suite ourselves.
|
||||
if hasattr(test_module, 'suite'):
|
||||
suite.addTest(test_module.suite())
|
||||
else:
|
||||
suite.addTest(unittest.defaultTestLoader.loadTestsFromModule(test_module))
|
||||
try:
|
||||
suite.addTest(doctest.DocTestSuite(test_module,
|
||||
checker=doctestOutputChecker,
|
||||
runner=DocTestRunner))
|
||||
except ValueError:
|
||||
# No doc tests in tests.py
|
||||
pass
|
||||
return suite
|
||||
|
||||
def run_tests(module_list, verbosity=1, extra_tests=[]):
|
||||
def build_test(label):
|
||||
"""Construct a test case a test with the specified label. Label should
|
||||
be of the form model.TestClass or model.TestClass.test_method. Returns
|
||||
an instantiated test or test suite corresponding to the label provided.
|
||||
|
||||
"""
|
||||
Run the unit tests for all the modules in the provided list.
|
||||
This testrunner will search each of the modules in the provided list,
|
||||
looking for doctests and unittests in models.py or tests.py within
|
||||
the module. A list of 'extra' tests may also be provided; these tests
|
||||
parts = label.split('.')
|
||||
if len(parts) < 2 or len(parts) > 3:
|
||||
raise ValueError("Test label '%s' should be of the form app.TestCase or app.TestCase.test_method" % label)
|
||||
|
||||
app_module = get_app(parts[0])
|
||||
TestClass = getattr(app_module, parts[1], None)
|
||||
|
||||
# Couldn't find the test class in models.py; look in tests.py
|
||||
if TestClass is None:
|
||||
test_module = get_tests(app_module)
|
||||
if test_module:
|
||||
TestClass = getattr(test_module, parts[1], None)
|
||||
|
||||
if len(parts) == 2: # label is app.TestClass
|
||||
try:
|
||||
return unittest.TestLoader().loadTestsFromTestCase(TestClass)
|
||||
except TypeError:
|
||||
raise ValueError("Test label '%s' does not refer to a test class" % label)
|
||||
else: # label is app.TestClass.test_method
|
||||
return TestClass(parts[2])
|
||||
|
||||
def run_tests(test_labels, verbosity=1, interactive=True, extra_tests=[]):
|
||||
"""
|
||||
Run the unit tests for all the test labels in the provided list.
|
||||
Labels must be of the form:
|
||||
- app.TestClass.test_method
|
||||
Run a single specific test method
|
||||
- app.TestClass
|
||||
Run all the test methods in a given class
|
||||
- app
|
||||
Search for doctests and unittests in the named application.
|
||||
|
||||
When looking for tests, the test runner will look in the models and
|
||||
tests modules for the application.
|
||||
|
||||
A list of 'extra' tests may also be provided; these tests
|
||||
will be added to the test suite.
|
||||
|
||||
Returns the number of tests that failed.
|
||||
@ -74,15 +123,23 @@ def run_tests(module_list, verbosity=1, extra_tests=[]):
|
||||
|
||||
settings.DEBUG = False
|
||||
suite = unittest.TestSuite()
|
||||
|
||||
for module in module_list:
|
||||
suite.addTest(build_suite(module))
|
||||
|
||||
if test_labels:
|
||||
for label in test_labels:
|
||||
if '.' in label:
|
||||
suite.addTest(build_test(label))
|
||||
else:
|
||||
app = get_app(label)
|
||||
suite.addTest(build_suite(app))
|
||||
else:
|
||||
for app in get_apps():
|
||||
suite.addTest(build_suite(app))
|
||||
|
||||
for test in extra_tests:
|
||||
suite.addTest(test)
|
||||
|
||||
old_name = settings.DATABASE_NAME
|
||||
create_test_db(verbosity)
|
||||
create_test_db(verbosity, autoclobber=not interactive)
|
||||
result = unittest.TextTestRunner(verbosity=verbosity).run(suite)
|
||||
destroy_test_db(old_name, verbosity)
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user