mirror of
https://github.com/django/django.git
synced 2025-07-05 18:29:11 +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/>
|
Ned Batchelder <http://www.nedbatchelder.com/>
|
||||||
Shannon -jj Behrens <http://jjinux.blogspot.com/>
|
Shannon -jj Behrens <http://jjinux.blogspot.com/>
|
||||||
Esdras Beleza <linux@esdrasbeleza.com>
|
Esdras Beleza <linux@esdrasbeleza.com>
|
||||||
|
Chris Bennett <chrisrbennett@yahoo.com>
|
||||||
James Bennett
|
James Bennett
|
||||||
Ben <afternoon@uk2.net>
|
Ben <afternoon@uk2.net>
|
||||||
Paul Bissex <http://e-scribe.com/>
|
Paul Bissex <http://e-scribe.com/>
|
||||||
Simon Blanchard
|
Simon Blanchard
|
||||||
|
Matt Boersma <ogghead@gmail.com>
|
||||||
boobsd@gmail.com
|
boobsd@gmail.com
|
||||||
Andrew Brehaut <http://brehaut.net/blog>
|
Andrew Brehaut <http://brehaut.net/blog>
|
||||||
brut.alll@gmail.com
|
brut.alll@gmail.com
|
||||||
@ -94,10 +96,12 @@ answer newbie questions, and generally made Django that much better:
|
|||||||
Maximillian Dornseif <md@hudora.de>
|
Maximillian Dornseif <md@hudora.de>
|
||||||
Jeremy Dunck <http://dunck.us/>
|
Jeremy Dunck <http://dunck.us/>
|
||||||
Andrew Durdin <adurdin@gmail.com>
|
Andrew Durdin <adurdin@gmail.com>
|
||||||
|
dusk@woofle.net
|
||||||
Andy Dustman <farcepest@gmail.com>
|
Andy Dustman <farcepest@gmail.com>
|
||||||
Clint Ecker
|
Clint Ecker
|
||||||
enlight
|
enlight
|
||||||
Enrico <rico.bl@gmail.com>
|
Enrico <rico.bl@gmail.com>
|
||||||
|
A. Murat Eren <meren@pardus.org.tr>
|
||||||
Ludvig Ericson <ludvig.ericson@gmail.com>
|
Ludvig Ericson <ludvig.ericson@gmail.com>
|
||||||
Dirk Eschler <dirk.eschler@gmx.net>
|
Dirk Eschler <dirk.eschler@gmx.net>
|
||||||
Marc Fargas <telenieko@telenieko.com>
|
Marc Fargas <telenieko@telenieko.com>
|
||||||
@ -114,7 +118,7 @@ answer newbie questions, and generally made Django that much better:
|
|||||||
glin@seznam.cz
|
glin@seznam.cz
|
||||||
martin.glueck@gmail.com
|
martin.glueck@gmail.com
|
||||||
GomoX <gomo@datafull.com>
|
GomoX <gomo@datafull.com>
|
||||||
Mario Gonzalez <gonzalemario @t gmail.com>
|
Mario Gonzalez <gonzalemario@gmail.com>
|
||||||
Simon Greenhill <dev@simon.net.nz>
|
Simon Greenhill <dev@simon.net.nz>
|
||||||
Owen Griffiths
|
Owen Griffiths
|
||||||
Espen Grindhaug <http://grindhaug.org/>
|
Espen Grindhaug <http://grindhaug.org/>
|
||||||
@ -141,7 +145,8 @@ answer newbie questions, and generally made Django that much better:
|
|||||||
junzhang.jn@gmail.com
|
junzhang.jn@gmail.com
|
||||||
Antti Kaihola <http://akaihola.blogspot.com/>
|
Antti Kaihola <http://akaihola.blogspot.com/>
|
||||||
Ben Dean Kawamura <ben.dean.kawamura@gmail.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/>
|
Garth Kidd <http://www.deadlybloodyserious.com/>
|
||||||
kilian <kilian.cavalotti@lip6.fr>
|
kilian <kilian.cavalotti@lip6.fr>
|
||||||
Sune Kirkeby <http://ibofobi.dk/>
|
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>
|
Martin Kosír <martin@martinkosir.net>
|
||||||
Meir Kriheli <http://mksoft.co.il/>
|
Meir Kriheli <http://mksoft.co.il/>
|
||||||
Bruce Kroeze <http://coderseye.com/>
|
Bruce Kroeze <http://coderseye.com/>
|
||||||
|
krzysiek.pawlik@silvermedia.pl
|
||||||
Joseph Kocherhans
|
Joseph Kocherhans
|
||||||
konrad@gwu.edu
|
konrad@gwu.edu
|
||||||
kurtiss@meetro.com
|
kurtiss@meetro.com
|
||||||
@ -167,13 +173,14 @@ answer newbie questions, and generally made Django that much better:
|
|||||||
lerouxb@gmail.com
|
lerouxb@gmail.com
|
||||||
Waylan Limberg <waylan@gmail.com>
|
Waylan Limberg <waylan@gmail.com>
|
||||||
limodou
|
limodou
|
||||||
|
Philip Lindborg <philip.lindborg@gmail.com>
|
||||||
Matt McClanahan <http://mmcc.cx/>
|
Matt McClanahan <http://mmcc.cx/>
|
||||||
Martin Maney <http://www.chipy.org/Martin_Maney>
|
Martin Maney <http://www.chipy.org/Martin_Maney>
|
||||||
masonsimon+django@gmail.com
|
masonsimon+django@gmail.com
|
||||||
Manuzhai
|
Manuzhai
|
||||||
Petar Marić <http://www.petarmaric.com/>
|
Petar Marić <http://www.petarmaric.com/>
|
||||||
Nuno Mariz <nmariz@gmail.com>
|
Nuno Mariz <nmariz@gmail.com>
|
||||||
marijn@metronomo.cl
|
Marijn Vriens <marijn@metronomo.cl>
|
||||||
mark@junklight.com
|
mark@junklight.com
|
||||||
Yasushi Masuda <whosaysni@gmail.com>
|
Yasushi Masuda <whosaysni@gmail.com>
|
||||||
mattycakes@gmail.com
|
mattycakes@gmail.com
|
||||||
@ -183,6 +190,7 @@ answer newbie questions, and generally made Django that much better:
|
|||||||
mikko@sorl.net
|
mikko@sorl.net
|
||||||
mitakummaa@gmail.com
|
mitakummaa@gmail.com
|
||||||
mmarshall
|
mmarshall
|
||||||
|
Andreas Mock <andreas.mock@web.de>
|
||||||
Reza Mohammadi <reza@zeerak.ir>
|
Reza Mohammadi <reza@zeerak.ir>
|
||||||
Eric Moritz <http://eric.themoritzfamily.com/>
|
Eric Moritz <http://eric.themoritzfamily.com/>
|
||||||
mrmachine <real.human@mrmachine.net>
|
mrmachine <real.human@mrmachine.net>
|
||||||
@ -207,6 +215,7 @@ answer newbie questions, and generally made Django that much better:
|
|||||||
plisk
|
plisk
|
||||||
Daniel Poelzleithner <http://poelzi.org/>
|
Daniel Poelzleithner <http://poelzi.org/>
|
||||||
polpak@yahoo.com
|
polpak@yahoo.com
|
||||||
|
Johann Queuniet <johann.queuniet@adh.naellia.eu>
|
||||||
J. Rademaker
|
J. Rademaker
|
||||||
Michael Radziej <mir@noris.de>
|
Michael Radziej <mir@noris.de>
|
||||||
Ramiro Morales <rm0@gmx.net>
|
Ramiro Morales <rm0@gmx.net>
|
||||||
@ -216,12 +225,14 @@ answer newbie questions, and generally made Django that much better:
|
|||||||
rhettg@gmail.com
|
rhettg@gmail.com
|
||||||
Henrique Romano <onaiort@gmail.com>
|
Henrique Romano <onaiort@gmail.com>
|
||||||
Armin Ronacher
|
Armin Ronacher
|
||||||
|
Brian Rosner <brosner@gmail.com>
|
||||||
Oliver Rutherfurd <http://rutherfurd.net/>
|
Oliver Rutherfurd <http://rutherfurd.net/>
|
||||||
Ivan Sagalaev (Maniac) <http://www.softwaremaniacs.org/>
|
Ivan Sagalaev (Maniac) <http://www.softwaremaniacs.org/>
|
||||||
Vinay Sajip <vinay_sajip@yahoo.co.uk>
|
Vinay Sajip <vinay_sajip@yahoo.co.uk>
|
||||||
David Schein
|
David Schein
|
||||||
scott@staplefish.com
|
scott@staplefish.com
|
||||||
serbaut@gmail.com
|
serbaut@gmail.com
|
||||||
|
John Shaffer <jshaffer2112@gmail.com>
|
||||||
Pete Shinners <pete@shinners.org>
|
Pete Shinners <pete@shinners.org>
|
||||||
Jozko Skrablin <jozko.skrablin@gmail.com>
|
Jozko Skrablin <jozko.skrablin@gmail.com>
|
||||||
SmileyChris <smileychris@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>
|
Vasiliy Stavenko <stavenko@gmail.com>
|
||||||
Thomas Steinacher <http://www.eggdrop.ch/>
|
Thomas Steinacher <http://www.eggdrop.ch/>
|
||||||
nowell strite
|
nowell strite
|
||||||
|
Sundance
|
||||||
|
SuperJared
|
||||||
Radek Švarz <http://www.svarz.cz/translate/>
|
Radek Švarz <http://www.svarz.cz/translate/>
|
||||||
Swaroop C H <http://www.swaroopch.info>
|
Swaroop C H <http://www.swaroopch.info>
|
||||||
Aaron Swartz <http://www.aaronsw.com/>
|
Aaron Swartz <http://www.aaronsw.com/>
|
||||||
|
@ -9,6 +9,7 @@ import re
|
|||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import getopt
|
import getopt
|
||||||
|
from itertools import dropwhile
|
||||||
|
|
||||||
pythonize_re = re.compile(r'\n\s*//')
|
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))
|
open(os.path.join(dirpath, '%s.py' % file), "wb").write(templatize(src))
|
||||||
thefile = '%s.py' % file
|
thefile = '%s.py' % file
|
||||||
if verbose: sys.stdout.write('processing file %s in %s\n' % (file, dirpath))
|
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"' % (
|
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"' % (
|
||||||
os.path.exists(potfile) and '--omit-header' or '', domain, os.path.join(dirpath, thefile))
|
domain, os.path.join(dirpath, thefile))
|
||||||
(stdin, stdout, stderr) = os.popen3(cmd, 'b')
|
(stdin, stdout, stderr) = os.popen3(cmd, 'b')
|
||||||
msgs = stdout.read()
|
msgs = stdout.read()
|
||||||
errors = stderr.read()
|
errors = stderr.read()
|
||||||
@ -116,13 +117,18 @@ def make_messages():
|
|||||||
old = '#: '+os.path.join(dirpath, thefile)[2:]
|
old = '#: '+os.path.join(dirpath, thefile)[2:]
|
||||||
new = '#: '+os.path.join(dirpath, file)[2:]
|
new = '#: '+os.path.join(dirpath, file)[2:]
|
||||||
msgs = msgs.replace(old, new)
|
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:
|
if msgs:
|
||||||
open(potfile, 'ab').write(msgs)
|
open(potfile, 'ab').write(msgs)
|
||||||
if thefile != file:
|
if thefile != file:
|
||||||
os.unlink(os.path.join(dirpath, thefile))
|
os.unlink(os.path.join(dirpath, thefile))
|
||||||
|
|
||||||
if os.path.exists(potfile):
|
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()
|
msgs = stdout.read()
|
||||||
errors = stderr.read()
|
errors = stderr.read()
|
||||||
if errors:
|
if errors:
|
||||||
|
@ -37,6 +37,8 @@ class LazySettings(object):
|
|||||||
# __setattr__(), which would be an infinite loop.
|
# __setattr__(), which would be an infinite loop.
|
||||||
self.__dict__['_target'] = value
|
self.__dict__['_target'] = value
|
||||||
else:
|
else:
|
||||||
|
if self._target is None:
|
||||||
|
self._import_settings()
|
||||||
setattr(self._target, name, value)
|
setattr(self._target, name, value)
|
||||||
|
|
||||||
def _import_settings(self):
|
def _import_settings(self):
|
||||||
|
@ -30,7 +30,6 @@ TIME_ZONE = 'America/Chicago'
|
|||||||
|
|
||||||
# Language code for this installation. All choices can be found here:
|
# Language code for this installation. All choices can be found here:
|
||||||
# http://www.w3.org/TR/REC-html40/struct/dirlang.html#langcodes
|
# http://www.w3.org/TR/REC-html40/struct/dirlang.html#langcodes
|
||||||
# http://blogs.law.harvard.edu/tech/stories/storyReader$15
|
|
||||||
LANGUAGE_CODE = 'en-us'
|
LANGUAGE_CODE = 'en-us'
|
||||||
|
|
||||||
# Languages we provide translations for, out of the box. The language name
|
# 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"
|
"PO-Revision-Date: 2005-12-04 13:21+0100\n"
|
||||||
"Last-Translator: Dirk Eschler <dirk.eschler@gmx.net>\n"
|
"Last-Translator: Dirk Eschler <dirk.eschler@gmx.net>\n"
|
||||||
"MIME-Version: 1.0\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"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
|
||||||
#: contrib/admin/media/js/SelectFilter2.js:33
|
#: contrib/admin/media/js/SelectFilter2.js:33
|
||||||
#, perl-format
|
#, perl-format
|
||||||
msgid "Available %s"
|
msgid "Available %s"
|
||||||
msgstr "Verfügbare %s"
|
msgstr "Verfügbare %s"
|
||||||
|
|
||||||
#: contrib/admin/media/js/SelectFilter2.js:41
|
#: contrib/admin/media/js/SelectFilter2.js:41
|
||||||
msgid "Choose all"
|
msgid "Choose all"
|
||||||
msgstr "Alles auswählen"
|
msgstr "Alles auswählen"
|
||||||
|
|
||||||
#: contrib/admin/media/js/SelectFilter2.js:46
|
#: contrib/admin/media/js/SelectFilter2.js:46
|
||||||
msgid "Add"
|
msgid "Add"
|
||||||
msgstr "Hinzufügen"
|
msgstr "Hinzufügen"
|
||||||
|
|
||||||
#: contrib/admin/media/js/SelectFilter2.js:48
|
#: contrib/admin/media/js/SelectFilter2.js:48
|
||||||
msgid "Remove"
|
msgid "Remove"
|
||||||
@ -34,15 +34,15 @@ msgstr "Entfernen"
|
|||||||
#: contrib/admin/media/js/SelectFilter2.js:53
|
#: contrib/admin/media/js/SelectFilter2.js:53
|
||||||
#, perl-format
|
#, perl-format
|
||||||
msgid "Chosen %s"
|
msgid "Chosen %s"
|
||||||
msgstr "Ausgewählte %s"
|
msgstr "Ausgewählte %s"
|
||||||
|
|
||||||
#: contrib/admin/media/js/SelectFilter2.js:54
|
#: contrib/admin/media/js/SelectFilter2.js:54
|
||||||
msgid "Select your choice(s) and click "
|
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
|
#: contrib/admin/media/js/SelectFilter2.js:59
|
||||||
msgid "Clear all"
|
msgid "Clear all"
|
||||||
msgstr "Alles abwählen"
|
msgstr "Alles abwählen"
|
||||||
|
|
||||||
#: contrib/admin/media/js/dateparse.js:26
|
#: contrib/admin/media/js/dateparse.js:26
|
||||||
#: contrib/admin/media/js/calendar.js:24
|
#: contrib/admin/media/js/calendar.js:24
|
||||||
@ -50,7 +50,7 @@ msgid ""
|
|||||||
"January February March April May June July August September October November "
|
"January February March April May June July August September October November "
|
||||||
"December"
|
"December"
|
||||||
msgstr ""
|
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"
|
"Dezember"
|
||||||
|
|
||||||
#: contrib/admin/media/js/dateparse.js:27
|
#: 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.
|
# Spanish translation for the django-admin JS files.
|
||||||
# Copyright (C)
|
# Copyright (C)
|
||||||
# This file is distributed under the same license as the PACKAGE package.
|
# This file is distributed under the same license as the PACKAGE package.
|
||||||
# Jorge Gajon <gajon@gajon.org>, 2005.
|
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: Django JavaScript 1.0\n"
|
"Project-Id-Version: Django JavaScript 1.0\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2005-12-09 11:51+0100\n"
|
"POT-Creation-Date: 2007-07-14 13:47-0500\n"
|
||||||
"PO-Revision-Date: 2005-12-06 21:32+0100\n"
|
"PO-Revision-Date: 2007-07-14 13:41-0500\n"
|
||||||
"Last-Translator: Jorge Gajon <gajon@gajon.org>\n"
|
"Last-Translator: Jorge Gajon <gajon@gajon.org>\n"
|
||||||
"MIME-Version: 1.0\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"
|
"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
|
#: contrib/admin/media/js/SelectFilter2.js:33
|
||||||
#, perl-format
|
#, perl-format
|
||||||
msgid "Available %s"
|
msgid "Available %s"
|
||||||
msgstr "%s Disponibles"
|
msgstr "%s Disponibles"
|
||||||
|
|
||||||
#: contrib/admin/media/js/SelectFilter2.js:41
|
#: contrib/admin/media/js/SelectFilter2.js:41
|
||||||
#, fuzzy
|
|
||||||
msgid "Choose all"
|
msgid "Choose all"
|
||||||
msgstr "Selecciona todos"
|
msgstr "Selecciona todos"
|
||||||
|
|
||||||
@ -45,66 +60,58 @@ msgstr "Haz tus elecciones y da click en "
|
|||||||
msgid "Clear all"
|
msgid "Clear all"
|
||||||
msgstr "Elimina todos"
|
msgstr "Elimina todos"
|
||||||
|
|
||||||
#: contrib/admin/media/js/dateparse.js:26
|
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:47
|
||||||
#: contrib/admin/media/js/calendar.js:24
|
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:81
|
||||||
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
|
|
||||||
msgid "Now"
|
msgid "Now"
|
||||||
msgstr "Ahora"
|
msgstr "Ahora"
|
||||||
|
|
||||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:48
|
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:51
|
||||||
msgid "Clock"
|
msgid "Clock"
|
||||||
msgstr "Reloj"
|
msgstr "Reloj"
|
||||||
|
|
||||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:77
|
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:78
|
||||||
msgid "Choose a time"
|
msgid "Choose a time"
|
||||||
msgstr "Elige una hora"
|
msgstr "Elige una hora"
|
||||||
|
|
||||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:81
|
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:82
|
||||||
msgid "Midnight"
|
msgid "Midnight"
|
||||||
msgstr "Medianoche"
|
msgstr "Medianoche"
|
||||||
|
|
||||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:82
|
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:83
|
||||||
msgid "6 a.m."
|
msgid "6 a.m."
|
||||||
msgstr "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"
|
msgid "Noon"
|
||||||
msgstr "Mediodía"
|
msgstr "Mediodía"
|
||||||
|
|
||||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:87
|
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:88
|
||||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:168
|
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:183
|
||||||
msgid "Cancel"
|
msgid "Cancel"
|
||||||
msgstr "Cancelar"
|
msgstr "Cancelar"
|
||||||
|
|
||||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:111
|
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:128
|
||||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:162
|
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:177
|
||||||
msgid "Today"
|
msgid "Today"
|
||||||
msgstr "Hoy"
|
msgstr "Hoy"
|
||||||
|
|
||||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:114
|
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:132
|
||||||
msgid "Calendar"
|
msgid "Calendar"
|
||||||
msgstr "Calendario"
|
msgstr "Calendario"
|
||||||
|
|
||||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:160
|
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:175
|
||||||
msgid "Yesterday"
|
msgid "Yesterday"
|
||||||
msgstr "Ayer"
|
msgstr "Ayer"
|
||||||
|
|
||||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:164
|
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:179
|
||||||
msgid "Tomorrow"
|
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
|
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||||
# Spanish translation work by Jorge Gajon.
|
# This file is distributed under the same license as the PACKAGE package.
|
||||||
# This file is distributed under the same license as the Django package.
|
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR
|
||||||
# Copyright (C) Ramiro Morales <rm0@gmx.net>, 2006,2007.
|
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: Django JavaScript 1.0\n"
|
"Project-Id-Version: Django Javascript 1.0\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2007-02-25 17:48-0300\n"
|
"POT-Creation-Date: 2007-07-14 13:45-0300\n"
|
||||||
"PO-Revision-Date: 2007-02-25 17:55-0300\n"
|
"PO-Revision-Date: 2007-07-14 14:36-0300\n"
|
||||||
"Last-Translator: Ramiro Morales <rm0@gmx.net>\n"
|
"Last-Translator: Ramiro Morales <rm0@gmx.net>\n"
|
||||||
|
"Language-Team: Django-I18N <django-i18n@googlegroups.com>\n"
|
||||||
"MIME-Version: 1.0\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"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
|
||||||
#: contrib/admin/media/js/SelectFilter2.js:33
|
#: contrib/admin/media/js/SelectFilter2.js:33
|
||||||
@ -55,7 +55,7 @@ msgstr ""
|
|||||||
|
|
||||||
#: contrib/admin/media/js/dateparse.js:33
|
#: contrib/admin/media/js/dateparse.js:33
|
||||||
msgid "Sunday Monday Tuesday Wednesday Thursday Friday Saturday"
|
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
|
#: contrib/admin/media/js/calendar.js:25
|
||||||
msgid "S M T W T F S"
|
msgid "S M T W T F S"
|
||||||
@ -93,7 +93,7 @@ msgstr "6 a.m."
|
|||||||
|
|
||||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:84
|
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:84
|
||||||
msgid "Noon"
|
msgid "Noon"
|
||||||
msgstr "Mediodía"
|
msgstr "Mediodía"
|
||||||
|
|
||||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:88
|
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:88
|
||||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:183
|
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:183
|
||||||
@ -115,4 +115,4 @@ msgstr "Ayer"
|
|||||||
|
|
||||||
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:179
|
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:179
|
||||||
msgid "Tomorrow"
|
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.
|
# 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.
|
# 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 ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@ -9,10 +9,10 @@ msgstr ""
|
|||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2005-12-24 16:39+0100\n"
|
"POT-Creation-Date: 2005-12-24 16:39+0100\n"
|
||||||
"PO-Revision-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"
|
"Language-Team: French <fr@li.org>\n"
|
||||||
"MIME-Version: 1.0\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"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
|
||||||
#: contrib/admin/media/js/calendar.js:24
|
#: contrib/admin/media/js/calendar.js:24
|
||||||
@ -21,8 +21,8 @@ msgid ""
|
|||||||
"January February March April May June July August September October November "
|
"January February March April May June July August September October November "
|
||||||
"December"
|
"December"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Janvier Février Mars Avril Mai Juin Juillet Août Septembre Octobre Novembre "
|
"Janvier Février Mars Avril Mai Juin Juillet Août Septembre Octobre Novembre "
|
||||||
"Décembre"
|
"Décembre"
|
||||||
|
|
||||||
#: contrib/admin/media/js/calendar.js:25
|
#: contrib/admin/media/js/calendar.js:25
|
||||||
msgid "S M T W T F S"
|
msgid "S M T W T F S"
|
||||||
@ -56,7 +56,7 @@ msgstr "Choisi %s"
|
|||||||
|
|
||||||
#: contrib/admin/media/js/SelectFilter2.js:54
|
#: contrib/admin/media/js/SelectFilter2.js:54
|
||||||
msgid "Select your choice(s) and click "
|
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
|
#: contrib/admin/media/js/SelectFilter2.js:59
|
||||||
msgid "Clear all"
|
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:
|
# Language code for this installation. All choices can be found here:
|
||||||
# http://www.w3.org/TR/REC-html40/struct/dirlang.html#langcodes
|
# http://www.w3.org/TR/REC-html40/struct/dirlang.html#langcodes
|
||||||
# http://blogs.law.harvard.edu/tech/stories/storyReader$15
|
|
||||||
LANGUAGE_CODE = 'en-us'
|
LANGUAGE_CODE = 'en-us'
|
||||||
|
|
||||||
SITE_ID = 1
|
SITE_ID = 1
|
||||||
|
@ -31,10 +31,11 @@ function showAddAnotherPopup(triggeringLink) {
|
|||||||
var name = triggeringLink.id.replace(/^add_/, '');
|
var name = triggeringLink.id.replace(/^add_/, '');
|
||||||
name = name.replace(/\./g, '___');
|
name = name.replace(/\./g, '___');
|
||||||
href = triggeringLink.href
|
href = triggeringLink.href
|
||||||
if (href.indexOf('?') == -1)
|
if (href.indexOf('?') == -1) {
|
||||||
href += '?_popup=1';
|
href += '?_popup=1';
|
||||||
else
|
} else {
|
||||||
href += '&_popup=1';
|
href += '&_popup=1';
|
||||||
|
}
|
||||||
var win = window.open(href, name, 'height=500,width=800,resizable=yes,scrollbars=yes');
|
var win = window.open(href, name, 'height=500,width=800,resizable=yes,scrollbars=yes');
|
||||||
win.focus();
|
win.focus();
|
||||||
return false;
|
return false;
|
||||||
|
@ -2,12 +2,12 @@ var LATIN_MAP = {
|
|||||||
'À': 'A', 'Á': 'A', 'Â': 'A', 'Ã': 'A', 'Ä': 'A', 'Å': 'A', 'Æ': 'AE', 'Ç':
|
'À': 'A', 'Á': 'A', 'Â': 'A', 'Ã': 'A', 'Ä': 'A', 'Å': 'A', 'Æ': 'AE', 'Ç':
|
||||||
'C', 'È': 'E', 'É': 'E', 'Ê': 'E', 'Ë': 'E', 'Ì': 'I', 'Í': 'I', 'Î': 'I',
|
'C', 'È': 'E', 'É': 'E', 'Ê': 'E', 'Ë': 'E', 'Ì': 'I', 'Í': 'I', 'Î': 'I',
|
||||||
'Ï': 'I', 'Ð': 'D', 'Ñ': 'N', 'Ò': 'O', 'Ó': 'O', 'Ô': 'O', 'Õ': 'O', 'Ö':
|
'Ï': 'I', 'Ð': 'D', 'Ñ': 'N', 'Ò': 'O', 'Ó': 'O', 'Ô': 'O', 'Õ': 'O', 'Ö':
|
||||||
'O', 'Ø': 'O', 'Ù': 'U', 'Ú': 'U', 'Û': 'U', 'Ü': 'U', 'Ý': 'Y', 'Þ': 'TH',
|
'O', 'Ő': 'O', 'Ø': 'O', 'Ù': 'U', 'Ú': 'U', 'Û': 'U', 'Ü': 'U', 'Ű': 'U',
|
||||||
'ß': 'ss', 'à':'a', 'á':'a', 'â': 'a', 'ã': 'a', 'ä': 'a', 'å': 'a', 'æ':
|
'Ý': 'Y', 'Þ': 'TH', 'ß': 'ss', 'à':'a', 'á':'a', 'â': 'a', 'ã': 'a', 'ä':
|
||||||
'ae', 'ç': 'c', 'è': 'e', 'é': 'e', 'ê': 'e', 'ë': 'e', 'ì': 'i', 'í': 'i',
|
'a', 'å': 'a', 'æ': 'ae', 'ç': 'c', 'è': 'e', 'é': 'e', 'ê': 'e', 'ë': 'e',
|
||||||
'î': 'i', 'ï': 'i', 'ð': 'o', 'ñ': 'n', 'ò': 'o', 'ó': 'o', 'ô': 'o', 'õ':
|
'ì': 'i', 'í': 'i', 'î': 'i', 'ï': 'i', 'ð': 'o', 'ñ': 'n', 'ò': 'o', 'ó':
|
||||||
'o', 'ö': 'o', 'ø': 'o', 'ù': 'u', 'ú': 'u', 'û': 'u', 'ü': 'u', 'ý': 'y',
|
'o', 'ô': 'o', 'õ': 'o', 'ö': 'o', 'ő': 'o', 'ø': 'o', 'ù': 'u', 'ú': 'u',
|
||||||
'þ': 'th', 'ÿ': 'y'
|
'û': 'u', 'ü': 'u', 'ű': 'u', 'ý': 'y', 'þ': 'th', 'ÿ': 'y'
|
||||||
}
|
}
|
||||||
var LATIN_SYMBOLS_MAP = {
|
var LATIN_SYMBOLS_MAP = {
|
||||||
'©':'(c)'
|
'©':'(c)'
|
||||||
|
@ -18,7 +18,7 @@ class LogEntry(models.Model):
|
|||||||
user = models.ForeignKey(User)
|
user = models.ForeignKey(User)
|
||||||
content_type = models.ForeignKey(ContentType, blank=True, null=True)
|
content_type = models.ForeignKey(ContentType, blank=True, null=True)
|
||||||
object_id = models.TextField(_('object id'), 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'))
|
action_flag = models.PositiveSmallIntegerField(_('action flag'))
|
||||||
change_message = models.TextField(_('change message'), blank=True)
|
change_message = models.TextField(_('change message'), blank=True)
|
||||||
objects = LogEntryManager()
|
objects = LogEntryManager()
|
||||||
|
@ -190,9 +190,11 @@ def items_for_result(cl, result):
|
|||||||
table_tag = {True:'th', False:'td'}[first]
|
table_tag = {True:'th', False:'td'}[first]
|
||||||
first = False
|
first = False
|
||||||
url = cl.url_for_result(result)
|
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>' % \
|
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:
|
else:
|
||||||
yield (u'<td%s>%s</td>' % (row_class, result_repr))
|
yield (u'<td%s>%s</td>' % (row_class, result_repr))
|
||||||
|
|
||||||
|
@ -362,7 +362,7 @@ class ChangeList(object):
|
|||||||
try:
|
try:
|
||||||
attr = getattr(self.model, field_name)
|
attr = getattr(self.model, field_name)
|
||||||
order_field = attr.admin_order_field
|
order_field = attr.admin_order_field
|
||||||
except IndexError:
|
except AttributeError:
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
if not isinstance(f.rel, models.ManyToOneRel) or not f.null:
|
if not isinstance(f.rel, models.ManyToOneRel) or not f.null:
|
||||||
|
@ -12,6 +12,8 @@ def load_backend(path):
|
|||||||
mod = __import__(module, {}, {}, [attr])
|
mod = __import__(module, {}, {}, [attr])
|
||||||
except ImportError, e:
|
except ImportError, e:
|
||||||
raise ImproperlyConfigured, 'Error importing authentication backend %s: "%s"' % (module, 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:
|
try:
|
||||||
cls = getattr(mod, attr)
|
cls = getattr(mod, attr)
|
||||||
except AttributeError:
|
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."
|
"A form that creates a user, with no privileges, from the given username and password."
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.fields = (
|
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]),
|
validator_list=[validators.isAlphaNumeric, self.isValidUsername]),
|
||||||
oldforms.PasswordField(field_name='password1', 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, maxlength=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."))]),
|
validator_list=[validators.AlwaysMatchesOtherField('password1', _("The two password fields didn't match."))]),
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -42,9 +42,9 @@ class AuthenticationForm(oldforms.Manipulator):
|
|||||||
"""
|
"""
|
||||||
self.request = request
|
self.request = request
|
||||||
self.fields = [
|
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]),
|
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
|
self.user_cache = None
|
||||||
|
|
||||||
@ -111,11 +111,11 @@ class PasswordChangeForm(oldforms.Manipulator):
|
|||||||
def __init__(self, user):
|
def __init__(self, user):
|
||||||
self.user = user
|
self.user = user
|
||||||
self.fields = (
|
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]),
|
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."))]),
|
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):
|
def isValidOldPassword(self, new_data, all_data):
|
||||||
@ -133,8 +133,8 @@ class AdminPasswordChangeForm(oldforms.Manipulator):
|
|||||||
def __init__(self, user):
|
def __init__(self, user):
|
||||||
self.user = user
|
self.user = user
|
||||||
self.fields = (
|
self.fields = (
|
||||||
oldforms.PasswordField(field_name='password1', 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, maxlength=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."))]),
|
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 datetime
|
||||||
import urllib
|
import urllib
|
||||||
|
|
||||||
|
UNUSABLE_PASSWORD = '!' # This will never be a valid hash
|
||||||
|
|
||||||
try:
|
try:
|
||||||
set
|
set
|
||||||
except NameError:
|
except NameError:
|
||||||
@ -48,9 +50,9 @@ class Permission(models.Model):
|
|||||||
|
|
||||||
Three basic permissions -- add, change and delete -- are automatically created for each Django 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)
|
content_type = models.ForeignKey(ContentType)
|
||||||
codename = models.CharField(_('codename'), maxlength=100)
|
codename = models.CharField(_('codename'), max_length=100)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = _('permission')
|
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.
|
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)
|
permissions = models.ManyToManyField(Permission, verbose_name=_('permissions'), blank=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
@ -80,11 +82,14 @@ class Group(models.Model):
|
|||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
class UserManager(models.Manager):
|
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."
|
"Creates and saves a User with the given username, e-mail and password."
|
||||||
now = datetime.datetime.now()
|
now = datetime.datetime.now()
|
||||||
user = self.model(None, username, '', '', email.strip().lower(), 'placeholder', False, True, False, now, 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()
|
user.save()
|
||||||
return user
|
return user
|
||||||
|
|
||||||
@ -100,11 +105,11 @@ class User(models.Model):
|
|||||||
|
|
||||||
Username and password are required. Other fields are optional.
|
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)."))
|
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'), maxlength=30, blank=True)
|
first_name = models.CharField(_('first name'), max_length=30, blank=True)
|
||||||
last_name = models.CharField(_('last name'), maxlength=30, blank=True)
|
last_name = models.CharField(_('last name'), max_length=30, blank=True)
|
||||||
email = models.EmailField(_('e-mail address'), 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_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_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."))
|
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 is_correct
|
||||||
return check_password(raw_password, self.password)
|
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):
|
def get_group_permissions(self):
|
||||||
"Returns a list of permission strings that this user has through his/her groups."
|
"Returns a list of permission strings that this user has through his/her groups."
|
||||||
if not hasattr(self, '_group_perm_cache'):
|
if not hasattr(self, '_group_perm_cache'):
|
||||||
@ -253,7 +265,8 @@ class User(models.Model):
|
|||||||
return self._profile_cache
|
return self._profile_cache
|
||||||
|
|
||||||
class Message(models.Model):
|
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)
|
user = models.ForeignKey(User)
|
||||||
message = models.TextField(_('message'))
|
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)
|
user = models.ForeignKey(User)
|
||||||
content_type = models.ForeignKey(ContentType)
|
content_type = models.ForeignKey(ContentType)
|
||||||
object_id = models.IntegerField(_('object ID'))
|
object_id = models.IntegerField(_('object ID'))
|
||||||
headline = models.CharField(_('headline'), maxlength=255, blank=True)
|
headline = models.CharField(_('headline'), max_length=255, blank=True)
|
||||||
comment = models.TextField(_('comment'), maxlength=3000)
|
comment = models.TextField(_('comment'), max_length=3000)
|
||||||
rating1 = models.PositiveSmallIntegerField(_('rating #1'), blank=True, null=True)
|
rating1 = models.PositiveSmallIntegerField(_('rating #1'), blank=True, null=True)
|
||||||
rating2 = models.PositiveSmallIntegerField(_('rating #2'), blank=True, null=True)
|
rating2 = models.PositiveSmallIntegerField(_('rating #2'), blank=True, null=True)
|
||||||
rating3 = models.PositiveSmallIntegerField(_('rating #3'), 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.
|
# A FreeComment is a comment by a non-registered user.
|
||||||
content_type = models.ForeignKey(ContentType)
|
content_type = models.ForeignKey(ContentType)
|
||||||
object_id = models.IntegerField(_('object ID'))
|
object_id = models.IntegerField(_('object ID'))
|
||||||
comment = models.TextField(_('comment'), maxlength=3000)
|
comment = models.TextField(_('comment'), max_length=3000)
|
||||||
person_name = models.CharField(_("person's name"), maxlength=50)
|
person_name = models.CharField(_("person's name"), max_length=50)
|
||||||
submit_date = models.DateTimeField(_('date/time submitted'), auto_now_add=True)
|
submit_date = models.DateTimeField(_('date/time submitted'), auto_now_add=True)
|
||||||
is_public = models.BooleanField(_('is public'))
|
is_public = models.BooleanField(_('is public'))
|
||||||
ip_address = models.IPAddressField(_('ip address'))
|
ip_address = models.IPAddressField(_('ip address'))
|
||||||
|
@ -5,6 +5,7 @@ from django import template
|
|||||||
from django.template import loader
|
from django.template import loader
|
||||||
from django.core.exceptions import ObjectDoesNotExist
|
from django.core.exceptions import ObjectDoesNotExist
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
|
from django.utils.encoding import smart_str
|
||||||
import re
|
import re
|
||||||
|
|
||||||
register = template.Library()
|
register = template.Library()
|
||||||
@ -174,6 +175,7 @@ class DoCommentForm:
|
|||||||
if tokens[4] != 'with':
|
if tokens[4] != 'with':
|
||||||
raise template.TemplateSyntaxError, "Fourth argument in %r tag must be 'with'" % tokens[0]
|
raise template.TemplateSyntaxError, "Fourth argument in %r tag must be 'with'" % tokens[0]
|
||||||
for option, args in zip(tokens[5::2], tokens[6::2]):
|
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:
|
if option in ('photos_optional', 'photos_required') and not self.free:
|
||||||
# VALIDATION ##############################################
|
# VALIDATION ##############################################
|
||||||
option_list = args.split(',')
|
option_list = args.split(',')
|
||||||
|
@ -29,7 +29,7 @@ class PublicCommentManipulator(AuthenticationForm):
|
|||||||
else:
|
else:
|
||||||
return []
|
return []
|
||||||
self.fields.extend([
|
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]),
|
validator_list=[self.hasNoProfanities]),
|
||||||
oldforms.RadioSelectField(field_name="rating1", choices=choices,
|
oldforms.RadioSelectField(field_name="rating1", choices=choices,
|
||||||
is_required=ratings_required and num_rating_choices > 0,
|
is_required=ratings_required and num_rating_choices > 0,
|
||||||
@ -122,9 +122,9 @@ class PublicFreeCommentManipulator(oldforms.Manipulator):
|
|||||||
"Manipulator that handles public free (unregistered) comments"
|
"Manipulator that handles public free (unregistered) comments"
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.fields = (
|
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]),
|
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]),
|
validator_list=[self.hasNoProfanities]),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -32,9 +32,9 @@ class ContentTypeManager(models.Manager):
|
|||||||
CONTENT_TYPE_CACHE = {}
|
CONTENT_TYPE_CACHE = {}
|
||||||
|
|
||||||
class ContentType(models.Model):
|
class ContentType(models.Model):
|
||||||
name = models.CharField(maxlength=100)
|
name = models.CharField(max_length=100)
|
||||||
app_label = models.CharField(maxlength=100)
|
app_label = models.CharField(max_length=100)
|
||||||
model = models.CharField(_('python model class name'), maxlength=100)
|
model = models.CharField(_('python model class name'), max_length=100)
|
||||||
objects = ContentTypeManager()
|
objects = ContentTypeManager()
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = _('content type')
|
verbose_name = _('content type')
|
||||||
|
@ -37,9 +37,10 @@ class FieldChoicePlugin(DatabrowsePlugin):
|
|||||||
|
|
||||||
def urls(self, plugin_name, easy_instance_field):
|
def urls(self, plugin_name, easy_instance_field):
|
||||||
if easy_instance_field.field in self.field_dict(easy_instance_field.model.model).values():
|
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(),
|
return [u'%s%s/%s/%s/' % (easy_instance_field.model.url(),
|
||||||
plugin_name, easy_instance_field.field.name,
|
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):
|
def model_view(self, request, model_databrowse, url):
|
||||||
self.model, self.site = model_databrowse.model, model_databrowse.site
|
self.model, self.site = model_databrowse.model, model_databrowse.site
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
<ul class="objectlist">
|
<ul class="objectlist">
|
||||||
{% for object in object_list %}
|
{% 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 %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
<ul class="objectlist">
|
<ul class="objectlist">
|
||||||
{% for object in object_list %}
|
{% 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 %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
<ul class="objectlist">
|
<ul class="objectlist">
|
||||||
{% for object in object_list %}
|
{% 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 %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
<ul class="objectlist">
|
<ul class="objectlist">
|
||||||
{% for choice in field.choices %}
|
{% 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 %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
<h2><a href="{{ model.url }}">{{ model.verbose_name_plural|capfirst }}</a></h2>
|
<h2><a href="{{ model.url }}">{{ model.verbose_name_plural|capfirst }}</a></h2>
|
||||||
<p>
|
<p>
|
||||||
{% for object in model.sample_objects %}
|
{% for object in model.sample_objects %}
|
||||||
<a href="{{ object.url }}">{{ object }}</a>,
|
<a href="{{ object.url }}">{{ object|escape }}</a>,
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
<a class="more" href="{{ model.url }}">More →</a>
|
<a class="more" href="{{ model.url }}">More →</a>
|
||||||
</p>
|
</p>
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
|
|
||||||
<ul class="objectlist">
|
<ul class="objectlist">
|
||||||
{% for object in model.objects %}
|
{% 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 %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
@ -4,9 +4,9 @@
|
|||||||
|
|
||||||
{% block content %}
|
{% 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">
|
<table class="objectinfo">
|
||||||
{% for field in object.fields %}
|
{% for field in object.fields %}
|
||||||
@ -14,8 +14,8 @@
|
|||||||
<th>{{ field.field.verbose_name|capfirst }}</th>
|
<th>{{ field.field.verbose_name|capfirst }}</th>
|
||||||
<td>
|
<td>
|
||||||
{% if field.urls %}
|
{% if field.urls %}
|
||||||
{% for urlvalue in field.urls %}
|
{% for value, url in field.urls %}
|
||||||
{% if urlvalue.1 %}<a href="{{ urlvalue.1 }}">{% endif %}{{ urlvalue.0 }}{% if urlvalue.1 %}</a>{% endif %}{% if not forloop.last %}, {% endif %}
|
{% if url %}<a href="{{ url }}">{% endif %}{{ value|escape }}{% if url %}</a>{% endif %}{% if not forloop.last %}, {% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% else %}None{% endif %}
|
{% else %}None{% endif %}
|
||||||
</td>
|
</td>
|
||||||
@ -29,7 +29,7 @@
|
|||||||
{% if related_object.object_list %}
|
{% if related_object.object_list %}
|
||||||
<ul class="objectlist">
|
<ul class="objectlist">
|
||||||
{% for object in related_object.object_list %}
|
{% 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 %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
{% else %}
|
{% else %}
|
||||||
|
@ -4,12 +4,12 @@ from django.contrib.sites.models import Site
|
|||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
class FlatPage(models.Model):
|
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."))
|
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'))
|
content = models.TextField(_('content'))
|
||||||
enable_comments = models.BooleanField(_('enable comments'))
|
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'."))
|
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."))
|
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)
|
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 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.translation import ugettext
|
||||||
from django.utils.encoding import smart_unicode
|
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):
|
class CLRutField(RegexField):
|
||||||
"""
|
"""
|
||||||
Chilean "Rol Unico Tributario" (RUT) field. This is the Chilean national
|
Chilean "Rol Unico Tributario" (RUT) field. This is the Chilean national
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
# -*- coding: iso-8859-1 -*-
|
|
||||||
"""
|
"""
|
||||||
Norwegian-specific Form helpers
|
Norwegian-specific Form helpers
|
||||||
"""
|
"""
|
||||||
@ -66,7 +65,7 @@ class NOSocialSecurityNumber(Field):
|
|||||||
weight_2 = [5, 4, 3, 2, 7, 6, 5, 4, 3, 2, 1]
|
weight_2 = [5, 4, 3, 2, 7, 6, 5, 4, 3, 2, 1]
|
||||||
|
|
||||||
def multiply_reduce(aval, bval):
|
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:
|
if multiply_reduce(digits, weight_1) % 11 != 0:
|
||||||
raise ValidationError(msg)
|
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):
|
class Redirect(models.Model):
|
||||||
site = models.ForeignKey(Site, radio_admin=models.VERTICAL)
|
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/'."))
|
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://'."))
|
help_text=_("This can be either an absolute path (as above) or a full URL starting with 'http://'."))
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
@ -2,7 +2,9 @@ from django.conf import settings
|
|||||||
from django.contrib.sessions.models import Session
|
from django.contrib.sessions.models import Session
|
||||||
from django.core.exceptions import SuspiciousOperation
|
from django.core.exceptions import SuspiciousOperation
|
||||||
from django.utils.cache import patch_vary_headers
|
from django.utils.cache import patch_vary_headers
|
||||||
|
from email.Utils import formatdate
|
||||||
import datetime
|
import datetime
|
||||||
|
import time
|
||||||
|
|
||||||
TEST_COOKIE_NAME = 'testcookie'
|
TEST_COOKIE_NAME = 'testcookie'
|
||||||
TEST_COOKIE_VALUE = 'worked'
|
TEST_COOKIE_VALUE = 'worked'
|
||||||
@ -37,7 +39,7 @@ class SessionWrapper(object):
|
|||||||
return self._session.get(key, default)
|
return self._session.get(key, default)
|
||||||
|
|
||||||
def pop(self, key, *args):
|
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)
|
return self._session.pop(key, *args)
|
||||||
|
|
||||||
def set_test_cookie(self):
|
def set_test_cookie(self):
|
||||||
@ -98,7 +100,11 @@ class SessionMiddleware(object):
|
|||||||
expires = None
|
expires = None
|
||||||
else:
|
else:
|
||||||
max_age = settings.SESSION_COOKIE_AGE
|
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,
|
new_session = Session.objects.save(session_key, request.session._session,
|
||||||
datetime.datetime.now() + datetime.timedelta(seconds=settings.SESSION_COOKIE_AGE))
|
datetime.datetime.now() + datetime.timedelta(seconds=settings.SESSION_COOKIE_AGE))
|
||||||
response.set_cookie(settings.SESSION_COOKIE_NAME, session_key,
|
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
|
the sessions documentation that is shipped with Django (also available
|
||||||
on the Django website).
|
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'))
|
session_data = models.TextField(_('session data'))
|
||||||
expire_date = models.DateTimeField(_('expire date'))
|
expire_date = models.DateTimeField(_('expire date'))
|
||||||
objects = SessionManager()
|
objects = SessionManager()
|
||||||
|
@ -4,11 +4,16 @@ from django.utils.translation import ugettext_lazy as _
|
|||||||
class SiteManager(models.Manager):
|
class SiteManager(models.Manager):
|
||||||
def get_current(self):
|
def get_current(self):
|
||||||
from django.conf import settings
|
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):
|
class Site(models.Model):
|
||||||
domain = models.CharField(_('domain name'), maxlength=100)
|
domain = models.CharField(_('domain name'), max_length=100)
|
||||||
name = models.CharField(_('display name'), maxlength=50)
|
name = models.CharField(_('display name'), max_length=50)
|
||||||
objects = SiteManager()
|
objects = SiteManager()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
@ -31,3 +36,20 @@ class SiteAdmin(admin.ModelAdmin):
|
|||||||
search_fields = ('domain', 'name')
|
search_fields = ('domain', 'name')
|
||||||
|
|
||||||
admin.site.register(Site, SiteAdmin)
|
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.core.exceptions import ImproperlyConfigured, ObjectDoesNotExist
|
||||||
from django.template import Context, loader, Template, TemplateDoesNotExist
|
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 import feedgenerator
|
||||||
from django.utils.encoding import smart_unicode
|
from django.utils.encoding import smart_unicode, iri_to_uri
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
|
||||||
def add_domain(domain, url):
|
def add_domain(domain, url):
|
||||||
if not url.startswith('http://'):
|
if not url.startswith('http://'):
|
||||||
# 'url' must already be ASCII and URL-quoted, so no need for encoding
|
# 'url' must already be ASCII and URL-quoted, so no need for encoding
|
||||||
# conversions here.
|
# conversions here.
|
||||||
url = u'http://%s%s' % (domain, url)
|
url = iri_to_uri(u'http://%s%s' % (domain, url))
|
||||||
return url
|
return url
|
||||||
|
|
||||||
class FeedDoesNotExist(ObjectDoesNotExist):
|
class FeedDoesNotExist(ObjectDoesNotExist):
|
||||||
@ -22,9 +22,10 @@ class Feed(object):
|
|||||||
title_template = None
|
title_template = None
|
||||||
description_template = None
|
description_template = None
|
||||||
|
|
||||||
def __init__(self, slug, feed_url):
|
def __init__(self, slug, request):
|
||||||
self.slug = slug
|
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.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)
|
self.description_template_name = self.description_template or ('feeds/%s_description.html' % slug)
|
||||||
|
|
||||||
@ -67,7 +68,11 @@ class Feed(object):
|
|||||||
else:
|
else:
|
||||||
obj = None
|
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 = self.__get_dynamic_attr('link', obj)
|
||||||
link = add_domain(current_site.domain, link)
|
link = add_domain(current_site.domain, link)
|
||||||
|
|
||||||
@ -83,6 +88,7 @@ class Feed(object):
|
|||||||
author_email = self.__get_dynamic_attr('author_email', obj),
|
author_email = self.__get_dynamic_attr('author_email', obj),
|
||||||
categories = self.__get_dynamic_attr('categories', obj),
|
categories = self.__get_dynamic_attr('categories', obj),
|
||||||
feed_copyright = self.__get_dynamic_attr('feed_copyright', obj),
|
feed_copyright = self.__get_dynamic_attr('feed_copyright', obj),
|
||||||
|
feed_guid = self.__get_dynamic_attr('feed_guid', obj),
|
||||||
)
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -114,7 +120,7 @@ class Feed(object):
|
|||||||
title = title_tmp.render(Context({'obj': item, 'site': current_site})),
|
title = title_tmp.render(Context({'obj': item, 'site': current_site})),
|
||||||
link = link,
|
link = link,
|
||||||
description = description_tmp.render(Context({'obj': item, 'site': current_site})),
|
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,
|
enclosure = enc,
|
||||||
pubdate = self.__get_dynamic_attr('item_pubdate', item),
|
pubdate = self.__get_dynamic_attr('item_pubdate', item),
|
||||||
author_name = author_name,
|
author_name = author_name,
|
||||||
|
@ -16,7 +16,7 @@ def feed(request, url, feed_dict=None):
|
|||||||
raise Http404, "Slug %r isn't registered." % slug
|
raise Http404, "Slug %r isn't registered." % slug
|
||||||
|
|
||||||
try:
|
try:
|
||||||
feedgen = f(slug, request.path).get_feed(param)
|
feedgen = f(slug, request).get_feed(param)
|
||||||
except feeds.FeedDoesNotExist:
|
except feeds.FeedDoesNotExist:
|
||||||
raise Http404, "Invalid feed parameters. Slug %r is valid, but other parameters, or lack thereof, are not." % slug
|
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"
|
"File-based cache backend"
|
||||||
|
|
||||||
from django.core.cache.backends.simple import CacheClass as SimpleCacheClass
|
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:
|
try:
|
||||||
import cPickle as pickle
|
import cPickle as pickle
|
||||||
except ImportError:
|
except ImportError:
|
||||||
@ -77,4 +78,4 @@ class CacheClass(SimpleCacheClass):
|
|||||||
raise EnvironmentError, "Cache directory '%s' does not exist and could not be created'" % self._dir
|
raise EnvironmentError, "Cache directory '%s' does not exist and could not be created'" % self._dir
|
||||||
|
|
||||||
def _key_to_file(self, key):
|
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."
|
"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.core.cache.backends.simple import CacheClass as SimpleCacheClass
|
||||||
from django.utils.synch import RWLock
|
from django.utils.synch import RWLock
|
||||||
import copy, time
|
|
||||||
|
|
||||||
class CacheClass(SimpleCacheClass):
|
class CacheClass(SimpleCacheClass):
|
||||||
def __init__(self, host, params):
|
def __init__(self, host, params):
|
||||||
@ -20,7 +25,10 @@ class CacheClass(SimpleCacheClass):
|
|||||||
elif exp < now:
|
elif exp < now:
|
||||||
should_delete = True
|
should_delete = True
|
||||||
else:
|
else:
|
||||||
return copy.deepcopy(self._cache[key])
|
try:
|
||||||
|
return pickle.loads(self._cache[key])
|
||||||
|
except pickle.PickleError:
|
||||||
|
return default
|
||||||
finally:
|
finally:
|
||||||
self._lock.reader_leaves()
|
self._lock.reader_leaves()
|
||||||
if should_delete:
|
if should_delete:
|
||||||
@ -35,7 +43,10 @@ class CacheClass(SimpleCacheClass):
|
|||||||
def set(self, key, value, timeout=None):
|
def set(self, key, value, timeout=None):
|
||||||
self._lock.writer_enters()
|
self._lock.writer_enters()
|
||||||
try:
|
try:
|
||||||
SimpleCacheClass.set(self, key, value, timeout)
|
try:
|
||||||
|
super(CacheClass, self).set(key, pickle.dumps(value), timeout)
|
||||||
|
except pickle.PickleError:
|
||||||
|
pass
|
||||||
finally:
|
finally:
|
||||||
self._lock.writer_leaves()
|
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"
|
"Memcached cache backend"
|
||||||
|
|
||||||
from django.core.cache.backends.base import BaseCache, InvalidCacheBackendError
|
from django.core.cache.backends.base import BaseCache, InvalidCacheBackendError
|
||||||
|
from django.utils.encoding import smart_unicode, smart_str
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import cmemcache as memcache
|
import cmemcache as memcache
|
||||||
@ -16,17 +17,22 @@ class CacheClass(BaseCache):
|
|||||||
self._cache = memcache.Client(server.split(';'))
|
self._cache = memcache.Client(server.split(';'))
|
||||||
|
|
||||||
def get(self, key, default=None):
|
def get(self, key, default=None):
|
||||||
val = self._cache.get(key)
|
val = self._cache.get(smart_str(key))
|
||||||
if val is None:
|
if val is None:
|
||||||
return default
|
return default
|
||||||
else:
|
else:
|
||||||
return val
|
if isinstance(val, basestring):
|
||||||
|
return smart_unicode(val)
|
||||||
|
else:
|
||||||
|
return val
|
||||||
|
|
||||||
def set(self, key, value, timeout=0):
|
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):
|
def delete(self, key):
|
||||||
self._cache.delete(key)
|
self._cache.delete(smart_str(key))
|
||||||
|
|
||||||
def get_many(self, keys):
|
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.core import signals
|
||||||
from django.dispatch import dispatcher
|
from django.dispatch import dispatcher
|
||||||
from django.utils import datastructures
|
from django.utils import datastructures
|
||||||
|
from django.utils.encoding import force_unicode
|
||||||
from django import http
|
from django import http
|
||||||
from pprint import pformat
|
from pprint import pformat
|
||||||
import os
|
import os
|
||||||
@ -13,7 +14,7 @@ import os
|
|||||||
class ModPythonRequest(http.HttpRequest):
|
class ModPythonRequest(http.HttpRequest):
|
||||||
def __init__(self, req):
|
def __init__(self, req):
|
||||||
self._req = req
|
self._req = req
|
||||||
self.path = req.uri
|
self.path = force_unicode(req.uri)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
# Since this is called as part of error handling, we need to be very
|
# 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.core import signals
|
||||||
from django.dispatch import dispatcher
|
from django.dispatch import dispatcher
|
||||||
from django.utils import datastructures
|
from django.utils import datastructures
|
||||||
|
from django.utils.encoding import force_unicode
|
||||||
from django import http
|
from django import http
|
||||||
from pprint import pformat
|
from pprint import pformat
|
||||||
from shutil import copyfileobj
|
from shutil import copyfileobj
|
||||||
@ -73,7 +74,7 @@ def safe_copyfileobj(fsrc, fdst, length=16*1024, size=0):
|
|||||||
class WSGIRequest(http.HttpRequest):
|
class WSGIRequest(http.HttpRequest):
|
||||||
def __init__(self, environ):
|
def __init__(self, environ):
|
||||||
self.environ = environ
|
self.environ = environ
|
||||||
self.path = environ['PATH_INFO']
|
self.path = force_unicode(environ['PATH_INFO'])
|
||||||
self.META = environ
|
self.META = environ
|
||||||
self.method = environ['REQUEST_METHOD'].upper()
|
self.method = environ['REQUEST_METHOD'].upper()
|
||||||
|
|
||||||
|
@ -95,19 +95,12 @@ def _get_sequence_list():
|
|||||||
|
|
||||||
return 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):
|
def get_sql_create(app):
|
||||||
"Returns a list of the CREATE TABLE SQL statements for the given 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 settings.DATABASE_ENGINE == 'dummy':
|
||||||
|
|
||||||
if not data_types:
|
|
||||||
# This must be the "dummy" database backend, which means the user
|
# This must be the "dummy" database backend, which means the user
|
||||||
# hasn't set DATABASE_ENGINE.
|
# hasn't set DATABASE_ENGINE.
|
||||||
sys.stderr.write(style.ERROR("Error: Django doesn't know which syntax to use for your SQL statements,\n" +
|
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
|
Returns list_of_sql, pending_references_dict
|
||||||
"""
|
"""
|
||||||
from django.db import backend, get_creation_module, models
|
from django.db import backend, models
|
||||||
data_types = get_creation_module().DATA_TYPES
|
|
||||||
|
|
||||||
opts = model._meta
|
opts = model._meta
|
||||||
final_output = []
|
final_output = []
|
||||||
table_output = []
|
table_output = []
|
||||||
pending_references = {}
|
pending_references = {}
|
||||||
for f in opts.fields:
|
for f in opts.fields:
|
||||||
if isinstance(f, (models.ForeignKey, models.OneToOneField)):
|
col_type = f.db_type()
|
||||||
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]
|
|
||||||
tablespace = f.db_tablespace or opts.db_tablespace
|
tablespace = f.db_tablespace or opts.db_tablespace
|
||||||
if col_type is not None:
|
if col_type is None:
|
||||||
# Make the definition (e.g. 'foo VARCHAR(30)') for this field.
|
# Skip ManyToManyFields, because they're not represented as
|
||||||
field_output = [style.SQL_FIELD(backend.quote_name(f.column)),
|
# database columns in this table.
|
||||||
style.SQL_COLTYPE(col_type % rel_field.__dict__)]
|
continue
|
||||||
field_output.append(style.SQL_KEYWORD('%sNULL' % (not f.null and 'NOT ' or '')))
|
# Make the definition (e.g. 'foo VARCHAR(30)') for this field.
|
||||||
if f.unique and (not f.primary_key or backend.allows_unique_and_pk):
|
field_output = [style.SQL_FIELD(backend.quote_name(f.column)),
|
||||||
field_output.append(style.SQL_KEYWORD('UNIQUE'))
|
style.SQL_COLTYPE(col_type)]
|
||||||
if f.primary_key:
|
field_output.append(style.SQL_KEYWORD('%sNULL' % (not f.null and 'NOT ' or '')))
|
||||||
field_output.append(style.SQL_KEYWORD('PRIMARY KEY'))
|
if f.unique and (not f.primary_key or backend.allows_unique_and_pk):
|
||||||
if tablespace and backend.supports_tablespaces and (f.unique or f.primary_key) and backend.autoindexes_primary_keys:
|
field_output.append(style.SQL_KEYWORD('UNIQUE'))
|
||||||
# We must specify the index tablespace inline, because we
|
if f.primary_key:
|
||||||
# won't be generating a CREATE INDEX statement for this field.
|
field_output.append(style.SQL_KEYWORD('PRIMARY KEY'))
|
||||||
field_output.append(backend.get_tablespace_sql(tablespace, inline=True))
|
if tablespace and backend.supports_tablespaces and (f.unique or f.primary_key) and backend.autoindexes_primary_keys:
|
||||||
if f.rel:
|
# We must specify the index tablespace inline, because we
|
||||||
if f.rel.to in known_models:
|
# won't be generating a CREATE INDEX statement for this field.
|
||||||
field_output.append(style.SQL_KEYWORD('REFERENCES') + ' ' + \
|
field_output.append(backend.get_tablespace_sql(tablespace, inline=True))
|
||||||
style.SQL_TABLE(backend.quote_name(f.rel.to._meta.db_table)) + ' (' + \
|
if f.rel:
|
||||||
style.SQL_FIELD(backend.quote_name(f.rel.to._meta.get_field(f.rel.field_name).column)) + ')' +
|
if f.rel.to in known_models:
|
||||||
backend.get_deferrable_sql()
|
field_output.append(style.SQL_KEYWORD('REFERENCES') + ' ' + \
|
||||||
)
|
style.SQL_TABLE(backend.quote_name(f.rel.to._meta.db_table)) + ' (' + \
|
||||||
else:
|
style.SQL_FIELD(backend.quote_name(f.rel.to._meta.get_field(f.rel.field_name).column)) + ')' +
|
||||||
# We haven't yet created the table to which this field
|
backend.get_deferrable_sql()
|
||||||
# is related, so save it for later.
|
)
|
||||||
pr = pending_references.setdefault(f.rel.to, []).append((model, f))
|
else:
|
||||||
table_output.append(' '.join(field_output))
|
# 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:
|
if opts.order_with_respect_to:
|
||||||
table_output.append(style.SQL_FIELD(backend.quote_name('_order')) + ' ' + \
|
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'))
|
style.SQL_KEYWORD('NULL'))
|
||||||
for field_constraints in opts.unique_together:
|
for field_constraints in opts.unique_together:
|
||||||
table_output.append(style.SQL_KEYWORD('UNIQUE') + ' (%s)' % \
|
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.
|
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
|
from django.db.backends.util import truncate_name
|
||||||
data_types = get_creation_module().DATA_TYPES
|
|
||||||
|
|
||||||
final_output = []
|
final_output = []
|
||||||
if backend.supports_constraints:
|
if backend.supports_constraints:
|
||||||
@ -257,11 +243,9 @@ def _get_sql_for_pending_references(model, pending_references):
|
|||||||
return final_output
|
return final_output
|
||||||
|
|
||||||
def _get_many_to_many_sql_for_model(model):
|
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
|
from django.contrib.contenttypes import generic
|
||||||
|
|
||||||
data_types = get_creation_module().DATA_TYPES
|
|
||||||
|
|
||||||
opts = model._meta
|
opts = model._meta
|
||||||
final_output = []
|
final_output = []
|
||||||
for f in opts.many_to_many:
|
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())) + ' (']
|
style.SQL_TABLE(backend.quote_name(f.m2m_db_table())) + ' (']
|
||||||
table_output.append(' %s %s %s%s,' % \
|
table_output.append(' %s %s %s%s,' % \
|
||||||
(style.SQL_FIELD(backend.quote_name('id')),
|
(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'),
|
style.SQL_KEYWORD('NOT NULL PRIMARY KEY'),
|
||||||
tablespace_sql))
|
tablespace_sql))
|
||||||
table_output.append(' %s %s %s %s (%s)%s,' % \
|
table_output.append(' %s %s %s %s (%s)%s,' % \
|
||||||
(style.SQL_FIELD(backend.quote_name(f.m2m_column_name())),
|
(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_KEYWORD('NOT NULL REFERENCES'),
|
||||||
style.SQL_TABLE(backend.quote_name(opts.db_table)),
|
style.SQL_TABLE(backend.quote_name(opts.db_table)),
|
||||||
style.SQL_FIELD(backend.quote_name(opts.pk.column)),
|
style.SQL_FIELD(backend.quote_name(opts.pk.column)),
|
||||||
backend.get_deferrable_sql()))
|
backend.get_deferrable_sql()))
|
||||||
table_output.append(' %s %s %s %s (%s)%s,' % \
|
table_output.append(' %s %s %s %s (%s)%s,' % \
|
||||||
(style.SQL_FIELD(backend.quote_name(f.m2m_reverse_name())),
|
(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_KEYWORD('NOT NULL REFERENCES'),
|
||||||
style.SQL_TABLE(backend.quote_name(f.rel.to._meta.db_table)),
|
style.SQL_TABLE(backend.quote_name(f.rel.to._meta.db_table)),
|
||||||
style.SQL_FIELD(backend.quote_name(f.rel.to._meta.pk.column)),
|
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):
|
def syncdb(verbosity=1, interactive=True):
|
||||||
"Creates the database tables for all apps in INSTALLED_APPS whose tables haven't already been created."
|
"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
|
from django.conf import settings
|
||||||
|
|
||||||
disable_termcolors()
|
disable_termcolors()
|
||||||
@ -533,8 +517,6 @@ def syncdb(verbosity=1, interactive=True):
|
|||||||
except ImportError:
|
except ImportError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
data_types = get_creation_module().DATA_TYPES
|
|
||||||
|
|
||||||
cursor = connection.cursor()
|
cursor = connection.cursor()
|
||||||
|
|
||||||
# Get a list of all existing database tables,
|
# Get a list of all existing database tables,
|
||||||
@ -928,9 +910,9 @@ def inspectdb():
|
|||||||
field_type, new_params = field_type
|
field_type, new_params = field_type
|
||||||
extra_params.update(new_params)
|
extra_params.update(new_params)
|
||||||
|
|
||||||
# Add maxlength for all CharFields.
|
# Add max_length for all CharFields.
|
||||||
if field_type == 'CharField' and row[3]:
|
if field_type == 'CharField' and row[3]:
|
||||||
extra_params['maxlength'] = row[3]
|
extra_params['max_length'] = row[3]
|
||||||
|
|
||||||
if field_type == 'DecimalField':
|
if field_type == 'DecimalField':
|
||||||
extra_params['max_digits'] = row[4]
|
extra_params['max_digits'] = row[4]
|
||||||
@ -1005,8 +987,8 @@ def get_validation_errors(outfile, app=None):
|
|||||||
for f in opts.fields:
|
for f in opts.fields:
|
||||||
if f.name == 'id' and not f.primary_key and opts.pk.name == 'id':
|
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)
|
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):
|
if isinstance(f, models.CharField) and f.max_length in (None, 0):
|
||||||
e.add(opts, '"%s": CharFields require a "maxlength" attribute.' % f.name)
|
e.add(opts, '"%s": CharFields require a "max_length" attribute.' % f.name)
|
||||||
if isinstance(f, models.DecimalField):
|
if isinstance(f, models.DecimalField):
|
||||||
if f.decimal_places is None:
|
if f.decimal_places is None:
|
||||||
e.add(opts, '"%s": DecimalFields require a "decimal_places" attribute.' % f.name)
|
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):
|
if f.db_index not in (None, True, False):
|
||||||
e.add(opts, '"%s": "db_index" should be either None, True or False.' % f.name)
|
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':
|
if settings.DATABASE_ENGINE == 'mysql':
|
||||||
db_version = connection.get_server_version()
|
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:
|
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 "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]])))
|
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
|
# Check to see if the related field will clash with any
|
||||||
# existing fields, m2m fields, m2m related objects or related objects
|
# 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):
|
except (AttributeError, KeyError):
|
||||||
error_text = str(e)
|
error_text = str(e)
|
||||||
sys.stderr.write(style.ERROR("Error: %s" % error_text) + '\n')
|
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:
|
except KeyboardInterrupt:
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
if use_reloader:
|
if use_reloader:
|
||||||
@ -1269,18 +1252,17 @@ runserver.args = '[--noreload] [--adminmedia=ADMIN_MEDIA_PATH] [optional port nu
|
|||||||
|
|
||||||
def createcachetable(tablename):
|
def createcachetable(tablename):
|
||||||
"Creates the table needed to use the SQL cache backend"
|
"Creates the table needed to use the SQL cache backend"
|
||||||
from django.db import backend, connection, transaction, get_creation_module, models
|
from django.db import backend, connection, transaction, models
|
||||||
data_types = get_creation_module().DATA_TYPES
|
|
||||||
fields = (
|
fields = (
|
||||||
# "key" is a reserved word in MySQL, so use "cache_key" instead.
|
# "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.TextField(name='value'),
|
||||||
models.DateTimeField(name='expires', db_index=True),
|
models.DateTimeField(name='expires', db_index=True),
|
||||||
)
|
)
|
||||||
table_output = []
|
table_output = []
|
||||||
index_output = []
|
index_output = []
|
||||||
for f in fields:
|
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 ""))
|
field_output.append("%sNULL" % (not f.null and "NOT " or ""))
|
||||||
if f.unique:
|
if f.unique:
|
||||||
field_output.append("UNIQUE")
|
field_output.append("UNIQUE")
|
||||||
@ -1321,6 +1303,10 @@ def run_shell(use_plain=False):
|
|||||||
shell.mainloop()
|
shell.mainloop()
|
||||||
except ImportError:
|
except ImportError:
|
||||||
import code
|
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.
|
try: # Try activating rlcompleter, because it's handy.
|
||||||
import readline
|
import readline
|
||||||
except ImportError:
|
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 don't have to wrap the following import in a 'try', because
|
||||||
# we already know 'readline' was imported successfully.
|
# we already know 'readline' was imported successfully.
|
||||||
import rlcompleter
|
import rlcompleter
|
||||||
|
readline.set_completer(rlcompleter.Completer(imported_objects).complete)
|
||||||
readline.parse_and_bind("tab:complete")
|
readline.parse_and_bind("tab:complete")
|
||||||
code.interact()
|
code.interact(local=imported_objects)
|
||||||
run_shell.args = '[--plain]'
|
run_shell.args = '[--plain]'
|
||||||
|
|
||||||
def dbshell():
|
def dbshell():
|
||||||
@ -1352,16 +1339,11 @@ def runfcgi(args):
|
|||||||
runfastcgi(args)
|
runfastcgi(args)
|
||||||
runfcgi.args = '[various KEY=val options, use `runfcgi help` for help]'
|
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"
|
"Runs the test suite for the specified applications"
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.db.models import get_app, get_apps
|
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('.')
|
test_path = settings.TEST_RUNNER.split('.')
|
||||||
# Allow for Python 2.5 relative paths
|
# Allow for Python 2.5 relative paths
|
||||||
if len(test_path) > 1:
|
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_module = __import__(test_module_name, {}, {}, test_path[-1])
|
||||||
test_runner = getattr(test_module, 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:
|
if failures:
|
||||||
sys.exit(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.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):
|
def load_data(fixture_labels, verbosity=1):
|
||||||
"Installs the provided fixture file(s) as data in the database."
|
"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." % \
|
print "Installing %s fixture '%s' from %s." % \
|
||||||
(format, fixture_name, humanize(fixture_dir))
|
(format, fixture_name, humanize(fixture_dir))
|
||||||
try:
|
try:
|
||||||
objects = serializers.deserialize(format, fixture)
|
objects = serializers.deserialize(format, fixture)
|
||||||
for obj in objects:
|
for obj in objects:
|
||||||
count[0] += 1
|
count[0] += 1
|
||||||
models.add(obj.object.__class__)
|
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])
|
action_mapping[action](args[1])
|
||||||
except IndexError:
|
except IndexError:
|
||||||
parser.print_usage_and_exit()
|
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:
|
try:
|
||||||
action_mapping[action](args[1:], int(options.verbosity))
|
action_mapping[action](args[1:], int(options.verbosity))
|
||||||
except IndexError:
|
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
|
# 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
|
# way. For example, if this file (manage.py) lives in a directory
|
||||||
# "myproject", this code would add "/path/to/myproject" to sys.path.
|
# "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)
|
project_name = os.path.basename(project_directory)
|
||||||
|
settings_name = os.path.splitext(settings_filename)[0]
|
||||||
sys.path.append(os.path.join(project_directory, '..'))
|
sys.path.append(os.path.join(project_directory, '..'))
|
||||||
project_module = __import__(project_name, {}, {}, [''])
|
project_module = __import__(project_name, {}, {}, [''])
|
||||||
sys.path.pop()
|
sys.path.pop()
|
||||||
|
|
||||||
# Set DJANGO_SETTINGS_MODULE appropriately.
|
# 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
|
return project_directory
|
||||||
|
|
||||||
def execute_manager(settings_mod, argv=None):
|
def execute_manager(settings_mod, argv=None):
|
||||||
|
@ -158,7 +158,12 @@ class DeserializedObject(object):
|
|||||||
return "<DeserializedObject: %s>" % smart_str(self.object)
|
return "<DeserializedObject: %s>" % smart_str(self.object)
|
||||||
|
|
||||||
def save(self, save_m2m=True):
|
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:
|
if self.m2m_data and save_m2m:
|
||||||
for accessor_name, object_list in self.m2m_data.items():
|
for accessor_name, object_list in self.m2m_data.items():
|
||||||
setattr(self.object, accessor_name, object_list)
|
setattr(self.object, accessor_name, object_list)
|
||||||
|
@ -171,7 +171,7 @@ class Deserializer(base.Deserializer):
|
|||||||
elif field.rel and isinstance(field.rel, models.ManyToOneRel):
|
elif field.rel and isinstance(field.rel, models.ManyToOneRel):
|
||||||
data[field.attname] = self._handle_fk_field_node(field_node, field)
|
data[field.attname] = self._handle_fk_field_node(field_node, field)
|
||||||
else:
|
else:
|
||||||
if len(field_node.childNodes) == 1 and field_node.childNodes[0].nodeName == 'None':
|
if field_node.getElementsByTagName('None'):
|
||||||
value = None
|
value = None
|
||||||
else:
|
else:
|
||||||
value = field.to_python(getInnerText(field_node).strip())
|
value = field.to_python(getInnerText(field_node).strip())
|
||||||
@ -185,7 +185,7 @@ class Deserializer(base.Deserializer):
|
|||||||
Handle a <field> node for a ForeignKey
|
Handle a <field> node for a ForeignKey
|
||||||
"""
|
"""
|
||||||
# Check if there is a child node named 'None', returning None if so.
|
# 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
|
return None
|
||||||
else:
|
else:
|
||||||
return field.rel.to._meta.get_field(field.rel.field_name).to_python(
|
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 BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
|
||||||
from types import ListType, StringType
|
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"
|
__version__ = "0.1"
|
||||||
__all__ = ['WSGIServer','WSGIRequestHandler','demo_app']
|
__all__ = ['WSGIServer','WSGIRequestHandler','demo_app']
|
||||||
@ -370,7 +376,7 @@ class ServerHandler(object):
|
|||||||
self._write('HTTP/%s %s\r\n' % (self.http_version,self.status))
|
self._write('HTTP/%s %s\r\n' % (self.http_version,self.status))
|
||||||
if 'Date' not in self.headers:
|
if 'Date' not in self.headers:
|
||||||
self._write(
|
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:
|
if self.server_software and 'Server' not in self.headers:
|
||||||
self._write('Server: %s\r\n' % self.server_software)
|
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.http import Http404
|
||||||
from django.core.exceptions import ImproperlyConfigured, ViewDoesNotExist
|
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
|
from django.utils.functional import memoize
|
||||||
import re
|
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
|
If can_fail is True, lookup_view might be a URL pattern label, so errors
|
||||||
during the import fail and the string is returned.
|
during the import fail and the string is returned.
|
||||||
"""
|
"""
|
||||||
try:
|
if not callable(lookup_view):
|
||||||
# Bail out early if lookup_view is not ASCII. This can't be a function.
|
try:
|
||||||
lookup_view = lookup_view.encode('ascii')
|
# Bail early for non-ASCII strings (they can't be functions).
|
||||||
|
lookup_view = lookup_view.encode('ascii')
|
||||||
if not callable(lookup_view):
|
|
||||||
mod_name, func_name = get_mod_func(lookup_view)
|
mod_name, func_name = get_mod_func(lookup_view)
|
||||||
try:
|
if func_name != '':
|
||||||
if func_name != '':
|
lookup_view = getattr(__import__(mod_name, {}, {}, ['']), func_name)
|
||||||
lookup_view = getattr(__import__(mod_name, {}, {}, ['']), func_name)
|
except (ImportError, AttributeError):
|
||||||
except (ImportError, AttributeError):
|
if not can_fail:
|
||||||
if not can_fail:
|
raise
|
||||||
raise
|
except UnicodeEncodeError:
|
||||||
except UnicodeEncodeError:
|
pass
|
||||||
pass
|
|
||||||
return lookup_view
|
return lookup_view
|
||||||
get_callable = memoize(get_callable, _callable_cache)
|
get_callable = memoize(get_callable, _callable_cache, 1)
|
||||||
|
|
||||||
def get_resolver(urlconf):
|
def get_resolver(urlconf):
|
||||||
if urlconf is None:
|
if urlconf is None:
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
urlconf = settings.ROOT_URLCONF
|
urlconf = settings.ROOT_URLCONF
|
||||||
return RegexURLResolver(r'^/', 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):
|
def get_mod_func(callback):
|
||||||
# Converts 'django.views.news.stories.story_detail' to
|
# 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.
|
# First we need to figure out whether it's a named or unnamed group.
|
||||||
#
|
#
|
||||||
grouped = match_obj.group(1)
|
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...
|
if m: # If this was a named group...
|
||||||
# m.group(1) is the name of the group
|
# m.group(1) is the name of the group
|
||||||
# m.group(2) is the regex.
|
# m.group(2) is the regex.
|
||||||
@ -127,9 +125,9 @@ class MatchChecker(object):
|
|||||||
test_regex = grouped
|
test_regex = grouped
|
||||||
# Note we're using re.match here on purpose because the start of
|
# Note we're using re.match here on purpose because the start of
|
||||||
# to string needs to match.
|
# 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))
|
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):
|
class RegexURLPattern(object):
|
||||||
def __init__(self, regex, callback, default_args=None, name=None):
|
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'
|
# 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
|
# which represents the path to a module and a view function name, or a
|
||||||
# callable object (view).
|
# callable object (view).
|
||||||
self.regex = re.compile(regex)
|
self.regex = re.compile(regex, re.UNICODE)
|
||||||
if callable(callback):
|
if callable(callback):
|
||||||
self._callback = callback
|
self._callback = callback
|
||||||
else:
|
else:
|
||||||
@ -146,6 +144,9 @@ class RegexURLPattern(object):
|
|||||||
self.default_args = default_args or {}
|
self.default_args = default_args or {}
|
||||||
self.name = name
|
self.name = name
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return '<%s %s %s>' % (self.__class__.__name__, self.name, self.regex.pattern)
|
||||||
|
|
||||||
def add_prefix(self, prefix):
|
def add_prefix(self, prefix):
|
||||||
"""
|
"""
|
||||||
Adds the prefix string to a string-based callback.
|
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):
|
def __init__(self, regex, urlconf_name, default_kwargs=None):
|
||||||
# regex is a string representing a regular expression.
|
# regex is a string representing a regular expression.
|
||||||
# urlconf_name is a string representing the module containing urlconfs.
|
# 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.urlconf_name = urlconf_name
|
||||||
self.callback = None
|
self.callback = None
|
||||||
self.default_kwargs = default_kwargs or {}
|
self.default_kwargs = default_kwargs or {}
|
||||||
self._reverse_dict = {}
|
self._reverse_dict = {}
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return '<%s %s %s>' % (self.__class__.__name__, self.urlconf_name, self.regex.pattern)
|
||||||
|
|
||||||
def _get_reverse_dict(self):
|
def _get_reverse_dict(self):
|
||||||
if not self._reverse_dict and hasattr(self.urlconf_module, 'urlpatterns'):
|
if not self._reverse_dict and hasattr(self.urlconf_module, 'urlpatterns'):
|
||||||
for pattern in reversed(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']])
|
tried.extend([(pattern.regex.pattern + ' ' + t) for t in e.args[0]['tried']])
|
||||||
else:
|
else:
|
||||||
if sub_match:
|
if sub_match:
|
||||||
sub_match_dict = dict(self.default_kwargs, **sub_match[2])
|
sub_match_dict = dict([(smart_str(k), v) for k, v in match.groupdict().items()])
|
||||||
return sub_match[0], sub_match[1], dict(match.groupdict(), **sub_match_dict)
|
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)
|
tried.append(pattern.regex.pattern)
|
||||||
raise Resolver404, {'tried': tried, 'path': new_path}
|
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.functional import Promise, lazy
|
||||||
from django.utils.encoding import force_unicode
|
from django.utils.encoding import force_unicode
|
||||||
import re
|
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}'
|
_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])?'
|
_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))
|
ansi_datetime_re = re.compile('^%s %s$' % (_datere, _timere))
|
||||||
email_re = re.compile(
|
email_re = re.compile(
|
||||||
r"(^[-!#$%&'*+/=?^_`{}|~0-9A-Z]+(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*" # dot-atom
|
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
|
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+$')
|
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}$')
|
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)
|
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
|
self.max_digits, self.decimal_places = max_digits, decimal_places
|
||||||
|
|
||||||
def __call__(self, field_data, all_data):
|
def __call__(self, field_data, all_data):
|
||||||
match = decimal_re.search(str(field_data))
|
try:
|
||||||
if not match:
|
val = Decimal(field_data)
|
||||||
|
except DecimalException:
|
||||||
raise ValidationError, _("Please enter a valid decimal number.")
|
raise ValidationError, _("Please enter a valid decimal number.")
|
||||||
|
|
||||||
digits = len(match.group('digits') or '')
|
pieces = str(val).split('.')
|
||||||
decimals = len(match.group('decimals') or '')
|
decimals = (len(pieces) == 2) and len(pieces[1]) or 0
|
||||||
|
digits = len(pieces[0])
|
||||||
|
|
||||||
if digits + decimals > self.max_digits:
|
if digits + decimals > self.max_digits:
|
||||||
raise ValidationError, ungettext("Please enter a valid decimal number with at most %s total digit.",
|
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
|
"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:
|
try:
|
||||||
float(data)
|
float(data)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
raise ValidationError, ugettext("Please enter a valid floating point number.")
|
raise ValidationError, _("Please enter a valid floating point number.")
|
||||||
|
|
||||||
class HasAllowableSize(object):
|
class HasAllowableSize(object):
|
||||||
"""
|
"""
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
DATA_TYPES = {
|
DATA_TYPES = {
|
||||||
'AutoField': 'int IDENTITY (1, 1)',
|
'AutoField': 'int IDENTITY (1, 1)',
|
||||||
'BooleanField': 'bit',
|
'BooleanField': 'bit',
|
||||||
'CharField': 'varchar(%(maxlength)s)',
|
'CharField': 'varchar(%(max_length)s)',
|
||||||
'CommaSeparatedIntegerField': 'varchar(%(maxlength)s)',
|
'CommaSeparatedIntegerField': 'varchar(%(max_length)s)',
|
||||||
'DateField': 'smalldatetime',
|
'DateField': 'smalldatetime',
|
||||||
'DateTimeField': 'smalldatetime',
|
'DateTimeField': 'smalldatetime',
|
||||||
'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)',
|
'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)',
|
||||||
@ -12,13 +12,12 @@ DATA_TYPES = {
|
|||||||
'ImageField': 'varchar(100)',
|
'ImageField': 'varchar(100)',
|
||||||
'IntegerField': 'int',
|
'IntegerField': 'int',
|
||||||
'IPAddressField': 'char(15)',
|
'IPAddressField': 'char(15)',
|
||||||
'ManyToManyField': None,
|
|
||||||
'NullBooleanField': 'bit',
|
'NullBooleanField': 'bit',
|
||||||
'OneToOneField': 'int',
|
'OneToOneField': 'int',
|
||||||
'PhoneNumberField': 'varchar(20)',
|
'PhoneNumberField': 'varchar(20)',
|
||||||
'PositiveIntegerField': 'int CONSTRAINT [CK_int_pos_%(column)s] CHECK ([%(column)s] > 0)',
|
'PositiveIntegerField': 'int CONSTRAINT [CK_int_pos_%(column)s] CHECK ([%(column)s] > 0)',
|
||||||
'PositiveSmallIntegerField': 'smallint CONSTRAINT [CK_smallint_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',
|
'SmallIntegerField': 'smallint',
|
||||||
'TextField': 'text',
|
'TextField': 'text',
|
||||||
'TimeField': 'time',
|
'TimeField': 'time',
|
||||||
|
@ -5,8 +5,8 @@
|
|||||||
DATA_TYPES = {
|
DATA_TYPES = {
|
||||||
'AutoField': 'integer AUTO_INCREMENT',
|
'AutoField': 'integer AUTO_INCREMENT',
|
||||||
'BooleanField': 'bool',
|
'BooleanField': 'bool',
|
||||||
'CharField': 'varchar(%(maxlength)s)',
|
'CharField': 'varchar(%(max_length)s)',
|
||||||
'CommaSeparatedIntegerField': 'varchar(%(maxlength)s)',
|
'CommaSeparatedIntegerField': 'varchar(%(max_length)s)',
|
||||||
'DateField': 'date',
|
'DateField': 'date',
|
||||||
'DateTimeField': 'datetime',
|
'DateTimeField': 'datetime',
|
||||||
'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)',
|
'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)',
|
||||||
@ -16,13 +16,12 @@ DATA_TYPES = {
|
|||||||
'ImageField': 'varchar(100)',
|
'ImageField': 'varchar(100)',
|
||||||
'IntegerField': 'integer',
|
'IntegerField': 'integer',
|
||||||
'IPAddressField': 'char(15)',
|
'IPAddressField': 'char(15)',
|
||||||
'ManyToManyField': None,
|
|
||||||
'NullBooleanField': 'bool',
|
'NullBooleanField': 'bool',
|
||||||
'OneToOneField': 'integer',
|
'OneToOneField': 'integer',
|
||||||
'PhoneNumberField': 'varchar(20)',
|
'PhoneNumberField': 'varchar(20)',
|
||||||
'PositiveIntegerField': 'integer UNSIGNED',
|
'PositiveIntegerField': 'integer UNSIGNED',
|
||||||
'PositiveSmallIntegerField': 'smallint UNSIGNED',
|
'PositiveSmallIntegerField': 'smallint UNSIGNED',
|
||||||
'SlugField': 'varchar(%(maxlength)s)',
|
'SlugField': 'varchar(%(max_length)s)',
|
||||||
'SmallIntegerField': 'smallint',
|
'SmallIntegerField': 'smallint',
|
||||||
'TextField': 'longtext',
|
'TextField': 'longtext',
|
||||||
'TimeField': 'time',
|
'TimeField': 'time',
|
||||||
|
@ -5,8 +5,8 @@
|
|||||||
DATA_TYPES = {
|
DATA_TYPES = {
|
||||||
'AutoField': 'integer AUTO_INCREMENT',
|
'AutoField': 'integer AUTO_INCREMENT',
|
||||||
'BooleanField': 'bool',
|
'BooleanField': 'bool',
|
||||||
'CharField': 'varchar(%(maxlength)s)',
|
'CharField': 'varchar(%(max_length)s)',
|
||||||
'CommaSeparatedIntegerField': 'varchar(%(maxlength)s)',
|
'CommaSeparatedIntegerField': 'varchar(%(max_length)s)',
|
||||||
'DateField': 'date',
|
'DateField': 'date',
|
||||||
'DateTimeField': 'datetime',
|
'DateTimeField': 'datetime',
|
||||||
'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)',
|
'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)',
|
||||||
@ -16,13 +16,12 @@ DATA_TYPES = {
|
|||||||
'ImageField': 'varchar(100)',
|
'ImageField': 'varchar(100)',
|
||||||
'IntegerField': 'integer',
|
'IntegerField': 'integer',
|
||||||
'IPAddressField': 'char(15)',
|
'IPAddressField': 'char(15)',
|
||||||
'ManyToManyField': None,
|
|
||||||
'NullBooleanField': 'bool',
|
'NullBooleanField': 'bool',
|
||||||
'OneToOneField': 'integer',
|
'OneToOneField': 'integer',
|
||||||
'PhoneNumberField': 'varchar(20)',
|
'PhoneNumberField': 'varchar(20)',
|
||||||
'PositiveIntegerField': 'integer UNSIGNED',
|
'PositiveIntegerField': 'integer UNSIGNED',
|
||||||
'PositiveSmallIntegerField': 'smallint UNSIGNED',
|
'PositiveSmallIntegerField': 'smallint UNSIGNED',
|
||||||
'SlugField': 'varchar(%(maxlength)s)',
|
'SlugField': 'varchar(%(max_length)s)',
|
||||||
'SmallIntegerField': 'smallint',
|
'SmallIntegerField': 'smallint',
|
||||||
'TextField': 'longtext',
|
'TextField': 'longtext',
|
||||||
'TimeField': 'time',
|
'TimeField': 'time',
|
||||||
|
@ -8,8 +8,8 @@ from django.core import management
|
|||||||
DATA_TYPES = {
|
DATA_TYPES = {
|
||||||
'AutoField': 'NUMBER(11)',
|
'AutoField': 'NUMBER(11)',
|
||||||
'BooleanField': 'NUMBER(1) CHECK (%(column)s IN (0,1))',
|
'BooleanField': 'NUMBER(1) CHECK (%(column)s IN (0,1))',
|
||||||
'CharField': 'NVARCHAR2(%(maxlength)s)',
|
'CharField': 'NVARCHAR2(%(max_length)s)',
|
||||||
'CommaSeparatedIntegerField': 'VARCHAR2(%(maxlength)s)',
|
'CommaSeparatedIntegerField': 'VARCHAR2(%(max_length)s)',
|
||||||
'DateField': 'DATE',
|
'DateField': 'DATE',
|
||||||
'DateTimeField': 'TIMESTAMP',
|
'DateTimeField': 'TIMESTAMP',
|
||||||
'DecimalField': 'NUMBER(%(max_digits)s, %(decimal_places)s)',
|
'DecimalField': 'NUMBER(%(max_digits)s, %(decimal_places)s)',
|
||||||
@ -19,7 +19,6 @@ DATA_TYPES = {
|
|||||||
'ImageField': 'NVARCHAR2(100)',
|
'ImageField': 'NVARCHAR2(100)',
|
||||||
'IntegerField': 'NUMBER(11)',
|
'IntegerField': 'NUMBER(11)',
|
||||||
'IPAddressField': 'VARCHAR2(15)',
|
'IPAddressField': 'VARCHAR2(15)',
|
||||||
'ManyToManyField': None,
|
|
||||||
'NullBooleanField': 'NUMBER(1) CHECK ((%(column)s IN (0,1)) OR (%(column)s IS NULL))',
|
'NullBooleanField': 'NUMBER(1) CHECK ((%(column)s IN (0,1)) OR (%(column)s IS NULL))',
|
||||||
'OneToOneField': 'NUMBER(11)',
|
'OneToOneField': 'NUMBER(11)',
|
||||||
'PhoneNumberField': 'VARCHAR2(20)',
|
'PhoneNumberField': 'VARCHAR2(20)',
|
||||||
|
@ -5,8 +5,8 @@
|
|||||||
DATA_TYPES = {
|
DATA_TYPES = {
|
||||||
'AutoField': 'serial',
|
'AutoField': 'serial',
|
||||||
'BooleanField': 'boolean',
|
'BooleanField': 'boolean',
|
||||||
'CharField': 'varchar(%(maxlength)s)',
|
'CharField': 'varchar(%(max_length)s)',
|
||||||
'CommaSeparatedIntegerField': 'varchar(%(maxlength)s)',
|
'CommaSeparatedIntegerField': 'varchar(%(max_length)s)',
|
||||||
'DateField': 'date',
|
'DateField': 'date',
|
||||||
'DateTimeField': 'timestamp with time zone',
|
'DateTimeField': 'timestamp with time zone',
|
||||||
'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)',
|
'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)',
|
||||||
@ -16,13 +16,12 @@ DATA_TYPES = {
|
|||||||
'ImageField': 'varchar(100)',
|
'ImageField': 'varchar(100)',
|
||||||
'IntegerField': 'integer',
|
'IntegerField': 'integer',
|
||||||
'IPAddressField': 'inet',
|
'IPAddressField': 'inet',
|
||||||
'ManyToManyField': None,
|
|
||||||
'NullBooleanField': 'boolean',
|
'NullBooleanField': 'boolean',
|
||||||
'OneToOneField': 'integer',
|
'OneToOneField': 'integer',
|
||||||
'PhoneNumberField': 'varchar(20)',
|
'PhoneNumberField': 'varchar(20)',
|
||||||
'PositiveIntegerField': 'integer CHECK ("%(column)s" >= 0)',
|
'PositiveIntegerField': 'integer CHECK ("%(column)s" >= 0)',
|
||||||
'PositiveSmallIntegerField': 'smallint CHECK ("%(column)s" >= 0)',
|
'PositiveSmallIntegerField': 'smallint CHECK ("%(column)s" >= 0)',
|
||||||
'SlugField': 'varchar(%(maxlength)s)',
|
'SlugField': 'varchar(%(max_length)s)',
|
||||||
'SmallIntegerField': 'smallint',
|
'SmallIntegerField': 'smallint',
|
||||||
'TextField': 'text',
|
'TextField': 'text',
|
||||||
'TimeField': 'time',
|
'TimeField': 'time',
|
||||||
|
@ -30,11 +30,8 @@ def get_relations(cursor, table_name):
|
|||||||
AND con.contype = 'f'""", [table_name])
|
AND con.contype = 'f'""", [table_name])
|
||||||
relations = {}
|
relations = {}
|
||||||
for row in cursor.fetchall():
|
for row in cursor.fetchall():
|
||||||
try:
|
# row[0] and row[1] are single-item lists, so grab the single item.
|
||||||
# row[0] and row[1] are like "{2}", so strip the curly braces.
|
relations[row[0][0] - 1] = (row[1][0] - 1, row[2])
|
||||||
relations[int(row[0][1:-1]) - 1] = (int(row[1][1:-1]) - 1, row[2])
|
|
||||||
except ValueError:
|
|
||||||
continue
|
|
||||||
return relations
|
return relations
|
||||||
|
|
||||||
def get_indexes(cursor, table_name):
|
def get_indexes(cursor, table_name):
|
||||||
|
@ -4,8 +4,8 @@
|
|||||||
DATA_TYPES = {
|
DATA_TYPES = {
|
||||||
'AutoField': 'integer',
|
'AutoField': 'integer',
|
||||||
'BooleanField': 'bool',
|
'BooleanField': 'bool',
|
||||||
'CharField': 'varchar(%(maxlength)s)',
|
'CharField': 'varchar(%(max_length)s)',
|
||||||
'CommaSeparatedIntegerField': 'varchar(%(maxlength)s)',
|
'CommaSeparatedIntegerField': 'varchar(%(max_length)s)',
|
||||||
'DateField': 'date',
|
'DateField': 'date',
|
||||||
'DateTimeField': 'datetime',
|
'DateTimeField': 'datetime',
|
||||||
'DecimalField': 'decimal',
|
'DecimalField': 'decimal',
|
||||||
@ -15,13 +15,12 @@ DATA_TYPES = {
|
|||||||
'ImageField': 'varchar(100)',
|
'ImageField': 'varchar(100)',
|
||||||
'IntegerField': 'integer',
|
'IntegerField': 'integer',
|
||||||
'IPAddressField': 'char(15)',
|
'IPAddressField': 'char(15)',
|
||||||
'ManyToManyField': None,
|
|
||||||
'NullBooleanField': 'bool',
|
'NullBooleanField': 'bool',
|
||||||
'OneToOneField': 'integer',
|
'OneToOneField': 'integer',
|
||||||
'PhoneNumberField': 'varchar(20)',
|
'PhoneNumberField': 'varchar(20)',
|
||||||
'PositiveIntegerField': 'integer unsigned',
|
'PositiveIntegerField': 'integer unsigned',
|
||||||
'PositiveSmallIntegerField': 'smallint unsigned',
|
'PositiveSmallIntegerField': 'smallint unsigned',
|
||||||
'SlugField': 'varchar(%(maxlength)s)',
|
'SlugField': 'varchar(%(max_length)s)',
|
||||||
'SmallIntegerField': 'smallint',
|
'SmallIntegerField': 'smallint',
|
||||||
'TextField': 'text',
|
'TextField': 'text',
|
||||||
'TimeField': 'time',
|
'TimeField': 'time',
|
||||||
|
@ -81,7 +81,7 @@ class FlexibleFieldLookupDict:
|
|||||||
import re
|
import re
|
||||||
m = re.search(r'^\s*(?:var)?char\s*\(\s*(\d+)\s*\)\s*$', key)
|
m = re.search(r'^\s*(?:var)?char\s*\(\s*(\d+)\s*\)\s*$', key)
|
||||||
if m:
|
if m:
|
||||||
return ('CharField', {'maxlength': int(m.group(1))})
|
return ('CharField', {'max_length': int(m.group(1))})
|
||||||
raise KeyError
|
raise KeyError
|
||||||
|
|
||||||
DATA_TYPES_REVERSE = FlexibleFieldLookupDict()
|
DATA_TYPES_REVERSE = FlexibleFieldLookupDict()
|
||||||
|
@ -15,14 +15,18 @@ from django.utils.text import capfirst
|
|||||||
# Admin stages.
|
# Admin stages.
|
||||||
ADD, CHANGE, BOTH = 1, 2, 3
|
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):
|
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
|
from django.core.urlresolvers import reverse
|
||||||
def inner(*args, **kwargs):
|
def inner(*args, **kwargs):
|
||||||
bits = func(*args, **kwargs)
|
bits = func(*args, **kwargs)
|
||||||
viewname = bits[0]
|
|
||||||
return reverse(bits[0], None, *bits[1:3])
|
return reverse(bits[0], None, *bits[1:3])
|
||||||
return inner
|
return inner
|
||||||
|
@ -206,7 +206,7 @@ class Model(object):
|
|||||||
|
|
||||||
_prepare = classmethod(_prepare)
|
_prepare = classmethod(_prepare)
|
||||||
|
|
||||||
def save(self):
|
def save(self, raw=False):
|
||||||
dispatcher.send(signal=signals.pre_save, sender=self.__class__, instance=self)
|
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]
|
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))
|
self._meta.pk.get_db_prep_lookup('exact', pk_val))
|
||||||
# If it does already exist, do an UPDATE.
|
# If it does already exist, do an UPDATE.
|
||||||
if cursor.fetchone()[0] > 0:
|
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:
|
if db_values:
|
||||||
cursor.execute("UPDATE %s SET %s WHERE %s=%%s" % \
|
cursor.execute("UPDATE %s SET %s WHERE %s=%%s" % \
|
||||||
(backend.quote_name(self._meta.db_table),
|
(backend.quote_name(self._meta.db_table),
|
||||||
@ -234,11 +234,11 @@ class Model(object):
|
|||||||
record_exists = False
|
record_exists = False
|
||||||
if not pk_set or not record_exists:
|
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)]
|
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 the PK has been manually set, respect that.
|
||||||
if pk_set:
|
if pk_set:
|
||||||
field_names += [f.column for f in self._meta.fields if isinstance(f, AutoField)]
|
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)
|
placeholders = ['%s'] * len(field_names)
|
||||||
if self._meta.order_with_respect_to:
|
if self._meta.order_with_respect_to:
|
||||||
field_names.append(backend.quote_name('_order'))
|
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.db.models import signals
|
||||||
from django.dispatch import dispatcher
|
from django.dispatch import dispatcher
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
@ -10,6 +11,7 @@ from django.utils.itercompat import tee
|
|||||||
from django.utils.text import capfirst
|
from django.utils.text import capfirst
|
||||||
from django.utils.translation import ugettext_lazy, ugettext as _
|
from django.utils.translation import ugettext_lazy, ugettext as _
|
||||||
from django.utils.encoding import smart_unicode, force_unicode, smart_str
|
from django.utils.encoding import smart_unicode, force_unicode, smart_str
|
||||||
|
from django.utils.maxlength import LegacyMaxlength
|
||||||
import datetime, os, time
|
import datetime, os, time
|
||||||
try:
|
try:
|
||||||
import decimal
|
import decimal
|
||||||
@ -61,6 +63,9 @@ def manipulator_validator_unique(f, opts, self, field_data, all_data):
|
|||||||
# getattr(obj, opts.pk.attname)
|
# getattr(obj, opts.pk.attname)
|
||||||
|
|
||||||
class Field(object):
|
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
|
# Designates whether empty strings fundamentally are allowed at the
|
||||||
# database level.
|
# database level.
|
||||||
@ -70,7 +75,7 @@ class Field(object):
|
|||||||
creation_counter = 0
|
creation_counter = 0
|
||||||
|
|
||||||
def __init__(self, verbose_name=None, name=None, primary_key=False,
|
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,
|
core=False, rel=None, default=NOT_PROVIDED, editable=True, serialize=True,
|
||||||
unique_for_date=None, unique_for_month=None, unique_for_year=None,
|
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,
|
validator_list=None, choices=None, radio_admin=None, help_text='', db_column=None,
|
||||||
@ -78,7 +83,7 @@ class Field(object):
|
|||||||
self.name = name
|
self.name = name
|
||||||
self.verbose_name = verbose_name
|
self.verbose_name = verbose_name
|
||||||
self.primary_key = primary_key
|
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
|
self.blank, self.null = blank, null
|
||||||
# Oracle treats the empty string ('') as null, so coerce the null
|
# Oracle treats the empty string ('') as null, so coerce the null
|
||||||
# option whenever '' is a possible value.
|
# option whenever '' is a possible value.
|
||||||
@ -115,6 +120,30 @@ class Field(object):
|
|||||||
"""
|
"""
|
||||||
return value
|
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):
|
def validate_full(self, field_data, all_data):
|
||||||
"""
|
"""
|
||||||
Returns a list of errors for this field. This is the main interface,
|
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):
|
def prepare_field_objs_and_params(self, manipulator, name_prefix):
|
||||||
params = {'validator_list': self.validator_list[:]}
|
params = {'validator_list': self.validator_list[:]}
|
||||||
if self.maxlength and not self.choices: # Don't give SelectFields a maxlength parameter.
|
if self.max_length and not self.choices: # Don't give SelectFields a max_length parameter.
|
||||||
params['maxlength'] = self.maxlength
|
params['max_length'] = self.max_length
|
||||||
|
|
||||||
if self.choices:
|
if self.choices:
|
||||||
if self.radio_admin:
|
if self.radio_admin:
|
||||||
@ -349,6 +378,9 @@ class Field(object):
|
|||||||
return self._choices
|
return self._choices
|
||||||
choices = property(_get_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):
|
def formfield(self, form_class=forms.CharField, **kwargs):
|
||||||
"Returns a django.newforms.Field instance for this database Field."
|
"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}
|
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)
|
return smart_unicode(value)
|
||||||
|
|
||||||
def formfield(self, **kwargs):
|
def formfield(self, **kwargs):
|
||||||
defaults = {'max_length': self.maxlength}
|
defaults = {'max_length': self.max_length}
|
||||||
defaults.update(kwargs)
|
defaults.update(kwargs)
|
||||||
return super(CharField, self).formfield(**defaults)
|
return super(CharField, self).formfield(**defaults)
|
||||||
|
|
||||||
@ -593,7 +625,8 @@ class DecimalField(Field):
|
|||||||
try:
|
try:
|
||||||
return decimal.Decimal(value)
|
return decimal.Decimal(value)
|
||||||
except decimal.InvalidOperation:
|
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):
|
def _format(self, value):
|
||||||
if isinstance(value, basestring):
|
if isinstance(value, basestring):
|
||||||
@ -642,7 +675,7 @@ class DecimalField(Field):
|
|||||||
|
|
||||||
class EmailField(CharField):
|
class EmailField(CharField):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
kwargs['maxlength'] = 75
|
kwargs['max_length'] = 75
|
||||||
CharField.__init__(self, *args, **kwargs)
|
CharField.__init__(self, *args, **kwargs)
|
||||||
|
|
||||||
def get_internal_type(self):
|
def get_internal_type(self):
|
||||||
@ -664,6 +697,13 @@ class FileField(Field):
|
|||||||
self.upload_to = upload_to
|
self.upload_to = upload_to
|
||||||
Field.__init__(self, verbose_name, name, **kwargs)
|
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):
|
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)
|
field_list = Field.get_manipulator_fields(self, opts, manipulator, change, name_prefix, rel, follow)
|
||||||
if not self.blank:
|
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)))
|
f = os.path.join(self.get_directory_name(), get_valid_filename(os.path.basename(filename)))
|
||||||
return os.path.normpath(f)
|
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):
|
class FilePathField(Field):
|
||||||
def __init__(self, verbose_name=None, name=None, path='', match=None, recursive=False, **kwargs):
|
def __init__(self, verbose_name=None, name=None, path='', match=None, recursive=False, **kwargs):
|
||||||
self.path, self.match, self.recursive = path, match, recursive
|
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))
|
setattr(new_object, self.height_field, getattr(original_object, self.height_field))
|
||||||
new_object.save()
|
new_object.save()
|
||||||
|
|
||||||
|
def formfield(self, **kwargs):
|
||||||
|
defaults = {'form_class': forms.ImageField}
|
||||||
|
return super(ImageField, self).formfield(**defaults)
|
||||||
|
|
||||||
class IntegerField(Field):
|
class IntegerField(Field):
|
||||||
empty_strings_allowed = False
|
empty_strings_allowed = False
|
||||||
def get_manipulator_field_objs(self):
|
def get_manipulator_field_objs(self):
|
||||||
@ -801,7 +858,7 @@ class IntegerField(Field):
|
|||||||
class IPAddressField(Field):
|
class IPAddressField(Field):
|
||||||
empty_strings_allowed = False
|
empty_strings_allowed = False
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
kwargs['maxlength'] = 15
|
kwargs['max_length'] = 15
|
||||||
Field.__init__(self, *args, **kwargs)
|
Field.__init__(self, *args, **kwargs)
|
||||||
|
|
||||||
def get_manipulator_field_objs(self):
|
def get_manipulator_field_objs(self):
|
||||||
@ -854,7 +911,7 @@ class PositiveSmallIntegerField(IntegerField):
|
|||||||
|
|
||||||
class SlugField(Field):
|
class SlugField(Field):
|
||||||
def __init__(self, *args, **kwargs):
|
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)
|
kwargs.setdefault('validator_list', []).append(validators.isSlug)
|
||||||
# Set db_index=True unless it's been set manually.
|
# Set db_index=True unless it's been set manually.
|
||||||
if 'db_index' not in kwargs:
|
if 'db_index' not in kwargs:
|
||||||
@ -940,7 +997,7 @@ class TimeField(Field):
|
|||||||
|
|
||||||
class URLField(CharField):
|
class URLField(CharField):
|
||||||
def __init__(self, verbose_name=None, name=None, verify_exists=True, **kwargs):
|
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:
|
if verify_exists:
|
||||||
kwargs.setdefault('validator_list', []).append(validators.isExistingURL)
|
kwargs.setdefault('validator_list', []).append(validators.isExistingURL)
|
||||||
self.verify_exists = verify_exists
|
self.verify_exists = verify_exists
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
from django.db import backend, transaction
|
from django.db import backend, transaction
|
||||||
from django.db.models import signals, get_model
|
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.db.models.related import RelatedObject
|
||||||
from django.utils.text import capfirst
|
from django.utils.text import capfirst
|
||||||
from django.utils.translation import ugettext_lazy, string_concat, ungettext, ugettext as _
|
from django.utils.translation import ugettext_lazy, string_concat, ungettext, ugettext as _
|
||||||
@ -548,6 +548,16 @@ class ForeignKey(RelatedField, Field):
|
|||||||
defaults.update(kwargs)
|
defaults.update(kwargs)
|
||||||
return super(ForeignKey, self).formfield(**defaults)
|
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):
|
class OneToOneField(RelatedField, IntegerField):
|
||||||
def __init__(self, to, to_field=None, **kwargs):
|
def __init__(self, to, to_field=None, **kwargs):
|
||||||
try:
|
try:
|
||||||
@ -609,6 +619,16 @@ class OneToOneField(RelatedField, IntegerField):
|
|||||||
defaults.update(kwargs)
|
defaults.update(kwargs)
|
||||||
return super(OneToOneField, self).formfield(**defaults)
|
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):
|
class ManyToManyField(RelatedField, Field):
|
||||||
def __init__(self, to, **kwargs):
|
def __init__(self, to, **kwargs):
|
||||||
kwargs['verbose_name'] = kwargs.get('verbose_name', None)
|
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."
|
"Returns the value of this field in the given model instance."
|
||||||
return getattr(obj, self.attname).all()
|
return getattr(obj, self.attname).all()
|
||||||
|
|
||||||
|
def save_form_data(self, instance, data):
|
||||||
|
setattr(instance, self.attname, data)
|
||||||
|
|
||||||
def formfield(self, **kwargs):
|
def formfield(self, **kwargs):
|
||||||
defaults = {'form_class': forms.ModelMultipleChoiceField, 'queryset': self.rel.to._default_manager.all()}
|
defaults = {'form_class': forms.ModelMultipleChoiceField, 'queryset': self.rel.to._default_manager.all()}
|
||||||
defaults.update(kwargs)
|
defaults.update(kwargs)
|
||||||
@ -719,6 +742,11 @@ class ManyToManyField(RelatedField, Field):
|
|||||||
defaults['initial'] = [i._get_pk_val() for i in defaults['initial']]
|
defaults['initial'] = [i._get_pk_val() for i in defaults['initial']]
|
||||||
return super(ManyToManyField, self).formfield(**defaults)
|
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):
|
class ManyToOneRel(object):
|
||||||
def __init__(self, to, field_name, num_in_admin=3, min_num_in_admin=None,
|
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,
|
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 import signals
|
||||||
from django.db.models.fields import FieldDoesNotExist
|
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):
|
def ensure_default_manager(sender):
|
||||||
cls = sender
|
cls = sender
|
||||||
if not hasattr(cls, '_default_manager'):
|
if not hasattr(cls, '_default_manager'):
|
||||||
@ -47,7 +43,7 @@ class Manager(object):
|
|||||||
|
|
||||||
def get_query_set(self):
|
def get_query_set(self):
|
||||||
"""Returns a new QuerySet object. Subclasses can override this method
|
"""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)
|
return QuerySet(self.model)
|
||||||
|
|
||||||
|
@ -579,28 +579,36 @@ class ValuesQuerySet(QuerySet):
|
|||||||
except EmptyResultSet:
|
except EmptyResultSet:
|
||||||
raise StopIteration
|
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 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]
|
fields = [self.model._meta.get_field(f, many_to_many=False) for f in self._fields]
|
||||||
|
field_names = self._fields
|
||||||
else:
|
else:
|
||||||
fields = []
|
fields = []
|
||||||
|
field_names = []
|
||||||
for f in self._fields:
|
for f in self._fields:
|
||||||
if f in [field.name for field in self.model._meta.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))
|
fields.append(self.model._meta.get_field(f, many_to_many=False))
|
||||||
elif not self._select.has_key( f ):
|
field_names.append(f)
|
||||||
raise FieldDoesNotExist, '%s has no field named %r' % ( self.model._meta.object_name, f )
|
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
|
|
||||||
else: # Default to all fields.
|
else: # Default to all fields.
|
||||||
fields = self.model._meta.fields
|
fields = self.model._meta.fields
|
||||||
field_names = [f.attname for f in fields]
|
field_names = [f.attname for f in fields]
|
||||||
|
|
||||||
columns = [f.column 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]
|
select = ['%s.%s' % (backend.quote_name(self.model._meta.db_table), backend.quote_name(c)) for c in columns]
|
||||||
# Add any additional SELECTs.
|
if extra_select:
|
||||||
if self._select:
|
select.extend(['(%s) AS %s' % (quote_only_if_word(s[1]), backend.quote_name(s[0])) for s in extra_select])
|
||||||
select.extend(['(%s) AS %s' % (quote_only_if_word(s[1]), backend.quote_name(s[0])) for s in self._select.items()])
|
field_names.extend([f[0] for f in extra_select])
|
||||||
|
|
||||||
cursor = connection.cursor()
|
cursor = connection.cursor()
|
||||||
cursor.execute("SELECT " + (self._distinct and "DISTINCT " or "") + ",".join(select) + sql, params)
|
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
|
# *Important*: do not import settings any earlier because of note
|
||||||
# in core.handlers.modpython.
|
# in core.handlers.modpython.
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
self.encoding = settings.DEFAULT_CHARSET
|
encoding = settings.DEFAULT_CHARSET
|
||||||
else:
|
self.encoding = encoding
|
||||||
self.encoding = encoding
|
|
||||||
self._mutable = True
|
self._mutable = True
|
||||||
for key, value in parse_qsl((query_string or ''), True): # keep_blank_values=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
|
self._mutable = mutable
|
||||||
|
|
||||||
def _assert_mutable(self):
|
def _assert_mutable(self):
|
||||||
|
@ -39,7 +39,7 @@ class CommonMiddleware(object):
|
|||||||
new_url[0] = 'www.' + old_url[0]
|
new_url[0] = 'www.' + old_url[0]
|
||||||
# Append a slash if append_slash is set and the URL doesn't have a
|
# Append a slash if append_slash is set and the URL doesn't have a
|
||||||
# trailing slash or a file extension.
|
# 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] + '/'
|
new_url[1] = new_url[1] + '/'
|
||||||
if settings.DEBUG and request.method == 'POST':
|
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])
|
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):
|
class ConditionalGetMiddleware(object):
|
||||||
"""
|
"""
|
||||||
@ -11,8 +11,7 @@ class ConditionalGetMiddleware(object):
|
|||||||
Also sets the Date and Content-Length response-headers.
|
Also sets the Date and Content-Length response-headers.
|
||||||
"""
|
"""
|
||||||
def process_response(self, request, response):
|
def process_response(self, request, response):
|
||||||
now = datetime.datetime.utcnow()
|
response['Date'] = formatdate()[:26] + "GMT"
|
||||||
response['Date'] = now.strftime('%a, %d %b %Y %H:%M:%S GMT')
|
|
||||||
if not response.has_header('Content-Length'):
|
if not response.has_header('Content-Length'):
|
||||||
response['Content-Length'] = str(len(response.content))
|
response['Content-Length'] = str(len(response.content))
|
||||||
|
|
||||||
|
@ -53,7 +53,7 @@ class SelectDateWidget(Widget):
|
|||||||
|
|
||||||
return u'\n'.join(output)
|
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)
|
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:
|
if y and m and d:
|
||||||
return '%s-%s-%s' % (y, m, d)
|
return '%s-%s-%s' % (y, m, d)
|
||||||
|
@ -7,17 +7,22 @@ import re
|
|||||||
import time
|
import time
|
||||||
|
|
||||||
from django.utils.translation import ugettext
|
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 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__ = (
|
__all__ = (
|
||||||
'Field', 'CharField', 'IntegerField',
|
'Field', 'CharField', 'IntegerField',
|
||||||
'DEFAULT_DATE_INPUT_FORMATS', 'DateField',
|
'DEFAULT_DATE_INPUT_FORMATS', 'DateField',
|
||||||
'DEFAULT_TIME_INPUT_FORMATS', 'TimeField',
|
'DEFAULT_TIME_INPUT_FORMATS', 'TimeField',
|
||||||
'DEFAULT_DATETIME_INPUT_FORMATS', 'DateTimeField',
|
'DEFAULT_DATETIME_INPUT_FORMATS', 'DateTimeField',
|
||||||
'RegexField', 'EmailField', 'URLField', 'BooleanField',
|
'RegexField', 'EmailField', 'FileField', 'ImageField', 'URLField', 'BooleanField',
|
||||||
'ChoiceField', 'NullBooleanField', 'MultipleChoiceField',
|
'ChoiceField', 'NullBooleanField', 'MultipleChoiceField',
|
||||||
'ComboField', 'MultiValueField', 'FloatField', 'DecimalField',
|
'ComboField', 'MultiValueField', 'FloatField', 'DecimalField',
|
||||||
'SplitDateTimeField',
|
'SplitDateTimeField',
|
||||||
@ -106,14 +111,16 @@ class CharField(Field):
|
|||||||
if value in EMPTY_VALUES:
|
if value in EMPTY_VALUES:
|
||||||
return u''
|
return u''
|
||||||
value = smart_unicode(value)
|
value = smart_unicode(value)
|
||||||
if self.max_length is not None and len(value) > self.max_length:
|
value_length = len(value)
|
||||||
raise ValidationError(ugettext(u'Ensure this value has at most %d characters.') % self.max_length)
|
if self.max_length is not None and value_length > 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 most %(max)d characters (it has %(length)d).') % {'max': self.max_length, 'length': value_length})
|
||||||
raise ValidationError(ugettext(u'Ensure this value has at least %d characters.') % self.min_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
|
return value
|
||||||
|
|
||||||
def widget_attrs(self, widget):
|
def widget_attrs(self, widget):
|
||||||
if self.max_length is not None and isinstance(widget, (TextInput, PasswordInput)):
|
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)}
|
return {'maxlength': str(self.max_length)}
|
||||||
|
|
||||||
class IntegerField(Field):
|
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)
|
raise ValidationError(ugettext('Ensure this value is greater than or equal to %s.') % self.min_value)
|
||||||
return value
|
return value
|
||||||
|
|
||||||
decimal_re = re.compile(r'^-?(?P<digits>\d+)(\.(?P<decimals>\d+))?$')
|
|
||||||
|
|
||||||
class DecimalField(Field):
|
class DecimalField(Field):
|
||||||
def __init__(self, max_value=None, min_value=None, max_digits=None, decimal_places=None, *args, **kwargs):
|
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
|
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:
|
if not self.required and value in EMPTY_VALUES:
|
||||||
return None
|
return None
|
||||||
value = value.strip()
|
value = value.strip()
|
||||||
match = decimal_re.search(value)
|
try:
|
||||||
if not match:
|
|
||||||
raise ValidationError(ugettext('Enter a number.'))
|
|
||||||
else:
|
|
||||||
value = Decimal(value)
|
value = Decimal(value)
|
||||||
digits = len(match.group('digits') or '')
|
except DecimalException:
|
||||||
decimals = len(match.group('decimals') or '')
|
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:
|
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)
|
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:
|
if self.min_value is not None and value < self.min_value:
|
||||||
@ -295,18 +300,17 @@ class DateTimeField(Field):
|
|||||||
continue
|
continue
|
||||||
raise ValidationError(ugettext(u'Enter a valid date/time.'))
|
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):
|
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.
|
regex can be either a string or a compiled regular expression object.
|
||||||
error_message is an optional error message to use, if
|
error_message is an optional error message to use, if
|
||||||
'Enter a valid value' is too generic for you.
|
'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):
|
if isinstance(regex, basestring):
|
||||||
regex = re.compile(regex)
|
regex = re.compile(regex)
|
||||||
self.regex = 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.')
|
self.error_message = error_message or ugettext(u'Enter a valid value.')
|
||||||
|
|
||||||
def clean(self, value):
|
def clean(self, value):
|
||||||
@ -314,16 +318,9 @@ class RegexField(Field):
|
|||||||
Validates that the input matches the regular expression. Returns a
|
Validates that the input matches the regular expression. Returns a
|
||||||
Unicode object.
|
Unicode object.
|
||||||
"""
|
"""
|
||||||
super(RegexField, self).clean(value)
|
value = super(RegexField, self).clean(value)
|
||||||
if value in EMPTY_VALUES:
|
|
||||||
value = u''
|
|
||||||
value = smart_unicode(value)
|
|
||||||
if value == u'':
|
if value == u'':
|
||||||
return value
|
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):
|
if not self.regex.search(value):
|
||||||
raise ValidationError(self.error_message)
|
raise ValidationError(self.error_message)
|
||||||
return value
|
return value
|
||||||
@ -351,6 +348,55 @@ except ImportError:
|
|||||||
# It's OK if Django settings aren't configured.
|
# It's OK if Django settings aren't configured.
|
||||||
URL_VALIDATOR_USER_AGENT = 'Django (http://www.djangoproject.com/)'
|
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):
|
class URLField(RegexField):
|
||||||
def __init__(self, max_length=None, min_length=None, verify_exists=False,
|
def __init__(self, max_length=None, min_length=None, verify_exists=False,
|
||||||
validator_user_agent=URL_VALIDATOR_USER_AGENT, *args, **kwargs):
|
validator_user_agent=URL_VALIDATOR_USER_AGENT, *args, **kwargs):
|
||||||
@ -446,10 +492,7 @@ class MultipleChoiceField(ChoiceField):
|
|||||||
return []
|
return []
|
||||||
if not isinstance(value, (list, tuple)):
|
if not isinstance(value, (list, tuple)):
|
||||||
raise ValidationError(ugettext(u'Enter a list of values.'))
|
raise ValidationError(ugettext(u'Enter a list of values.'))
|
||||||
new_value = []
|
new_value = [smart_unicode(val) for val in value]
|
||||||
for val in value:
|
|
||||||
val = smart_unicode(val)
|
|
||||||
new_value.append(val)
|
|
||||||
# Validate that each value in the value list is in self.choices.
|
# Validate that each value in the value list is in self.choices.
|
||||||
valid_values = set([smart_unicode(k) for k, v in self.choices])
|
valid_values = set([smart_unicode(k) for k, v in self.choices])
|
||||||
for val in new_value:
|
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
|
# 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*
|
# information. Any improvements to the form API should be made to *this*
|
||||||
# class, not to the Form class.
|
# class, not to the Form class.
|
||||||
def __init__(self, data=None, auto_id='id_%s', prefix=None, initial=None):
|
def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None, initial=None):
|
||||||
self.is_bound = data is not None
|
self.is_bound = data is not None or files is not None
|
||||||
self.data = data or {}
|
self.data = data or {}
|
||||||
|
self.files = files or {}
|
||||||
self.auto_id = auto_id
|
self.auto_id = auto_id
|
||||||
self.prefix = prefix
|
self.prefix = prefix
|
||||||
self.initial = initial or {}
|
self.initial = initial or {}
|
||||||
@ -88,7 +89,7 @@ class BaseForm(StrAndUnicode):
|
|||||||
return BoundField(self, field, name)
|
return BoundField(self, field, name)
|
||||||
|
|
||||||
def _get_errors(self):
|
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:
|
if self._errors is None:
|
||||||
self.full_clean()
|
self.full_clean()
|
||||||
return self._errors
|
return self._errors
|
||||||
@ -182,7 +183,7 @@ class BaseForm(StrAndUnicode):
|
|||||||
# value_from_datadict() gets the data from the dictionary.
|
# value_from_datadict() gets the data from the dictionary.
|
||||||
# Each widget type knows how to retrieve its own data, because some
|
# Each widget type knows how to retrieve its own data, because some
|
||||||
# widgets split data over several HTML fields.
|
# 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.
|
# HACK: ['', ''] and [None, None] deal with SplitDateTimeWidget. This should be more robust.
|
||||||
if value not in (None, '', ['', ''], [None, None]):
|
if value not in (None, '', ['', ''], [None, None]):
|
||||||
return False
|
return False
|
||||||
@ -198,10 +199,10 @@ class BaseForm(StrAndUnicode):
|
|||||||
return
|
return
|
||||||
self.cleaned_data = {}
|
self.cleaned_data = {}
|
||||||
for name, field in self.fields.items():
|
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
|
# Each widget type knows how to retrieve its own data, because some
|
||||||
# widgets split data over several HTML fields.
|
# 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:
|
try:
|
||||||
value = field.clean(value)
|
value = field.clean(value)
|
||||||
self.cleaned_data[name] = value
|
self.cleaned_data[name] = value
|
||||||
@ -257,16 +258,8 @@ class BoundField(StrAndUnicode):
|
|||||||
self.help_text = field.help_text or ''
|
self.help_text = field.help_text or ''
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
"Renders this field as an HTML widget."
|
"""Renders this field as an HTML widget."""
|
||||||
# Use the 'widget' attribute on the field to determine which type
|
return self.as_widget()
|
||||||
# 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
|
|
||||||
|
|
||||||
def _errors(self):
|
def _errors(self):
|
||||||
"""
|
"""
|
||||||
@ -276,7 +269,14 @@ class BoundField(StrAndUnicode):
|
|||||||
return self.form.errors.get(self.name, ErrorList())
|
return self.form.errors.get(self.name, ErrorList())
|
||||||
errors = property(_errors)
|
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 {}
|
attrs = attrs or {}
|
||||||
auto_id = self.auto_id
|
auto_id = self.auto_id
|
||||||
if auto_id and 'id' not in attrs and 'id' not in widget.attrs:
|
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.
|
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)
|
data = property(_data)
|
||||||
|
|
||||||
def label_tag(self, contents=None, attrs=None):
|
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
|
continue
|
||||||
if fields and f.name not in fields:
|
if fields and f.name not in fields:
|
||||||
continue
|
continue
|
||||||
setattr(instance, f.name, cleaned_data[f.name])
|
f.save_form_data(instance, cleaned_data[f.name])
|
||||||
if commit:
|
# Wrap up the saving of m2m data as a function
|
||||||
instance.save()
|
def save_m2m():
|
||||||
|
opts = instance.__class__._meta
|
||||||
|
cleaned_data = form.cleaned_data
|
||||||
for f in opts.many_to_many:
|
for f in opts.many_to_many:
|
||||||
if fields and f.name not in fields:
|
if fields and f.name not in fields:
|
||||||
continue
|
continue
|
||||||
if f.name in cleaned_data:
|
if f.name in cleaned_data:
|
||||||
setattr(instance, f.attname, cleaned_data[f.name])
|
f.save_form_data(instance, cleaned_data[f.name])
|
||||||
# GOTCHA: If many-to-many data is given and commit=False, the many-to-many
|
if commit:
|
||||||
# data will be lost. This happens because a many-to-many options cannot be
|
# If we are committing, save the instance and the m2m data immediately
|
||||||
# set on an object until after it's saved. Maybe we should raise an
|
instance.save()
|
||||||
# exception in that case.
|
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
|
return instance
|
||||||
|
|
||||||
def make_model_save(model, fields, fail_message):
|
def make_model_save(model, fields, fail_message):
|
||||||
|
@ -47,7 +47,7 @@ class Widget(object):
|
|||||||
attrs.update(extra_attrs)
|
attrs.update(extra_attrs)
|
||||||
return 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
|
Given a dictionary of data and this widget's name, returns the value
|
||||||
of this widget. Returns None if it's not provided.
|
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)
|
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])
|
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):
|
if isinstance(data, MultiValueDict):
|
||||||
return data.getlist(name)
|
return data.getlist(name)
|
||||||
return data.get(name, None)
|
return data.get(name, None)
|
||||||
@ -121,6 +121,13 @@ class MultipleHiddenInput(HiddenInput):
|
|||||||
class FileInput(Input):
|
class FileInput(Input):
|
||||||
input_type = 'file'
|
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):
|
class Textarea(Widget):
|
||||||
def __init__(self, attrs=None):
|
def __init__(self, attrs=None):
|
||||||
# The 'rows' and 'cols' attributes are required for HTML correctness.
|
# The 'rows' and 'cols' attributes are required for HTML correctness.
|
||||||
@ -188,7 +195,7 @@ class NullBooleanSelect(Select):
|
|||||||
value = u'1'
|
value = u'1'
|
||||||
return super(NullBooleanSelect, self).render(name, value, attrs, choices)
|
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)
|
value = data.get(name, None)
|
||||||
return {u'2': True, u'3': False, True: True, False: False}.get(value, 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>')
|
output.append(u'</select>')
|
||||||
return u'\n'.join(output)
|
return u'\n'.join(output)
|
||||||
|
|
||||||
def value_from_datadict(self, data, name):
|
def value_from_datadict(self, data, files, name):
|
||||||
if isinstance(data, MultiValueDict):
|
if isinstance(data, MultiValueDict):
|
||||||
return data.getlist(name)
|
return data.getlist(name)
|
||||||
return data.get(name, None)
|
return data.get(name, None)
|
||||||
|
|
||||||
class RadioInput(StrAndUnicode):
|
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):
|
def __init__(self, name, value, attrs, choice, index):
|
||||||
self.name, self.value = name, value
|
self.name, self.value = name, value
|
||||||
self.attrs = attrs
|
self.attrs = attrs
|
||||||
@ -239,7 +250,10 @@ class RadioInput(StrAndUnicode):
|
|||||||
return u'<input%s />' % flatatt(final_attrs)
|
return u'<input%s />' % flatatt(final_attrs)
|
||||||
|
|
||||||
class RadioFieldRenderer(StrAndUnicode):
|
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):
|
def __init__(self, name, value, attrs, choices):
|
||||||
self.name, self.value, self.attrs = name, value, attrs
|
self.name, self.value, self.attrs = name, value, attrs
|
||||||
self.choices = choices
|
self.choices = choices
|
||||||
@ -253,16 +267,30 @@ class RadioFieldRenderer(StrAndUnicode):
|
|||||||
return RadioInput(self.name, self.value, self.attrs.copy(), choice, idx)
|
return RadioInput(self.name, self.value, self.attrs.copy(), choice, idx)
|
||||||
|
|
||||||
def __unicode__(self):
|
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])
|
return u'<ul>\n%s\n</ul>' % u'\n'.join([u'<li>%s</li>' % force_unicode(w) for w in self])
|
||||||
|
|
||||||
class RadioSelect(Select):
|
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 = ''
|
if value is None: value = ''
|
||||||
str_value = force_unicode(value) # Normalize to string.
|
str_value = force_unicode(value) # Normalize to string.
|
||||||
final_attrs = self.build_attrs(attrs)
|
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_):
|
def id_for_label(self, id_):
|
||||||
# RadioSelect is represented by multiple <input type="radio"> fields,
|
# RadioSelect is represented by multiple <input type="radio"> fields,
|
||||||
@ -356,8 +384,8 @@ class MultiWidget(Widget):
|
|||||||
return id_
|
return id_
|
||||||
id_for_label = classmethod(id_for_label)
|
id_for_label = classmethod(id_for_label)
|
||||||
|
|
||||||
def value_from_datadict(self, data, name):
|
def value_from_datadict(self, data, files, name):
|
||||||
return [widget.value_from_datadict(data, name + '_%s' % i) for i, widget in enumerate(self.widgets)]
|
return [widget.value_from_datadict(data, files, name + '_%s' % i) for i, widget in enumerate(self.widgets)]
|
||||||
|
|
||||||
def format_output(self, rendered_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.utils.html import escape
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.utils.translation import ugettext, ungettext
|
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_'
|
FORM_FIELD_ID_PREFIX = 'id_'
|
||||||
|
|
||||||
@ -302,6 +303,9 @@ class FormField(object):
|
|||||||
Subclasses should also implement a render(data) method, which is responsible
|
Subclasses should also implement a render(data) method, which is responsible
|
||||||
for rending the form field in XHTML.
|
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):
|
def __str__(self):
|
||||||
return unicode(self).encode('utf-8')
|
return unicode(self).encode('utf-8')
|
||||||
@ -390,19 +394,19 @@ class FormField(object):
|
|||||||
|
|
||||||
class TextField(FormField):
|
class TextField(FormField):
|
||||||
input_type = "text"
|
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 = []
|
if validator_list is None: validator_list = []
|
||||||
self.field_name = field_name
|
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.is_required = is_required
|
||||||
self.validator_list = [self.isValidLength, self.hasNoNewlines] + validator_list
|
self.validator_list = [self.isValidLength, self.hasNoNewlines] + validator_list
|
||||||
if member_name != None:
|
if member_name != None:
|
||||||
self.member_name = member_name
|
self.member_name = member_name
|
||||||
|
|
||||||
def isValidLength(self, data, form):
|
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.",
|
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):
|
def hasNoNewlines(self, data, form):
|
||||||
if data and '\n' in data:
|
if data and '\n' in data:
|
||||||
@ -411,12 +415,12 @@ class TextField(FormField):
|
|||||||
def render(self, data):
|
def render(self, data):
|
||||||
if data is None:
|
if data is None:
|
||||||
data = u''
|
data = u''
|
||||||
maxlength = u''
|
max_length = u''
|
||||||
if self.maxlength:
|
if self.max_length:
|
||||||
maxlength = u'maxlength="%s" ' % self.maxlength
|
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/>' % \
|
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.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):
|
def html2python(data):
|
||||||
return data
|
return data
|
||||||
@ -426,14 +430,14 @@ class PasswordField(TextField):
|
|||||||
input_type = "password"
|
input_type = "password"
|
||||||
|
|
||||||
class LargeTextField(TextField):
|
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 = []
|
if validator_list is None: validator_list = []
|
||||||
self.field_name = field_name
|
self.field_name = field_name
|
||||||
self.rows, self.cols, self.is_required = rows, cols, is_required
|
self.rows, self.cols, self.is_required = rows, cols, is_required
|
||||||
self.validator_list = validator_list[:]
|
self.validator_list = validator_list[:]
|
||||||
if maxlength:
|
if max_length:
|
||||||
self.validator_list.append(self.isValidLength)
|
self.validator_list.append(self.isValidLength)
|
||||||
self.maxlength = maxlength
|
self.max_length = max_length
|
||||||
|
|
||||||
def render(self, data):
|
def render(self, data):
|
||||||
if data is None:
|
if data is None:
|
||||||
@ -502,7 +506,7 @@ class SelectField(FormField):
|
|||||||
|
|
||||||
def isValidChoice(self, data, form):
|
def isValidChoice(self, data, form):
|
||||||
str_data = smart_unicode(data)
|
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:
|
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}
|
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):
|
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 = []
|
if validator_list is None: validator_list = []
|
||||||
validator_list = [self.isInteger] + validator_list
|
validator_list = [self.isInteger] + validator_list
|
||||||
if member_name is not None:
|
if member_name is not None:
|
||||||
self.member_name = member_name
|
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):
|
def isInteger(self, field_data, all_data):
|
||||||
try:
|
try:
|
||||||
@ -730,57 +734,57 @@ class IntegerField(TextField):
|
|||||||
html2python = staticmethod(html2python)
|
html2python = staticmethod(html2python)
|
||||||
|
|
||||||
class SmallIntegerField(IntegerField):
|
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 = []
|
if validator_list is None: validator_list = []
|
||||||
validator_list = [self.isSmallInteger] + 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):
|
def isSmallInteger(self, field_data, all_data):
|
||||||
if not -32768 <= int(field_data) <= 32767:
|
if not -32768 <= int(field_data) <= 32767:
|
||||||
raise validators.CriticalValidationError, ugettext("Enter a whole number between -32,768 and 32,767.")
|
raise validators.CriticalValidationError, ugettext("Enter a whole number between -32,768 and 32,767.")
|
||||||
|
|
||||||
class PositiveIntegerField(IntegerField):
|
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 = []
|
if validator_list is None: validator_list = []
|
||||||
validator_list = [self.isPositive] + 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):
|
def isPositive(self, field_data, all_data):
|
||||||
if int(field_data) < 0:
|
if int(field_data) < 0:
|
||||||
raise validators.CriticalValidationError, ugettext("Enter a positive number.")
|
raise validators.CriticalValidationError, ugettext("Enter a positive number.")
|
||||||
|
|
||||||
class PositiveSmallIntegerField(IntegerField):
|
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 = []
|
if validator_list is None: validator_list = []
|
||||||
validator_list = [self.isPositiveSmall] + 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):
|
def isPositiveSmall(self, field_data, all_data):
|
||||||
if not 0 <= int(field_data) <= 32767:
|
if not 0 <= int(field_data) <= 32767:
|
||||||
raise validators.CriticalValidationError, ugettext("Enter a whole number between 0 and 32,767.")
|
raise validators.CriticalValidationError, ugettext("Enter a whole number between 0 and 32,767.")
|
||||||
|
|
||||||
class FloatField(TextField):
|
class FloatField(TextField):
|
||||||
def __init__(self, field_name, is_required=False, validator_list=None):
|
def __init__(self, field_name, is_required=False, validator_list=None):
|
||||||
if validator_list is None: validator_list = []
|
if validator_list is None: validator_list = []
|
||||||
validator_list = [validators.isValidFloat] + validator_list
|
validator_list = [validators.isValidFloat] + validator_list
|
||||||
TextField.__init__(self, field_name, is_required=is_required, validator_list=validator_list)
|
TextField.__init__(self, field_name, is_required=is_required, validator_list=validator_list)
|
||||||
|
|
||||||
def html2python(data):
|
def html2python(data):
|
||||||
if data == '' or data is None:
|
if data == '' or data is None:
|
||||||
return None
|
return None
|
||||||
return float(data)
|
return float(data)
|
||||||
html2python = staticmethod(html2python)
|
html2python = staticmethod(html2python)
|
||||||
|
|
||||||
class DecimalField(TextField):
|
class DecimalField(TextField):
|
||||||
def __init__(self, field_name, max_digits, decimal_places, is_required=False, validator_list=None):
|
def __init__(self, field_name, max_digits, decimal_places, is_required=False, validator_list=None):
|
||||||
if validator_list is None: validator_list = []
|
if validator_list is None: validator_list = []
|
||||||
self.max_digits, self.decimal_places = max_digits, decimal_places
|
self.max_digits, self.decimal_places = max_digits, decimal_places
|
||||||
validator_list = [self.isValidDecimal] + 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.
|
# 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)
|
super(DecimalField, self).__init__(field_name, max_digits+2, max_digits+2, is_required, validator_list)
|
||||||
|
|
||||||
def isValidDecimal(self, field_data, all_data):
|
def isValidDecimal(self, field_data, all_data):
|
||||||
v = validators.IsValidDecimal(self.max_digits, self.decimal_places)
|
v = validators.IsValidDecimal(self.max_digits, self.decimal_places)
|
||||||
try:
|
try:
|
||||||
v(field_data, all_data)
|
v(field_data, all_data)
|
||||||
except validators.ValidationError, e:
|
except validators.ValidationError, e:
|
||||||
@ -789,14 +793,14 @@ class DecimalField(TextField):
|
|||||||
def html2python(data):
|
def html2python(data):
|
||||||
if data == '' or data is None:
|
if data == '' or data is None:
|
||||||
return None
|
return None
|
||||||
try:
|
try:
|
||||||
import decimal
|
import decimal
|
||||||
except ImportError:
|
except ImportError:
|
||||||
from django.utils import _decimal as decimal
|
from django.utils import _decimal as decimal
|
||||||
try:
|
try:
|
||||||
return decimal.Decimal(data)
|
return decimal.Decimal(data)
|
||||||
except decimal.InvalidOperation, e:
|
except decimal.InvalidOperation, e:
|
||||||
raise ValueError, e
|
raise ValueError, e
|
||||||
html2python = staticmethod(html2python)
|
html2python = staticmethod(html2python)
|
||||||
|
|
||||||
####################
|
####################
|
||||||
@ -806,10 +810,10 @@ class DecimalField(TextField):
|
|||||||
class DatetimeField(TextField):
|
class DatetimeField(TextField):
|
||||||
"""A FormField that automatically converts its data to a datetime.datetime object.
|
"""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."""
|
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 = []
|
if validator_list is None: validator_list = []
|
||||||
self.field_name = field_name
|
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.is_required = is_required
|
||||||
self.validator_list = [validators.isValidANSIDatetime] + validator_list
|
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):
|
def __init__(self, field_name, is_required=False, validator_list=None):
|
||||||
if validator_list is None: validator_list = []
|
if validator_list is None: validator_list = []
|
||||||
validator_list = [self.isValidDate] + 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)
|
is_required=is_required, validator_list=validator_list)
|
||||||
|
|
||||||
def isValidDate(self, field_data, all_data):
|
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):
|
def __init__(self, field_name, is_required=False, validator_list=None):
|
||||||
if validator_list is None: validator_list = []
|
if validator_list is None: validator_list = []
|
||||||
validator_list = [self.isValidTime] + 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)
|
is_required=is_required, validator_list=validator_list)
|
||||||
|
|
||||||
def isValidTime(self, field_data, all_data):
|
def isValidTime(self, field_data, all_data):
|
||||||
@ -893,10 +897,10 @@ class TimeField(TextField):
|
|||||||
|
|
||||||
class EmailField(TextField):
|
class EmailField(TextField):
|
||||||
"A convenience FormField for validating e-mail addresses"
|
"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 = []
|
if validator_list is None: validator_list = []
|
||||||
validator_list = [self.isValidEmail] + 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)
|
is_required=is_required, validator_list=validator_list)
|
||||||
|
|
||||||
def isValidEmail(self, field_data, all_data):
|
def isValidEmail(self, field_data, all_data):
|
||||||
@ -907,10 +911,10 @@ class EmailField(TextField):
|
|||||||
|
|
||||||
class URLField(TextField):
|
class URLField(TextField):
|
||||||
"A convenience FormField for validating URLs"
|
"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 = []
|
if validator_list is None: validator_list = []
|
||||||
validator_list = [self.isValidURL] + 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)
|
is_required=is_required, validator_list=validator_list)
|
||||||
|
|
||||||
def isValidURL(self, field_data, all_data):
|
def isValidURL(self, field_data, all_data):
|
||||||
@ -920,10 +924,10 @@ class URLField(TextField):
|
|||||||
raise validators.CriticalValidationError, e.messages
|
raise validators.CriticalValidationError, e.messages
|
||||||
|
|
||||||
class IPAddressField(TextField):
|
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 = []
|
if validator_list is None: validator_list = []
|
||||||
validator_list = [self.isValidIPAddress] + 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)
|
is_required=is_required, validator_list=validator_list)
|
||||||
|
|
||||||
def isValidIPAddress(self, field_data, all_data):
|
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):
|
def __init__(self, field_name, is_required=False, validator_list=None):
|
||||||
if validator_list is None: validator_list = []
|
if validator_list is None: validator_list = []
|
||||||
validator_list = [self.isValidPhone] + 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)
|
is_required=is_required, validator_list=validator_list)
|
||||||
|
|
||||||
def isValidPhone(self, field_data, all_data):
|
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):
|
def __init__(self, field_name, is_required=False, validator_list=None):
|
||||||
if validator_list is None: validator_list = []
|
if validator_list is None: validator_list = []
|
||||||
validator_list = [self.isValidUSState] + 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)
|
is_required=is_required, validator_list=validator_list)
|
||||||
|
|
||||||
def isValidUSState(self, field_data, all_data):
|
def isValidUSState(self, field_data, all_data):
|
||||||
@ -1001,10 +1005,10 @@ class USStateField(TextField):
|
|||||||
|
|
||||||
class CommaSeparatedIntegerField(TextField):
|
class CommaSeparatedIntegerField(TextField):
|
||||||
"A convenience FormField for validating comma-separated integer fields"
|
"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 = []
|
if validator_list is None: validator_list = []
|
||||||
validator_list = [self.isCommaSeparatedIntegerList] + 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)
|
is_required=is_required, validator_list=validator_list)
|
||||||
|
|
||||||
def isCommaSeparatedIntegerList(self, field_data, all_data):
|
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
|
This module collects helper functions and classes that "span" multiple levels
|
||||||
# for convenience's sake.
|
of MVC. In other words, these functions/classes introduce controlled coupling
|
||||||
|
for convenience's sake.
|
||||||
|
"""
|
||||||
|
|
||||||
from django.template import loader
|
from django.template import loader
|
||||||
from django.http import HttpResponse, Http404
|
from django.http import HttpResponse, Http404
|
||||||
from django.db.models.manager import Manager
|
from django.db.models.manager import Manager
|
||||||
|
from django.db.models.query import QuerySet
|
||||||
|
|
||||||
def render_to_response(*args, **kwargs):
|
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))
|
return HttpResponse(loader.render_to_string(*args, **kwargs))
|
||||||
load_and_render = render_to_response # For backwards compatibility.
|
load_and_render = render_to_response # For backwards compatibility.
|
||||||
|
|
||||||
def get_object_or_404(klass, *args, **kwargs):
|
def _get_queryset(klass):
|
||||||
if isinstance(klass, Manager):
|
"""
|
||||||
|
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
|
manager = klass
|
||||||
klass = manager.model
|
|
||||||
else:
|
else:
|
||||||
manager = klass._default_manager
|
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:
|
try:
|
||||||
return manager.get(*args, **kwargs)
|
return queryset.get(*args, **kwargs)
|
||||||
except klass.DoesNotExist:
|
except queryset.model.DoesNotExist:
|
||||||
raise Http404('No %s matches the given query.' % klass._meta.object_name)
|
raise Http404('No %s matches the given query.' % queryset.model._meta.object_name)
|
||||||
|
|
||||||
def get_list_or_404(klass, *args, **kwargs):
|
def get_list_or_404(klass, *args, **kwargs):
|
||||||
if isinstance(klass, Manager):
|
"""
|
||||||
manager = klass
|
Uses filter() to return a list of objects, or raise a Http404 exception if
|
||||||
else:
|
the list is empty.
|
||||||
manager = klass._default_manager
|
|
||||||
obj_list = list(manager.filter(*args, **kwargs))
|
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:
|
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
|
return obj_list
|
||||||
|
@ -512,7 +512,7 @@ filter_raw_string = r"""
|
|||||||
)?
|
)?
|
||||||
)""" % {
|
)""" % {
|
||||||
'str': r"""[^"\\]*(?:\\.[^"\\]*)*""",
|
'str': r"""[^"\\]*(?:\\.[^"\\]*)*""",
|
||||||
'var_chars': "A-Za-z0-9\_\." ,
|
'var_chars': "\w\." ,
|
||||||
'filter_sep': re.escape(FILTER_SEPARATOR),
|
'filter_sep': re.escape(FILTER_SEPARATOR),
|
||||||
'arg_sep': re.escape(FILTER_ARGUMENT_SEPARATOR),
|
'arg_sep': re.escape(FILTER_ARGUMENT_SEPARATOR),
|
||||||
'i18n_open' : re.escape("_("),
|
'i18n_open' : re.escape("_("),
|
||||||
@ -520,7 +520,7 @@ filter_raw_string = r"""
|
|||||||
}
|
}
|
||||||
|
|
||||||
filter_raw_string = filter_raw_string.replace("\n", "").replace(" ", "")
|
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):
|
class FilterExpression(object):
|
||||||
"""
|
"""
|
||||||
|
@ -556,7 +556,7 @@ def pprint(value):
|
|||||||
try:
|
try:
|
||||||
return pformat(value)
|
return pformat(value)
|
||||||
except Exception, e:
|
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)
|
# Syntax: register.filter(name of filter, callback)
|
||||||
register.filter(add)
|
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
|
As you can see, the ``if`` tag can take an option ``{% else %}`` clause that
|
||||||
will be displayed if the test fails.
|
will be displayed if the test fails.
|
||||||
|
|
||||||
``if`` tags may use ``or`` or ``not`` to test a number of variables or to
|
``if`` tags may use ``or``, ``and`` or ``not`` to test a number of
|
||||||
negate a given variable::
|
variables or to negate a given variable::
|
||||||
|
|
||||||
{% if not athlete_list %}
|
{% if not athlete_list %}
|
||||||
There are no athletes.
|
There are no athletes.
|
||||||
@ -660,19 +660,32 @@ def do_if(parser, token):
|
|||||||
There are some athletes or some coaches.
|
There are some athletes or some coaches.
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
{% if athlete_list and coach_list %}
|
||||||
|
Both atheletes and coaches are available.
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{% if not athlete_list or coach_list %}
|
{% if not athlete_list or coach_list %}
|
||||||
There are no athletes, or there are some coaches.
|
There are no athletes, or there are some coaches.
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
For simplicity, ``if`` tags do not allow ``and`` clauses. Use nested ``if``
|
{% if athlete_list and not coach_list %}
|
||||||
tags instead::
|
There are some athletes and absolutely no coaches.
|
||||||
|
|
||||||
{% if athlete_list %}
|
|
||||||
{% if coach_list %}
|
|
||||||
Number of athletes: {{ athlete_list|count }}.
|
|
||||||
Number of coaches: {{ coach_list|count }}.
|
|
||||||
{% endif %}
|
|
||||||
{% endif %}
|
{% 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()
|
bits = token.contents.split()
|
||||||
del bits[0]
|
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.conf import settings
|
||||||
from django.core.exceptions import ImproperlyConfigured
|
from django.core.exceptions import ImproperlyConfigured
|
||||||
from django.template import TemplateDoesNotExist
|
from django.template import TemplateDoesNotExist
|
||||||
import os
|
from django.utils._os import safe_join
|
||||||
|
|
||||||
# At compile time, cache the directories to search.
|
# At compile time, cache the directories to search.
|
||||||
app_template_dirs = []
|
app_template_dirs = []
|
||||||
@ -28,8 +33,14 @@ for app in settings.INSTALLED_APPS:
|
|||||||
app_template_dirs = tuple(app_template_dirs)
|
app_template_dirs = tuple(app_template_dirs)
|
||||||
|
|
||||||
def get_template_sources(template_name, template_dirs=None):
|
def get_template_sources(template_name, template_dirs=None):
|
||||||
for template_dir in app_template_dirs:
|
if not template_dirs:
|
||||||
yield os.path.join(template_dir, template_name)
|
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):
|
def load_template_source(template_name, template_dirs=None):
|
||||||
for filepath in get_template_sources(template_name, template_dirs):
|
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.conf import settings
|
||||||
from django.template import TemplateDoesNotExist
|
from django.template import TemplateDoesNotExist
|
||||||
import os
|
from django.utils._os import safe_join
|
||||||
|
|
||||||
def get_template_sources(template_name, template_dirs=None):
|
def get_template_sources(template_name, template_dirs=None):
|
||||||
if not template_dirs:
|
if not template_dirs:
|
||||||
template_dirs = settings.TEMPLATE_DIRS
|
template_dirs = settings.TEMPLATE_DIRS
|
||||||
for template_dir in 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):
|
def load_template_source(template_name, template_dirs=None):
|
||||||
tried = []
|
tried = []
|
||||||
|
@ -195,7 +195,7 @@ class Client:
|
|||||||
'CONTENT_LENGTH': None,
|
'CONTENT_LENGTH': None,
|
||||||
'CONTENT_TYPE': 'text/html; charset=utf-8',
|
'CONTENT_TYPE': 'text/html; charset=utf-8',
|
||||||
'PATH_INFO': path,
|
'PATH_INFO': path,
|
||||||
'QUERY_STRING': urlencode(data),
|
'QUERY_STRING': urlencode(data, doseq=True),
|
||||||
'REQUEST_METHOD': 'GET',
|
'REQUEST_METHOD': 'GET',
|
||||||
}
|
}
|
||||||
r.update(extra)
|
r.update(extra)
|
||||||
@ -225,10 +225,11 @@ class Client:
|
|||||||
"""Set the Client to appear as if it has sucessfully logged into a site.
|
"""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
|
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)
|
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()
|
obj = Session.objects.get_new_session_object()
|
||||||
|
|
||||||
# Create a fake request to store login details
|
# Create a fake request to store login details
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import unittest
|
import unittest
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
from django.db.models import get_app, get_apps
|
||||||
from django.test import _doctest as doctest
|
from django.test import _doctest as doctest
|
||||||
from django.test.utils import setup_test_environment, teardown_test_environment
|
from django.test.utils import setup_test_environment, teardown_test_environment
|
||||||
from django.test.utils import create_test_db, destroy_test_db
|
from django.test.utils import create_test_db, destroy_test_db
|
||||||
@ -10,34 +11,10 @@ TEST_MODULE = 'tests'
|
|||||||
|
|
||||||
doctestOutputChecker = OutputChecker()
|
doctestOutputChecker = OutputChecker()
|
||||||
|
|
||||||
def build_suite(app_module):
|
def get_tests(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
|
|
||||||
try:
|
try:
|
||||||
app_path = app_module.__name__.split('.')[:-1]
|
app_path = app_module.__name__.split('.')[:-1]
|
||||||
test_module = __import__('.'.join(app_path + [TEST_MODULE]), {}, {}, TEST_MODULE)
|
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:
|
except ImportError, e:
|
||||||
# Couldn't import tests.py. Was it due to a missing file, or
|
# 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?
|
# 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__)])
|
mod = find_module(TEST_MODULE, [os.path.dirname(app_module.__file__)])
|
||||||
except ImportError:
|
except ImportError:
|
||||||
# 'tests' module doesn't exist. Move on.
|
# 'tests' module doesn't exist. Move on.
|
||||||
pass
|
test_module = None
|
||||||
else:
|
else:
|
||||||
# The module exists, so there must be an import error in the
|
# The module exists, so there must be an import error in the
|
||||||
# test module itself. We don't need the module; so if 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]:
|
if mod[0]:
|
||||||
mod[0].close()
|
mod[0].close()
|
||||||
raise
|
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
|
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.
|
parts = label.split('.')
|
||||||
This testrunner will search each of the modules in the provided list,
|
if len(parts) < 2 or len(parts) > 3:
|
||||||
looking for doctests and unittests in models.py or tests.py within
|
raise ValueError("Test label '%s' should be of the form app.TestCase or app.TestCase.test_method" % label)
|
||||||
the module. A list of 'extra' tests may also be provided; these tests
|
|
||||||
|
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.
|
will be added to the test suite.
|
||||||
|
|
||||||
Returns the number of tests that failed.
|
Returns the number of tests that failed.
|
||||||
@ -74,15 +123,23 @@ def run_tests(module_list, verbosity=1, extra_tests=[]):
|
|||||||
|
|
||||||
settings.DEBUG = False
|
settings.DEBUG = False
|
||||||
suite = unittest.TestSuite()
|
suite = unittest.TestSuite()
|
||||||
|
|
||||||
for module in module_list:
|
if test_labels:
|
||||||
suite.addTest(build_suite(module))
|
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:
|
for test in extra_tests:
|
||||||
suite.addTest(test)
|
suite.addTest(test)
|
||||||
|
|
||||||
old_name = settings.DATABASE_NAME
|
old_name = settings.DATABASE_NAME
|
||||||
create_test_db(verbosity)
|
create_test_db(verbosity, autoclobber=not interactive)
|
||||||
result = unittest.TextTestRunner(verbosity=verbosity).run(suite)
|
result = unittest.TextTestRunner(verbosity=verbosity).run(suite)
|
||||||
destroy_test_db(old_name, verbosity)
|
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