Ticket #1714: readonly-fields.diff
File readonly-fields.diff, 20.4 KB (added by , 19 years ago) |
---|
-
django/forms/__init__.py
a b class FormField: 361 361 "Returns the HTML 'id' attribute for this form field." 362 362 return FORM_FIELD_ID_PREFIX + self.field_name 363 363 364 def css_class(self): 365 readonly_label = '' 366 if self.readonly: 367 readonly_label = "Readonly" 368 return "v%s%s" % (readonly_label, self.__class__.__name__) 369 364 370 #################### 365 371 # GENERIC WIDGETS # 366 372 #################### 367 373 368 374 class TextField(FormField): 369 375 input_type = "text" 370 def __init__(self, field_name, length=30, maxlength=None, is_required=False, validator_list=[], member_name=None ):376 def __init__(self, field_name, length=30, maxlength=None, is_required=False, validator_list=[], member_name=None, readonly=False): 371 377 self.field_name = field_name 372 378 self.length, self.maxlength = length, maxlength 373 379 self.is_required = is_required 374 380 self.validator_list = [self.isValidLength, self.hasNoNewlines] + validator_list 375 381 if member_name != None: 376 382 self.member_name = member_name 383 self.readonly = readonly 377 384 378 385 def isValidLength(self, data, form): 379 386 if data and self.maxlength and len(data.decode(settings.DEFAULT_CHARSET)) > self.maxlength: … … class TextField(FormField): 388 395 if data is None: 389 396 data = '' 390 397 maxlength = '' 398 readonly = '' 391 399 if self.maxlength: 392 400 maxlength = 'maxlength="%s" ' % self.maxlength 401 if self.readonly: 402 readonly = 'readonly="readonly"' 393 403 if isinstance(data, unicode): 394 404 data = data.encode(settings.DEFAULT_CHARSET) 395 return '<input type="%s" id="%s" class=" v%s%s" name="%s" size="%s" value="%s"%s/>' % \396 (self.input_type, self.get_id(), self. __class__.__name__, self.is_required and ' required' or '',397 self.field_name, self.length, escape(data), maxlength )405 return '<input type="%s" id="%s" class="%s%s" name="%s" size="%s" value="%s" %s %s/>' % \ 406 (self.input_type, self.get_id(), self.css_class(), self.is_required and ' required' or '', 407 self.field_name, self.length, escape(data), maxlength, readonly) 398 408 399 409 def html2python(data): 400 410 return data … … class PasswordField(TextField): 404 414 input_type = "password" 405 415 406 416 class LargeTextField(TextField): 407 def __init__(self, field_name, rows=10, cols=40, is_required=False, validator_list=[], maxlength=None ):417 def __init__(self, field_name, rows=10, cols=40, is_required=False, validator_list=[], maxlength=None, readonly=False): 408 418 self.field_name = field_name 409 419 self.rows, self.cols, self.is_required = rows, cols, is_required 410 420 self.validator_list = validator_list[:] 411 421 if maxlength: 412 422 self.validator_list.append(self.isValidLength) 413 423 self.maxlength = maxlength 424 self.readonly = readonly 414 425 415 426 def render(self, data): 416 427 if data is None: 417 428 data = '' 418 429 if isinstance(data, unicode): 419 430 data = data.encode(settings.DEFAULT_CHARSET) 420 return '<textarea id="%s" class="v%s%s" name="%s" rows="%s" cols="%s">%s</textarea>' % \ 421 (self.get_id(), self.__class__.__name__, self.is_required and ' required' or '', 422 self.field_name, self.rows, self.cols, escape(data)) 431 readonly = '' 432 if self.readonly: 433 readonly = 'readonly="readonly"' 434 return '<textarea id="%s" class="%s%s" name="%s" rows="%s" cols="%s" %s>%s</textarea>' % \ 435 (self.get_id(), self.css_class(), self.is_required and ' required' or '', 436 self.field_name, self.rows, self.cols, readonly, escape(data)) 423 437 424 438 class HiddenField(FormField): 425 439 def __init__(self, field_name, is_required=False, validator_list=[]): … … class HiddenField(FormField): 431 445 (self.get_id(), self.field_name, escape(data)) 432 446 433 447 class CheckboxField(FormField): 434 def __init__(self, field_name, checked_by_default=False ):448 def __init__(self, field_name, checked_by_default=False, readonly=False): 435 449 self.field_name = field_name 436 450 self.checked_by_default = checked_by_default 437 451 self.is_required, self.validator_list = False, [] # because the validator looks for these 452 self.readonly = readonly 438 453 439 454 def render(self, data): 440 455 checked_html = '' 456 readonly = '' 457 if self.readonly: 458 readonly = ' disabled="disabled"' 441 459 if data or (data is '' and self.checked_by_default): 442 460 checked_html = ' checked="checked"' 443 return '<input type="checkbox" id="%s" class=" v%s" name="%s"%s/>' % \444 (self.get_id(), self. __class__.__name__,445 self.field_name, checked_html )461 return '<input type="checkbox" id="%s" class="%s" name="%s"%s%s/>' % \ 462 (self.get_id(), self.css_class(), 463 self.field_name, checked_html, readonly) 446 464 447 465 def html2python(data): 448 466 "Convert value from browser ('on' or '') to a Python boolean" … … class CheckboxField(FormField): 452 470 html2python = staticmethod(html2python) 453 471 454 472 class SelectField(FormField): 455 def __init__(self, field_name, choices=[], size=1, is_required=False, validator_list=[], member_name=None ):473 def __init__(self, field_name, choices=[], size=1, is_required=False, validator_list=[], member_name=None, readonly=False): 456 474 self.field_name = field_name 457 475 # choices is a list of (value, human-readable key) tuples because order matters 458 476 self.choices, self.size, self.is_required = choices, size, is_required 459 477 self.validator_list = [self.isValidChoice] + validator_list 478 self.readonly = readonly 460 479 if member_name != None: 461 480 self.member_name = member_name 462 481 463 482 def render(self, data): 464 output = ['<select id="%s" class="v%s%s" name="%s" size="%s">' % \ 465 (self.get_id(), self.__class__.__name__, 466 self.is_required and ' required' or '', self.field_name, self.size)] 483 disabled = '' 484 if self.readonly: 485 disabled='disabled="disabled"' 486 output = ['<select id="%s" class="%s%s" name="%s" size="%s" %s>' % \ 487 (self.get_id(), self.css_class(), 488 self.is_required and ' required' or '', self.field_name, self.size, 489 disabled)] 467 490 str_data = str(data) # normalize to string 468 491 for value, display_name in self.choices: 469 492 selected_html = '' … … class NullSelectField(SelectField): 488 511 html2python = staticmethod(html2python) 489 512 490 513 class RadioSelectField(FormField): 491 def __init__(self, field_name, choices=[], ul_class='', is_required=False, validator_list=[], member_name=None ):514 def __init__(self, field_name, choices=[], ul_class='', is_required=False, validator_list=[], member_name=None, readonly=False): 492 515 self.field_name = field_name 493 516 # choices is a list of (value, human-readable key) tuples because order matters 494 517 self.choices, self.is_required = choices, is_required 495 518 self.validator_list = [self.isValidChoice] + validator_list 496 519 self.ul_class = ul_class 520 self.readonly = readonly 497 521 if member_name != None: 498 522 self.member_name = member_name 499 523 … … class RadioSelectField(FormField): 532 556 str_data = str(data) # normalize to string 533 557 for i, (value, display_name) in enumerate(self.choices): 534 558 selected_html = '' 559 readonly = '' 535 560 if str(value) == str_data: 536 561 selected_html = ' checked="checked"' 562 if self.readonly: 563 readonly = 'readonly="readonly"' 537 564 datalist.append({ 538 565 'value': value, 539 566 'name': display_name, 540 'field': '<input type="radio" id="%s" name="%s" value="%s"%s />' % \541 (self.get_id() + '_' + str(i), self.field_name, value, selected_html ),567 'field': '<input type="radio" id="%s" name="%s" value="%s"%s %s/>' % \ 568 (self.get_id() + '_' + str(i), self.field_name, value, selected_html, readonly), 542 569 'label': '<label for="%s">%s</label>' % \ 543 570 (self.get_id() + '_' + str(i), display_name), 544 571 }) … … class RadioSelectField(FormField): 552 579 553 580 class NullBooleanField(SelectField): 554 581 "This SelectField provides 'Yes', 'No' and 'Unknown', mapping results to True, False or None" 555 def __init__(self, field_name, is_required=False, validator_list=[] ):582 def __init__(self, field_name, is_required=False, validator_list=[], readonly=False): 556 583 SelectField.__init__(self, field_name, choices=[('1', 'Unknown'), ('2', 'Yes'), ('3', 'No')], 557 is_required=is_required, validator_list=validator_list )584 is_required=is_required, validator_list=validator_list, readonly=readonly) 558 585 559 586 def render(self, data): 560 587 if data is None: data = '1' … … class CheckboxSelectMultipleField(Select 605 632 back into the single list that validators, renderers and save() expect. 606 633 """ 607 634 requires_data_list = True 608 def __init__(self, field_name, choices=[], validator_list=[] ):609 SelectMultipleField.__init__(self, field_name, choices, size=1, is_required=False, validator_list=validator_list )635 def __init__(self, field_name, choices=[], validator_list=[], readonly=False): 636 SelectMultipleField.__init__(self, field_name, choices, size=1, is_required=False, validator_list=validator_list, readonly=readonly) 610 637 611 638 def prepare(self, new_data): 612 639 # new_data has "split" this field into several fields, so flatten it … … # INTEGERS/FLOATS # 671 698 #################### 672 699 673 700 class IntegerField(TextField): 674 def __init__(self, field_name, length=10, maxlength=None, is_required=False, validator_list=[], member_name=None ):701 def __init__(self, field_name, length=10, maxlength=None, is_required=False, validator_list=[], member_name=None, readonly=False): 675 702 validator_list = [self.isInteger] + validator_list 676 703 if member_name is not None: 677 704 self.member_name = member_name 678 TextField.__init__(self, field_name, length, maxlength, is_required, validator_list )705 TextField.__init__(self, field_name, length, maxlength, is_required, validator_list, readonly) 679 706 680 707 def isInteger(self, field_data, all_data): 681 708 try: … … class IntegerField(TextField): 690 717 html2python = staticmethod(html2python) 691 718 692 719 class SmallIntegerField(IntegerField): 693 def __init__(self, field_name, length=5, maxlength=5, is_required=False, validator_list=[] ):720 def __init__(self, field_name, length=5, maxlength=5, is_required=False, validator_list=[], readonly=False): 694 721 validator_list = [self.isSmallInteger] + validator_list 695 IntegerField.__init__(self, field_name, length, maxlength, is_required, validator_list )722 IntegerField.__init__(self, field_name, length, maxlength, is_required, validator_list, readonly) 696 723 697 724 def isSmallInteger(self, field_data, all_data): 698 725 if not -32768 <= int(field_data) <= 32767: 699 726 raise validators.CriticalValidationError, gettext("Enter a whole number between -32,768 and 32,767.") 700 727 701 728 class PositiveIntegerField(IntegerField): 702 def __init__(self, field_name, length=10, maxlength=None, is_required=False, validator_list=[] ):729 def __init__(self, field_name, length=10, maxlength=None, is_required=False, validator_list=[], readonly=False): 703 730 validator_list = [self.isPositive] + validator_list 704 IntegerField.__init__(self, field_name, length, maxlength, is_required, validator_list )731 IntegerField.__init__(self, field_name, length, maxlength, is_required, validator_list, readonly) 705 732 706 733 def isPositive(self, field_data, all_data): 707 734 if int(field_data) < 0: 708 735 raise validators.CriticalValidationError, gettext("Enter a positive number.") 709 736 710 737 class PositiveSmallIntegerField(IntegerField): 711 def __init__(self, field_name, length=5, maxlength=None, is_required=False, validator_list=[] ):738 def __init__(self, field_name, length=5, maxlength=None, is_required=False, validator_list=[], readonly=False): 712 739 validator_list = [self.isPositiveSmall] + validator_list 713 IntegerField.__init__(self, field_name, length, maxlength, is_required, validator_list )740 IntegerField.__init__(self, field_name, length, maxlength, is_required, validator_list, readonly) 714 741 715 742 def isPositiveSmall(self, field_data, all_data): 716 743 if not 0 <= int(field_data) <= 32767: 717 744 raise validators.CriticalValidationError, gettext("Enter a whole number between 0 and 32,767.") 718 745 719 746 class FloatField(TextField): 720 def __init__(self, field_name, max_digits, decimal_places, is_required=False, validator_list=[] ):747 def __init__(self, field_name, max_digits, decimal_places, is_required=False, validator_list=[], readonly=False): 721 748 self.max_digits, self.decimal_places = max_digits, decimal_places 722 749 validator_list = [self.isValidFloat] + validator_list 723 TextField.__init__(self, field_name, max_digits+1, max_digits+1, is_required, validator_list )750 TextField.__init__(self, field_name, max_digits+1, max_digits+1, is_required, validator_list, readonly) 724 751 725 752 def isValidFloat(self, field_data, all_data): 726 753 v = validators.IsValidFloat(self.max_digits, self.decimal_places) … … #################### 742 769 class DatetimeField(TextField): 743 770 """A FormField that automatically converts its data to a datetime.datetime object. 744 771 The data should be in the format YYYY-MM-DD HH:MM:SS.""" 745 def __init__(self, field_name, length=30, maxlength=None, is_required=False, validator_list=[] ):772 def __init__(self, field_name, length=30, maxlength=None, is_required=False, validator_list=[], readonly=False): 746 773 self.field_name = field_name 747 774 self.length, self.maxlength = length, maxlength 748 775 self.is_required = is_required 749 776 self.validator_list = [validators.isValidANSIDatetime] + validator_list 777 self.readonly = readonly 750 778 751 779 def html2python(data): 752 780 "Converts the field into a datetime.datetime object" … … class DatetimeField(TextField): 765 793 class DateField(TextField): 766 794 """A FormField that automatically converts its data to a datetime.date object. 767 795 The data should be in the format YYYY-MM-DD.""" 768 def __init__(self, field_name, is_required=False, validator_list=[] ):796 def __init__(self, field_name, is_required=False, validator_list=[], readonly=False): 769 797 validator_list = [self.isValidDate] + validator_list 770 798 TextField.__init__(self, field_name, length=10, maxlength=10, 771 is_required=is_required, validator_list=validator_list )799 is_required=is_required, validator_list=validator_list, readonly=readonly) 772 800 773 801 def isValidDate(self, field_data, all_data): 774 802 try: … … class DateField(TextField): 789 817 class TimeField(TextField): 790 818 """A FormField that automatically converts its data to a datetime.time object. 791 819 The data should be in the format HH:MM:SS or HH:MM:SS.mmmmmm.""" 792 def __init__(self, field_name, is_required=False, validator_list=[] ):820 def __init__(self, field_name, is_required=False, validator_list=[], readonly=False): 793 821 validator_list = [self.isValidTime] + validator_list 794 822 TextField.__init__(self, field_name, length=8, maxlength=8, 795 is_required=is_required, validator_list=validator_list )823 is_required=is_required, validator_list=validator_list, readonly=readonly) 796 824 797 825 def isValidTime(self, field_data, all_data): 798 826 try: … … #################### 823 851 824 852 class EmailField(TextField): 825 853 "A convenience FormField for validating e-mail addresses" 826 def __init__(self, field_name, length=50, maxlength=75, is_required=False, validator_list=[] ):854 def __init__(self, field_name, length=50, maxlength=75, is_required=False, validator_list=[], readonly=False): 827 855 validator_list = [self.isValidEmail] + validator_list 828 856 TextField.__init__(self, field_name, length, maxlength=maxlength, 829 is_required=is_required, validator_list=validator_list )857 is_required=is_required, validator_list=validator_list, readonly=readonly) 830 858 831 859 def isValidEmail(self, field_data, all_data): 832 860 try: … … class EmailField(TextField): 836 864 837 865 class URLField(TextField): 838 866 "A convenience FormField for validating URLs" 839 def __init__(self, field_name, length=50, is_required=False, validator_list=[] ):867 def __init__(self, field_name, length=50, is_required=False, validator_list=[], readonly=False): 840 868 validator_list = [self.isValidURL] + validator_list 841 869 TextField.__init__(self, field_name, length=length, maxlength=200, 842 is_required=is_required, validator_list=validator_list )870 is_required=is_required, validator_list=validator_list, readonly=readonly) 843 871 844 872 def isValidURL(self, field_data, all_data): 845 873 try: … … class URLField(TextField): 848 876 raise validators.CriticalValidationError, e.messages 849 877 850 878 class IPAddressField(TextField): 851 def __init__(self, field_name, length=15, maxlength=15, is_required=False, validator_list=[] ):879 def __init__(self, field_name, length=15, maxlength=15, is_required=False, validator_list=[], readonly=False): 852 880 validator_list = [self.isValidIPAddress] + validator_list 853 881 TextField.__init__(self, field_name, length=length, maxlength=maxlength, 854 is_required=is_required, validator_list=validator_list )882 is_required=is_required, validator_list=validator_list, readonly=readonly) 855 883 856 884 def isValidIPAddress(self, field_data, all_data): 857 885 try: … … #################### 869 897 870 898 class FilePathField(SelectField): 871 899 "A SelectField whose choices are the files in a given directory." 872 def __init__(self, field_name, path, match=None, recursive=False, is_required=False, validator_list=[] ):900 def __init__(self, field_name, path, match=None, recursive=False, is_required=False, validator_list=[], readonly=False): 873 901 import os 874 902 if match is not None: 875 903 import re … … class FilePathField(SelectField): 888 916 choices.append((full_file, f)) 889 917 except OSError: 890 918 pass 891 SelectField.__init__(self, field_name, choices, 1, is_required, validator_list )919 SelectField.__init__(self, field_name, choices, 1, is_required, validator_list, readonly) 892 920 893 921 class PhoneNumberField(TextField): 894 922 "A convenience FormField for validating phone numbers (e.g. '630-555-1234')" 895 def __init__(self, field_name, is_required=False, validator_list=[] ):923 def __init__(self, field_name, is_required=False, validator_list=[], readonly=False): 896 924 validator_list = [self.isValidPhone] + validator_list 897 925 TextField.__init__(self, field_name, length=12, maxlength=12, 898 is_required=is_required, validator_list=validator_list )926 is_required=is_required, validator_list=validator_list, readonly=readonly) 899 927 900 928 def isValidPhone(self, field_data, all_data): 901 929 try: … … class PhoneNumberField(TextField): 905 933 906 934 class USStateField(TextField): 907 935 "A convenience FormField for validating U.S. states (e.g. 'IL')" 908 def __init__(self, field_name, is_required=False, validator_list=[] ):936 def __init__(self, field_name, is_required=False, validator_list=[], readonly=False): 909 937 validator_list = [self.isValidUSState] + validator_list 910 938 TextField.__init__(self, field_name, length=2, maxlength=2, 911 is_required=is_required, validator_list=validator_list )939 is_required=is_required, validator_list=validator_list, readonly=readonly) 912 940 913 941 def isValidUSState(self, field_data, all_data): 914 942 try: … … class USStateField(TextField): 925 953 926 954 class CommaSeparatedIntegerField(TextField): 927 955 "A convenience FormField for validating comma-separated integer fields" 928 def __init__(self, field_name, maxlength=None, is_required=False, validator_list=[] ):956 def __init__(self, field_name, maxlength=None, is_required=False, validator_list=[], readonly=False): 929 957 validator_list = [self.isCommaSeparatedIntegerList] + validator_list 930 958 TextField.__init__(self, field_name, length=20, maxlength=maxlength, 931 is_required=is_required, validator_list=validator_list )959 is_required=is_required, validator_list=validator_list, readonly=readonly) 932 960 933 961 def isCommaSeparatedIntegerList(self, field_data, all_data): 934 962 try: