Ticket #2926: django_forms_attributes.2.diff
File django_forms_attributes.2.diff, 24.6 KB (added by , 18 years ago) |
---|
-
__init__.py
280 280 this field must pass in order to be added or changed. 281 281 is_required 282 282 A Boolean. Is it a required field? 283 attribute_dict 284 A dictionary of property/value attributes for the form field. 283 285 Subclasses should also implement a render(data) method, which is responsible 284 286 for rending the form field in XHTML. 285 287 """ … … 360 362 def get_id(self): 361 363 "Returns the HTML 'id' attribute for this form field." 362 364 return FORM_FIELD_ID_PREFIX + self.field_name 365 366 def get_attribute_string(self): 367 attributes = '' 368 if self.attribute_dict: 369 attributes = " ".join(["%s=\"%s\"" % (p, v) for p, v in self.attribute_dict.items()]) 370 return attributes 363 371 364 372 #################### 365 373 # GENERIC WIDGETS # … … 367 375 368 376 class TextField(FormField): 369 377 input_type = "text" 370 def __init__(self, field_name, length=30, maxlength=None, is_required=False, validator_list=None, member_name=None ):378 def __init__(self, field_name, length=30, maxlength=None, is_required=False, validator_list=None, member_name=None, attribute_dict=None): 371 379 if validator_list is None: validator_list = [] 380 if attribute_dict is None: attribute_dict = {} 372 381 self.field_name = field_name 373 382 self.length, self.maxlength = length, maxlength 374 383 self.is_required = is_required 375 384 self.validator_list = [self.isValidLength, self.hasNoNewlines] + validator_list 385 self.attribute_dict = attribute_dict 376 386 if member_name != None: 377 387 self.member_name = member_name 378 388 … … 393 403 maxlength = 'maxlength="%s" ' % self.maxlength 394 404 if isinstance(data, unicode): 395 405 data = data.encode(settings.DEFAULT_CHARSET) 396 return '<input type="%s" id="%s" class="v%s%s" name="%s" size="%s" value="%s" %s />' % \406 return '<input type="%s" id="%s" class="v%s%s" name="%s" size="%s" value="%s" %s %s />' % \ 397 407 (self.input_type, self.get_id(), self.__class__.__name__, self.is_required and ' required' or '', 398 self.field_name, self.length, escape(data), maxlength )408 self.field_name, self.length, escape(data), maxlength, self.get_attribute_string()) 399 409 400 410 def html2python(data): 401 411 return data … … 405 415 input_type = "password" 406 416 407 417 class LargeTextField(TextField): 408 def __init__(self, field_name, rows=10, cols=40, is_required=False, validator_list=None, maxlength=None ):418 def __init__(self, field_name, rows=10, cols=40, is_required=False, validator_list=None, maxlength=None, attribute_dict=None): 409 419 if validator_list is None: validator_list = [] 420 if attribute_dict is None: attribute_dict = {} 410 421 self.field_name = field_name 411 422 self.rows, self.cols, self.is_required = rows, cols, is_required 412 423 self.validator_list = validator_list[:] 424 self.attribute_dict = attribute_dict 413 425 if maxlength: 414 426 self.validator_list.append(self.isValidLength) 415 427 self.maxlength = maxlength … … 419 431 data = '' 420 432 if isinstance(data, unicode): 421 433 data = data.encode(settings.DEFAULT_CHARSET) 422 return '<textarea id="%s" class="v%s%s" name="%s" rows="%s" cols="%s" >%s</textarea>' % \434 return '<textarea id="%s" class="v%s%s" name="%s" rows="%s" cols="%s" %s>%s</textarea>' % \ 423 435 (self.get_id(), self.__class__.__name__, self.is_required and ' required' or '', 424 self.field_name, self.rows, self.cols, escape(data))436 self.field_name, self.rows, self.cols, self.get_attribute_string(), escape(data)) 425 437 426 438 class HiddenField(FormField): 427 def __init__(self, field_name, is_required=False, validator_list=None ):439 def __init__(self, field_name, is_required=False, validator_list=None, attribute_dict=None): 428 440 if validator_list is None: validator_list = [] 441 if attribute_dict is None: attribute_dict = {} 429 442 self.field_name, self.is_required = field_name, is_required 430 443 self.validator_list = validator_list[:] 444 self.attribute_dict = attribute_dict 431 445 432 446 def render(self, data): 433 return '<input type="hidden" id="%s" name="%s" value="%s" />' % \434 (self.get_id(), self.field_name, escape(data) )447 return '<input type="hidden" id="%s" name="%s" value="%s" %s />' % \ 448 (self.get_id(), self.field_name, escape(data), self.get_attribute_string()) 435 449 436 450 class CheckboxField(FormField): 437 def __init__(self, field_name, checked_by_default=False, validator_list=None ):451 def __init__(self, field_name, checked_by_default=False, validator_list=None, attribute_dict=None): 438 452 if validator_list is None: validator_list = [] 453 if attribute_dict is None: attribute_dict = {} 439 454 self.field_name = field_name 440 455 self.checked_by_default = checked_by_default 441 456 self.is_required = False # because the validator looks for these 442 457 self.validator_list = validator_list[:] 458 self.attribute_dict = attribute_dict 443 459 444 460 def render(self, data): 445 461 checked_html = '' 446 462 if data or (data is '' and self.checked_by_default): 447 463 checked_html = ' checked="checked"' 448 return '<input type="checkbox" id="%s" class="v%s" name="%s"%s />' % \464 return '<input type="checkbox" id="%s" class="v%s" name="%s"%s %s />' % \ 449 465 (self.get_id(), self.__class__.__name__, 450 self.field_name, checked_html )466 self.field_name, checked_html, self.get_attribute_string()) 451 467 452 468 def html2python(data): 453 469 "Convert value from browser ('on' or '') to a Python boolean" … … 457 473 html2python = staticmethod(html2python) 458 474 459 475 class SelectField(FormField): 460 def __init__(self, field_name, choices=None, size=1, is_required=False, validator_list=None, member_name=None ):476 def __init__(self, field_name, choices=None, size=1, is_required=False, validator_list=None, member_name=None, attribute_dict=None): 461 477 if validator_list is None: validator_list = [] 478 if attribute_dict is None: attribute_dict = {} 462 479 if choices is None: choices = [] 463 480 self.field_name = field_name 464 481 # choices is a list of (value, human-readable key) tuples because order matters 465 482 self.choices, self.size, self.is_required = choices, size, is_required 466 483 self.validator_list = [self.isValidChoice] + validator_list 484 self.attribute_dict = attribute_dict 467 485 if member_name != None: 468 486 self.member_name = member_name 469 487 470 488 def render(self, data): 471 output = ['<select id="%s" class="v%s%s" name="%s" size="%s" >' % \489 output = ['<select id="%s" class="v%s%s" name="%s" size="%s" %s>' % \ 472 490 (self.get_id(), self.__class__.__name__, 473 self.is_required and ' required' or '', self.field_name, self.size )]491 self.is_required and ' required' or '', self.field_name, self.size, self.get_attribute_string())] 474 492 str_data = str(data) # normalize to string 475 493 for value, display_name in self.choices: 476 494 selected_html = '' … … 495 513 html2python = staticmethod(html2python) 496 514 497 515 class RadioSelectField(FormField): 498 def __init__(self, field_name, choices=None, ul_class='', is_required=False, validator_list=None, member_name=None ):516 def __init__(self, field_name, choices=None, ul_class='', is_required=False, validator_list=None, member_name=None, attribute_dict=None): 499 517 if validator_list is None: validator_list = [] 518 if attribute_dict is None: attribute_dict = {} 500 519 if choices is None: choices = [] 501 520 self.field_name = field_name 502 521 # choices is a list of (value, human-readable key) tuples because order matters 503 522 self.choices, self.is_required = choices, is_required 504 523 self.validator_list = [self.isValidChoice] + validator_list 505 524 self.ul_class = ul_class 525 self.attribute_dict = attribute_dict 506 526 if member_name != None: 507 527 self.member_name = member_name 508 528 … … 546 566 datalist.append({ 547 567 'value': value, 548 568 'name': display_name, 549 'field': '<input type="radio" id="%s" name="%s" value="%s"%s />' % \550 (self.get_id() + '_' + str(i), self.field_name, value, selected_html ),569 'field': '<input type="radio" id="%s" name="%s" value="%s"%s %s/>' % \ 570 (self.get_id() + '_' + str(i), self.field_name, value, selected_html, self.get_attribute_string()), 551 571 'label': '<label for="%s">%s</label>' % \ 552 572 (self.get_id() + '_' + str(i), display_name), 553 573 }) … … 561 581 562 582 class NullBooleanField(SelectField): 563 583 "This SelectField provides 'Yes', 'No' and 'Unknown', mapping results to True, False or None" 564 def __init__(self, field_name, is_required=False, validator_list=None ):584 def __init__(self, field_name, is_required=False, validator_list=None, attribute_dict=None): 565 585 if validator_list is None: validator_list = [] 566 586 SelectField.__init__(self, field_name, choices=[('1', 'Unknown'), ('2', 'Yes'), ('3', 'No')], 567 is_required=is_required, validator_list=validator_list )587 is_required=is_required, validator_list=validator_list, attribute_dict=attribute_dict) 568 588 569 589 def render(self, data): 570 590 if data is None: data = '1' … … 579 599 class SelectMultipleField(SelectField): 580 600 requires_data_list = True 581 601 def render(self, data): 582 output = ['<select id="%s" class="v%s%s" name="%s" size="%s" multiple="multiple" >' % \602 output = ['<select id="%s" class="v%s%s" name="%s" size="%s" multiple="multiple" %s>' % \ 583 603 (self.get_id(), self.__class__.__name__, self.is_required and ' required' or '', 584 self.field_name, self.size )]604 self.field_name, self.size, self.get_attribute_string())] 585 605 str_data_list = map(str, data) # normalize to strings 586 606 for value, choice in self.choices: 587 607 selected_html = '' … … 615 635 back into the single list that validators, renderers and save() expect. 616 636 """ 617 637 requires_data_list = True 618 def __init__(self, field_name, choices=None, ul_class='', validator_list=None ):638 def __init__(self, field_name, choices=None, ul_class='', validator_list=None, attribute_dict=None): 619 639 if validator_list is None: validator_list = [] 620 640 if choices is None: choices = [] 621 641 self.ul_class = ul_class 622 SelectMultipleField.__init__(self, field_name, choices, size=1, is_required=False, validator_list=validator_list )642 SelectMultipleField.__init__(self, field_name, choices, size=1, is_required=False, validator_list=validator_list, attribute_dict=attribute_dict) 623 643 624 644 def prepare(self, new_data): 625 645 # new_data has "split" this field into several fields, so flatten it … … 638 658 if str(value) in str_data_list: 639 659 checked_html = ' checked="checked"' 640 660 field_name = '%s%s' % (self.field_name, value) 641 output.append('<li><input type="checkbox" id="%s" class="v%s" name="%s"%s /> <label for="%s">%s</label></li>' % \642 (self.get_id() + value , self.__class__.__name__, field_name, checked_html, 643 self.get_ id() + value, choice))661 output.append('<li><input type="checkbox" id="%s" class="v%s" name="%s"%s %s /> <label for="%s">%s</label></li>' % \ 662 (self.get_id() + value , self.__class__.__name__, field_name, checked_html, 663 self.get_attribute_string(), self.get_id() + value, choice)) 644 664 output.append('</ul>') 645 665 return '\n'.join(output) 646 666 … … 649 669 #################### 650 670 651 671 class FileUploadField(FormField): 652 def __init__(self, field_name, is_required=False, validator_list=None ):672 def __init__(self, field_name, is_required=False, validator_list=None, attribute_dict=None): 653 673 if validator_list is None: validator_list = [] 674 if attribute_dict is None: attribute_dict = {} 654 675 self.field_name, self.is_required = field_name, is_required 676 self.attribute_dict = attribute_dict 655 677 self.validator_list = [self.isNonEmptyFile] + validator_list 656 678 657 679 def isNonEmptyFile(self, field_data, all_data): … … 663 685 raise validators.CriticalValidationError, gettext("The submitted file is empty.") 664 686 665 687 def render(self, data): 666 return '<input type="file" id="%s" class="v%s" name="%s" />' % \667 (self.get_id(), self.__class__.__name__, self.field_name )688 return '<input type="file" id="%s" class="v%s" name="%s" %s />' % \ 689 (self.get_id(), self.__class__.__name__, self.field_name, self.get_attribute_string()) 668 690 669 691 def html2python(data): 670 692 if data is None: … … 689 711 #################### 690 712 691 713 class IntegerField(TextField): 692 def __init__(self, field_name, length=10, maxlength=None, is_required=False, validator_list=None, member_name=None ):714 def __init__(self, field_name, length=10, maxlength=None, is_required=False, validator_list=None, member_name=None, attribute_dict=None): 693 715 if validator_list is None: validator_list = [] 694 716 validator_list = [self.isInteger] + validator_list 695 717 if member_name is not None: 696 718 self.member_name = member_name 697 TextField.__init__(self, field_name, length, maxlength, is_required, validator_list )719 TextField.__init__(self, field_name, length, maxlength, is_required, validator_list, attribute_dict=attribute_dict) 698 720 699 721 def isInteger(self, field_data, all_data): 700 722 try: … … 709 731 html2python = staticmethod(html2python) 710 732 711 733 class SmallIntegerField(IntegerField): 712 def __init__(self, field_name, length=5, maxlength=5, is_required=False, validator_list=None ):734 def __init__(self, field_name, length=5, maxlength=5, is_required=False, validator_list=None, attribute_dict=None): 713 735 if validator_list is None: validator_list = [] 714 736 validator_list = [self.isSmallInteger] + validator_list 715 IntegerField.__init__(self, field_name, length, maxlength, is_required, validator_list )737 IntegerField.__init__(self, field_name, length, maxlength, is_required, validator_list, attribute_dict=attribute_dict) 716 738 717 739 def isSmallInteger(self, field_data, all_data): 718 740 if not -32768 <= int(field_data) <= 32767: 719 741 raise validators.CriticalValidationError, gettext("Enter a whole number between -32,768 and 32,767.") 720 742 721 743 class PositiveIntegerField(IntegerField): 722 def __init__(self, field_name, length=10, maxlength=None, is_required=False, validator_list=None ):744 def __init__(self, field_name, length=10, maxlength=None, is_required=False, validator_list=None, attribute_dict=None): 723 745 if validator_list is None: validator_list = [] 724 746 validator_list = [self.isPositive] + validator_list 725 IntegerField.__init__(self, field_name, length, maxlength, is_required, validator_list )747 IntegerField.__init__(self, field_name, length, maxlength, is_required, validator_list, attribute_dict=attribute_dict) 726 748 727 749 def isPositive(self, field_data, all_data): 728 750 if int(field_data) < 0: 729 751 raise validators.CriticalValidationError, gettext("Enter a positive number.") 730 752 731 753 class PositiveSmallIntegerField(IntegerField): 732 def __init__(self, field_name, length=5, maxlength=None, is_required=False, validator_list=None ):754 def __init__(self, field_name, length=5, maxlength=None, is_required=False, validator_list=None, attribute_dict=None): 733 755 if validator_list is None: validator_list = [] 734 756 validator_list = [self.isPositiveSmall] + validator_list 735 IntegerField.__init__(self, field_name, length, maxlength, is_required, validator_list )757 IntegerField.__init__(self, field_name, length, maxlength, is_required, validator_list, attribute_dict=attribute_dict) 736 758 737 759 def isPositiveSmall(self, field_data, all_data): 738 760 if not 0 <= int(field_data) <= 32767: 739 761 raise validators.CriticalValidationError, gettext("Enter a whole number between 0 and 32,767.") 740 762 741 763 class FloatField(TextField): 742 def __init__(self, field_name, max_digits, decimal_places, is_required=False, validator_list=None ):764 def __init__(self, field_name, max_digits, decimal_places, is_required=False, validator_list=None, attribute_dict=None): 743 765 if validator_list is None: validator_list = [] 744 766 self.max_digits, self.decimal_places = max_digits, decimal_places 745 767 validator_list = [self.isValidFloat] + validator_list 746 TextField.__init__(self, field_name, max_digits+1, max_digits+1, is_required, validator_list )768 TextField.__init__(self, field_name, max_digits+1, max_digits+1, is_required, validator_list, attribute_dict=attribute_dict) 747 769 748 770 def isValidFloat(self, field_data, all_data): 749 771 v = validators.IsValidFloat(self.max_digits, self.decimal_places) … … 765 787 class DatetimeField(TextField): 766 788 """A FormField that automatically converts its data to a datetime.datetime object. 767 789 The data should be in the format YYYY-MM-DD HH:MM:SS.""" 768 def __init__(self, field_name, length=30, maxlength=None, is_required=False, validator_list=None ):790 def __init__(self, field_name, length=30, maxlength=None, is_required=False, validator_list=None, attribute_dict=None): 769 791 if validator_list is None: validator_list = [] 792 if attribute_dict is None: attribute_dict = {} 770 793 self.field_name = field_name 771 794 self.length, self.maxlength = length, maxlength 772 795 self.is_required = is_required 773 796 self.validator_list = [validators.isValidANSIDatetime] + validator_list 797 self.attribute_dict = attribute_dict 774 798 775 799 def html2python(data): 776 800 "Converts the field into a datetime.datetime object" … … 792 816 class DateField(TextField): 793 817 """A FormField that automatically converts its data to a datetime.date object. 794 818 The data should be in the format YYYY-MM-DD.""" 795 def __init__(self, field_name, is_required=False, validator_list=None ):819 def __init__(self, field_name, is_required=False, validator_list=None, attribute_dict=None): 796 820 if validator_list is None: validator_list = [] 797 821 validator_list = [self.isValidDate] + validator_list 798 822 TextField.__init__(self, field_name, length=10, maxlength=10, 799 is_required=is_required, validator_list=validator_list )823 is_required=is_required, validator_list=validator_list, attribute_dict=attribute_dict) 800 824 801 825 def isValidDate(self, field_data, all_data): 802 826 try: … … 817 841 class TimeField(TextField): 818 842 """A FormField that automatically converts its data to a datetime.time object. 819 843 The data should be in the format HH:MM:SS or HH:MM:SS.mmmmmm.""" 820 def __init__(self, field_name, is_required=False, validator_list=None ):844 def __init__(self, field_name, is_required=False, validator_list=None, attribute_dict=None): 821 845 if validator_list is None: validator_list = [] 822 846 validator_list = [self.isValidTime] + validator_list 823 847 TextField.__init__(self, field_name, length=8, maxlength=8, 824 is_required=is_required, validator_list=validator_list )848 is_required=is_required, validator_list=validator_list, attribute_dict=attribute_dict) 825 849 826 850 def isValidTime(self, field_data, all_data): 827 851 try: … … 852 876 853 877 class EmailField(TextField): 854 878 "A convenience FormField for validating e-mail addresses" 855 def __init__(self, field_name, length=50, maxlength=75, is_required=False, validator_list=None ):879 def __init__(self, field_name, length=50, maxlength=75, is_required=False, validator_list=None, attribute_dict=None): 856 880 if validator_list is None: validator_list = [] 857 881 validator_list = [self.isValidEmail] + validator_list 858 882 TextField.__init__(self, field_name, length, maxlength=maxlength, 859 is_required=is_required, validator_list=validator_list )883 is_required=is_required, validator_list=validator_list, attribute_dict=attribute_dict) 860 884 861 885 def isValidEmail(self, field_data, all_data): 862 886 try: … … 866 890 867 891 class URLField(TextField): 868 892 "A convenience FormField for validating URLs" 869 def __init__(self, field_name, length=50, maxlength=200, is_required=False, validator_list=None ):893 def __init__(self, field_name, length=50, maxlength=200, is_required=False, validator_list=None, attribute_dict=None): 870 894 if validator_list is None: validator_list = [] 871 895 validator_list = [self.isValidURL] + validator_list 872 896 TextField.__init__(self, field_name, length=length, maxlength=maxlength, 873 is_required=is_required, validator_list=validator_list )897 is_required=is_required, validator_list=validator_list, attribute_dict=attribute_dict) 874 898 875 899 def isValidURL(self, field_data, all_data): 876 900 try: … … 879 903 raise validators.CriticalValidationError, e.messages 880 904 881 905 class IPAddressField(TextField): 882 def __init__(self, field_name, length=15, maxlength=15, is_required=False, validator_list=None ):906 def __init__(self, field_name, length=15, maxlength=15, is_required=False, validator_list=None, attribute_dict=None): 883 907 if validator_list is None: validator_list = [] 884 908 validator_list = [self.isValidIPAddress] + validator_list 885 909 TextField.__init__(self, field_name, length=length, maxlength=maxlength, 886 is_required=is_required, validator_list=validator_list )910 is_required=is_required, validator_list=validator_list, attribute_dict=attribute_dict) 887 911 888 912 def isValidIPAddress(self, field_data, all_data): 889 913 try: … … 901 925 902 926 class FilePathField(SelectField): 903 927 "A SelectField whose choices are the files in a given directory." 904 def __init__(self, field_name, path, match=None, recursive=False, is_required=False, validator_list=None ):928 def __init__(self, field_name, path, match=None, recursive=False, is_required=False, validator_list=None, attribute_dict=None): 905 929 import os 906 930 from django.db.models import BLANK_CHOICE_DASH 907 931 if match is not None: … … 921 945 choices.append((full_file, f)) 922 946 except OSError: 923 947 pass 924 SelectField.__init__(self, field_name, choices, 1, is_required, validator_list )948 SelectField.__init__(self, field_name, choices, 1, is_required, validator_list, attribute_dict=attribute_dict) 925 949 926 950 class PhoneNumberField(TextField): 927 951 "A convenience FormField for validating phone numbers (e.g. '630-555-1234')" 928 def __init__(self, field_name, is_required=False, validator_list=None ):952 def __init__(self, field_name, is_required=False, validator_list=None, attribute_dict=None): 929 953 if validator_list is None: validator_list = [] 930 954 validator_list = [self.isValidPhone] + validator_list 931 955 TextField.__init__(self, field_name, length=12, maxlength=12, 932 is_required=is_required, validator_list=validator_list )956 is_required=is_required, validator_list=validator_list, attribute_dict=attribute_dict) 933 957 934 958 def isValidPhone(self, field_data, all_data): 935 959 try: … … 939 963 940 964 class USStateField(TextField): 941 965 "A convenience FormField for validating U.S. states (e.g. 'IL')" 942 def __init__(self, field_name, is_required=False, validator_list=None ):966 def __init__(self, field_name, is_required=False, validator_list=None, attribute_dict=None): 943 967 if validator_list is None: validator_list = [] 944 968 validator_list = [self.isValidUSState] + validator_list 945 969 TextField.__init__(self, field_name, length=2, maxlength=2, 946 is_required=is_required, validator_list=validator_list )970 is_required=is_required, validator_list=validator_list, attribute_dict=attribute_dict) 947 971 948 972 def isValidUSState(self, field_data, all_data): 949 973 try: … … 960 984 961 985 class CommaSeparatedIntegerField(TextField): 962 986 "A convenience FormField for validating comma-separated integer fields" 963 def __init__(self, field_name, maxlength=None, is_required=False, validator_list=None ):987 def __init__(self, field_name, maxlength=None, is_required=False, validator_list=None, attribute_dict=None): 964 988 if validator_list is None: validator_list = [] 965 989 validator_list = [self.isCommaSeparatedIntegerList] + validator_list 966 990 TextField.__init__(self, field_name, length=20, maxlength=maxlength, 967 is_required=is_required, validator_list=validator_list )991 is_required=is_required, validator_list=validator_list, attribute_dict=attribute_dict) 968 992 969 993 def isCommaSeparatedIntegerList(self, field_data, all_data): 970 994 try: