| 1586 | | |
|---|
| 1587 | | def manipulator_valid_rel_key(f, self, field_data, all_data): |
|---|
| 1588 | | "Validates that the value is a valid foreign key" |
|---|
| 1589 | | mod = f.rel.to.get_model_module() |
|---|
| 1590 | | try: |
|---|
| 1591 | | mod.get_object(**{'id__iexact': field_data}) |
|---|
| 1592 | | except ObjectDoesNotExist: |
|---|
| 1593 | | raise validators.ValidationError, "Please enter a valid %s." % f.verbose_name |
|---|
| 1594 | | |
|---|
| 1595 | | #################### |
|---|
| 1596 | | # FIELDS # |
|---|
| 1597 | | #################### |
|---|
| 1598 | | |
|---|
| 1599 | | class Field(object): |
|---|
| 1600 | | |
|---|
| 1601 | | # Designates whether empty strings fundamentally are allowed at the |
|---|
| 1602 | | # database level. |
|---|
| 1603 | | empty_strings_allowed = True |
|---|
| 1604 | | |
|---|
| 1605 | | def __init__(self, name, verbose_name=None, primary_key=False, |
|---|
| 1606 | | maxlength=None, unique=False, blank=False, null=False, db_index=None, |
|---|
| 1607 | | core=False, rel=None, default=NOT_PROVIDED, editable=True, |
|---|
| 1608 | | prepopulate_from=None, unique_for_date=None, unique_for_month=None, |
|---|
| 1609 | | unique_for_year=None, validator_list=None, choices=None, radio_admin=None, |
|---|
| 1610 | | help_text=''): |
|---|
| 1611 | | self.name = name |
|---|
| 1612 | | self.verbose_name = verbose_name or name.replace('_', ' ') |
|---|
| 1613 | | self.primary_key = primary_key |
|---|
| 1614 | | self.maxlength, self.unique = maxlength, unique |
|---|
| 1615 | | self.blank, self.null = blank, null |
|---|
| 1616 | | self.core, self.rel, self.default = core, rel, default |
|---|
| 1617 | | self.editable = editable |
|---|
| 1618 | | self.validator_list = validator_list or [] |
|---|
| 1619 | | self.prepopulate_from = prepopulate_from |
|---|
| 1620 | | self.unique_for_date, self.unique_for_month = unique_for_date, unique_for_month |
|---|
| 1621 | | self.unique_for_year = unique_for_year |
|---|
| 1622 | | self.choices = choices or [] |
|---|
| 1623 | | self.radio_admin = radio_admin |
|---|
| 1624 | | self.help_text = help_text |
|---|
| 1625 | | if rel and isinstance(rel, ManyToMany): |
|---|
| 1626 | | self.help_text += ' Hold down "Control", or "Command" on a Mac, to select more than one.' |
|---|
| 1627 | | |
|---|
| 1628 | | # Set db_index to True if the field has a relationship and doesn't explicitly set db_index. |
|---|
| 1629 | | if db_index is None: |
|---|
| 1630 | | if isinstance(rel, OneToOne) or isinstance(rel, ManyToOne): |
|---|
| 1631 | | self.db_index = True |
|---|
| 1632 | | else: |
|---|
| 1633 | | self.db_index = False |
|---|
| 1634 | | else: |
|---|
| 1635 | | self.db_index = db_index |
|---|
| 1636 | | |
|---|
| 1637 | | def pre_save(self, obj, value, add): |
|---|
| 1638 | | """ |
|---|
| 1639 | | Hook for altering the object obj based on the value of this field and |
|---|
| 1640 | | and on the add/change status. |
|---|
| 1641 | | """ |
|---|
| 1642 | | pass |
|---|
| 1643 | | |
|---|
| 1644 | | def get_db_prep_save(self, value, add): |
|---|
| 1645 | | "Returns field's value prepared for saving into a database." |
|---|
| 1646 | | return value |
|---|
| 1647 | | |
|---|
| 1648 | | def get_db_prep_lookup(self, lookup_type, value): |
|---|
| 1649 | | "Returns field's value prepared for database lookup." |
|---|
| 1650 | | if lookup_type in ('exact', 'gt', 'gte', 'lt', 'lte', 'ne', 'month', 'day'): |
|---|
| 1651 | | return [value] |
|---|
| 1652 | | elif lookup_type in ('range', 'in'): |
|---|
| 1653 | | return value |
|---|
| 1654 | | elif lookup_type == 'year': |
|---|
| 1655 | | return ['%s-01-01' % value, '%s-12-31' % value] |
|---|
| 1656 | | elif lookup_type in ('contains', 'icontains'): |
|---|
| 1657 | | return ["%%%s%%" % prep_for_like_query(value)] |
|---|
| 1658 | | elif lookup_type == 'iexact': |
|---|
| 1659 | | return [prep_for_like_query(value)] |
|---|
| 1660 | | elif lookup_type in ('startswith', 'istartswith'): |
|---|
| 1661 | | return ["%s%%" % prep_for_like_query(value)] |
|---|
| 1662 | | elif lookup_type in ('endswith', 'iendswith'): |
|---|
| 1663 | | return ["%%%s" % prep_for_like_query(value)] |
|---|
| 1664 | | elif lookup_type == 'isnull': |
|---|
| 1665 | | return [] |
|---|
| 1666 | | raise TypeError, "Field has invalid lookup: %s" % lookup_type |
|---|
| 1667 | | |
|---|
| 1668 | | def has_default(self): |
|---|
| 1669 | | "Returns a boolean of whether this field has a default value." |
|---|
| 1670 | | return self.default != NOT_PROVIDED |
|---|
| 1671 | | |
|---|
| 1672 | | def get_default(self): |
|---|
| 1673 | | "Returns the default value for this field." |
|---|
| 1674 | | if self.default != NOT_PROVIDED: |
|---|
| 1675 | | if hasattr(self.default, '__get_value__'): |
|---|
| 1676 | | return self.default.__get_value__() |
|---|
| 1677 | | return self.default |
|---|
| 1678 | | if self.null: |
|---|
| 1679 | | return None |
|---|
| 1680 | | return "" |
|---|
| 1681 | | |
|---|
| 1682 | | def get_manipulator_field_names(self, name_prefix): |
|---|
| 1683 | | """ |
|---|
| 1684 | | Returns a list of field names that this object adds to the manipulator. |
|---|
| 1685 | | """ |
|---|
| 1686 | | return [name_prefix + self.name] |
|---|
| 1687 | | |
|---|
| 1688 | | def get_manipulator_fields(self, opts, manipulator, change, name_prefix='', rel=False): |
|---|
| 1689 | | """ |
|---|
| 1690 | | Returns a list of formfields.FormField instances for this field. It |
|---|
| 1691 | | calculates the choices at runtime, not at compile time. |
|---|
| 1692 | | |
|---|
| 1693 | | name_prefix is a prefix to prepend to the "field_name" argument. |
|---|
| 1694 | | rel is a boolean specifying whether this field is in a related context. |
|---|
| 1695 | | """ |
|---|
| 1696 | | params = {'validator_list': self.validator_list[:]} |
|---|
| 1697 | | if self.maxlength and not self.choices: # Don't give SelectFields a maxlength parameter. |
|---|
| 1698 | | params['maxlength'] = self.maxlength |
|---|
| 1699 | | if isinstance(self.rel, ManyToOne): |
|---|
| 1700 | | if self.rel.raw_id_admin: |
|---|
| 1701 | | field_objs = self.get_manipulator_field_objs() |
|---|
| 1702 | | params['validator_list'].append(curry(manipulator_valid_rel_key, self, manipulator)) |
|---|
| 1703 | | else: |
|---|
| 1704 | | if self.radio_admin: |
|---|
| 1705 | | field_objs = [formfields.RadioSelectField] |
|---|
| 1706 | | params['choices'] = self.get_choices(include_blank=self.blank, blank_choice=BLANK_CHOICE_NONE) |
|---|
| 1707 | | params['ul_class'] = get_ul_class(self.radio_admin) |
|---|
| 1708 | | else: |
|---|
| 1709 | | if self.null: |
|---|
| 1710 | | field_objs = [formfields.NullSelectField] |
|---|
| 1711 | | else: |
|---|
| 1712 | | field_objs = [formfields.SelectField] |
|---|
| 1713 | | params['choices'] = self.get_choices() |
|---|
| 1714 | | elif self.choices: |
|---|
| 1715 | | if self.radio_admin: |
|---|
| 1716 | | field_objs = [formfields.RadioSelectField] |
|---|
| 1717 | | params['choices'] = self.get_choices(include_blank=self.blank, blank_choice=BLANK_CHOICE_NONE) |
|---|
| 1718 | | params['ul_class'] = get_ul_class(self.radio_admin) |
|---|
| 1719 | | else: |
|---|
| 1720 | | field_objs = [formfields.SelectField] |
|---|
| 1721 | | params['choices'] = self.get_choices() |
|---|
| 1722 | | else: |
|---|
| 1723 | | field_objs = self.get_manipulator_field_objs() |
|---|
| 1724 | | |
|---|
| 1725 | | # Add the "unique" validator(s). |
|---|
| 1726 | | for field_name_list in opts.unique_together: |
|---|
| 1727 | | if field_name_list[0] == self.name: |
|---|
| 1728 | | params['validator_list'].append(getattr(manipulator, 'isUnique%s' % '_'.join(field_name_list))) |
|---|
| 1729 | | |
|---|
| 1730 | | # Add the "unique for..." validator(s). |
|---|
| 1731 | | if self.unique_for_date: |
|---|
| 1732 | | params['validator_list'].append(getattr(manipulator, 'isUnique%sFor%s' % (self.name, self.unique_for_date))) |
|---|
| 1733 | | if self.unique_for_month: |
|---|
| 1734 | | params['validator_list'].append(getattr(manipulator, 'isUnique%sFor%s' % (self.name, self.unique_for_month))) |
|---|
| 1735 | | if self.unique_for_year: |
|---|
| 1736 | | params['validator_list'].append(getattr(manipulator, 'isUnique%sFor%s' % (self.name, self.unique_for_year))) |
|---|
| 1737 | | if self.unique: |
|---|
| 1738 | | params['validator_list'].append(curry(manipulator_validator_unique, self, opts, manipulator)) |
|---|
| 1739 | | |
|---|
| 1740 | | # Only add is_required=True if the field cannot be blank. Primary keys |
|---|
| 1741 | | # are a special case, and fields in a related context should set this |
|---|
| 1742 | | # as False, because they'll be caught by a separate validator -- |
|---|
| 1743 | | # RequiredIfOtherFieldGiven. |
|---|
| 1744 | | params['is_required'] = not self.blank and not self.primary_key and not rel |
|---|
| 1745 | | |
|---|
| 1746 | | # If this field is in a related context, check whether any other fields |
|---|
| 1747 | | # in the related object have core=True. If so, add a validator -- |
|---|
| 1748 | | # RequiredIfOtherFieldsGiven -- to this FormField. |
|---|
| 1749 | | if rel and not self.blank and not isinstance(self, AutoField) and not isinstance(self, FileField): |
|---|
| 1750 | | # First, get the core fields, if any. |
|---|
| 1751 | | core_field_names = [] |
|---|
| 1752 | | for f in opts.fields: |
|---|
| 1753 | | if f.core and f != self: |
|---|
| 1754 | | core_field_names.extend(f.get_manipulator_field_names(name_prefix)) |
|---|
| 1755 | | # Now, if there are any, add the validator to this FormField. |
|---|
| 1756 | | if core_field_names: |
|---|
| 1757 | | params['validator_list'].append(validators.RequiredIfOtherFieldsGiven(core_field_names, "This field is required.")) |
|---|
| 1758 | | |
|---|
| 1759 | | # BooleanFields (CheckboxFields) are a special case. They don't take |
|---|
| 1760 | | # is_required or validator_list. |
|---|
| 1761 | | if isinstance(self, BooleanField): |
|---|
| 1762 | | del params['validator_list'], params['is_required'] |
|---|
| 1763 | | |
|---|
| 1764 | | # Finally, add the field_names. |
|---|
| 1765 | | field_names = self.get_manipulator_field_names(name_prefix) |
|---|
| 1766 | | return [man(field_name=field_names[i], **params) for i, man in enumerate(field_objs)] |
|---|
| 1767 | | |
|---|
| 1768 | | def get_manipulator_new_data(self, new_data, rel=False): |
|---|
| 1769 | | """ |
|---|
| 1770 | | Given the full new_data dictionary (from the manipulator), returns this |
|---|
| 1771 | | field's data. |
|---|
| 1772 | | """ |
|---|
| 1773 | | if rel: |
|---|
| 1774 | | return new_data.get(self.name, [self.get_default()])[0] |
|---|
| 1775 | | else: |
|---|
| 1776 | | val = new_data.get(self.name, self.get_default()) |
|---|
| 1777 | | if not self.empty_strings_allowed and val == '' and self.null: |
|---|
| 1778 | | val = None |
|---|
| 1779 | | return val |
|---|
| 1780 | | |
|---|
| 1781 | | def get_choices(self, include_blank=True, blank_choice=BLANK_CHOICE_DASH): |
|---|
| 1782 | | "Returns a list of tuples used as SelectField choices for this field." |
|---|
| 1783 | | first_choice = include_blank and blank_choice or [] |
|---|
| 1784 | | if self.choices: |
|---|
| 1785 | | return first_choice + list(self.choices) |
|---|
| 1786 | | rel_obj = self.rel.to |
|---|
| 1787 | | return first_choice + [(getattr(x, rel_obj.pk.name), repr(x)) for x in rel_obj.get_model_module().get_list(**self.rel.limit_choices_to)] |
|---|
| 1788 | | |
|---|
| 1789 | | class AutoField(Field): |
|---|
| 1790 | | empty_strings_allowed = False |
|---|
| 1791 | | def get_manipulator_fields(self, opts, manipulator, change, name_prefix='', rel=False): |
|---|
| 1792 | | if not rel: |
|---|
| 1793 | | return [] # Don't add a FormField unless it's in a related context. |
|---|
| 1794 | | return Field.get_manipulator_fields(self, opts, manipulator, change, name_prefix, rel) |
|---|
| 1795 | | |
|---|
| 1796 | | def get_manipulator_field_objs(self): |
|---|
| 1797 | | return [formfields.HiddenField] |
|---|
| 1798 | | |
|---|
| 1799 | | def get_manipulator_new_data(self, new_data, rel=False): |
|---|
| 1800 | | if not rel: |
|---|
| 1801 | | return None |
|---|
| 1802 | | return Field.get_manipulator_new_data(self, new_data, rel) |
|---|
| 1803 | | |
|---|
| 1804 | | class BooleanField(Field): |
|---|
| 1805 | | def __init__(self, *args, **kwargs): |
|---|
| 1806 | | kwargs['blank'] = True |
|---|
| 1807 | | Field.__init__(self, *args, **kwargs) |
|---|
| 1808 | | |
|---|
| 1809 | | def get_manipulator_field_objs(self): |
|---|
| 1810 | | return [formfields.CheckboxField] |
|---|
| 1811 | | |
|---|
| 1812 | | class CharField(Field): |
|---|
| 1813 | | def get_manipulator_field_objs(self): |
|---|
| 1814 | | return [formfields.TextField] |
|---|
| 1815 | | |
|---|
| 1816 | | class CommaSeparatedIntegerField(CharField): |
|---|
| 1817 | | def get_manipulator_field_objs(self): |
|---|
| 1818 | | return [formfields.CommaSeparatedIntegerField] |
|---|
| 1819 | | |
|---|
| 1820 | | class DateField(Field): |
|---|
| 1821 | | empty_strings_allowed = False |
|---|
| 1822 | | def __init__(self, name, verbose_name=None, auto_now=False, auto_now_add=False, **kwargs): |
|---|
| 1823 | | self.auto_now, self.auto_now_add = auto_now, auto_now_add |
|---|
| 1824 | | if auto_now or auto_now_add: |
|---|
| 1825 | | kwargs['editable'] = False |
|---|
| 1826 | | Field.__init__(self, name, verbose_name, **kwargs) |
|---|
| 1827 | | |
|---|
| 1828 | | def get_db_prep_lookup(self, lookup_type, value): |
|---|
| 1829 | | if lookup_type == 'range': |
|---|
| 1830 | | value = [str(v) for v in value] |
|---|
| 1831 | | else: |
|---|
| 1832 | | value = str(value) |
|---|
| 1833 | | return Field.get_db_prep_lookup(self, lookup_type, value) |
|---|
| 1834 | | |
|---|
| 1835 | | def pre_save(self, obj, value, add): |
|---|
| 1836 | | if self.auto_now or (self.auto_now_add and add): |
|---|
| 1837 | | setattr(obj, self.name, datetime.datetime.now()) |
|---|
| 1838 | | |
|---|
| 1839 | | def get_db_prep_save(self, value, add): |
|---|
| 1840 | | # Casts dates into string format for entry into database. |
|---|
| 1841 | | if value is not None: |
|---|
| 1842 | | value = value.strftime('%Y-%m-%d') |
|---|
| 1843 | | return Field.get_db_prep_save(self, value, add) |
|---|
| 1844 | | |
|---|
| 1845 | | def get_manipulator_field_objs(self): |
|---|
| 1846 | | return [formfields.DateField] |
|---|
| 1847 | | |
|---|
| 1848 | | class DateTimeField(DateField): |
|---|
| 1849 | | def get_db_prep_save(self, value, add): |
|---|
| 1850 | | # Casts dates into string format for entry into database. |
|---|
| 1851 | | if value is not None: |
|---|
| 1852 | | value = value.strftime('%Y-%m-%d %H:%M:%S') |
|---|
| 1853 | | return Field.get_db_prep_save(self, value, add) |
|---|
| 1854 | | |
|---|
| 1855 | | def get_manipulator_field_objs(self): |
|---|
| 1856 | | return [formfields.DateField, formfields.TimeField] |
|---|
| 1857 | | |
|---|
| 1858 | | def get_manipulator_field_names(self, name_prefix): |
|---|
| 1859 | | return [name_prefix + self.name + '_date', name_prefix + self.name + '_time'] |
|---|
| 1860 | | |
|---|
| 1861 | | def get_manipulator_new_data(self, new_data, rel=False): |
|---|
| 1862 | | date_field, time_field = self.get_manipulator_field_names('') |
|---|
| 1863 | | if rel: |
|---|
| 1864 | | d = new_data.get(date_field, [None])[0] |
|---|
| 1865 | | t = new_data.get(time_field, [None])[0] |
|---|
| 1866 | | else: |
|---|
| 1867 | | d = new_data.get(date_field, None) |
|---|
| 1868 | | t = new_data.get(time_field, None) |
|---|
| 1869 | | if d is not None and t is not None: |
|---|
| 1870 | | return datetime.datetime.combine(d, t) |
|---|
| 1871 | | return self.get_default() |
|---|
| 1872 | | |
|---|
| 1873 | | class EmailField(Field): |
|---|
| 1874 | | def get_manipulator_field_objs(self): |
|---|
| 1875 | | return [formfields.EmailField] |
|---|
| 1876 | | |
|---|
| 1877 | | class FileField(Field): |
|---|
| 1878 | | def __init__(self, name, verbose_name=None, upload_to='', **kwargs): |
|---|
| 1879 | | self.upload_to = upload_to |
|---|
| 1880 | | Field.__init__(self, name, verbose_name, **kwargs) |
|---|
| 1881 | | |
|---|
| 1882 | | def get_manipulator_fields(self, opts, manipulator, change, name_prefix='', rel=False): |
|---|
| 1883 | | field_list = Field.get_manipulator_fields(self, opts, manipulator, change, name_prefix, rel) |
|---|
| 1884 | | |
|---|
| 1885 | | if not self.blank: |
|---|
| 1886 | | if rel: |
|---|
| 1887 | | # This validator makes sure FileFields work in a related context. |
|---|
| 1888 | | class RequiredFileField: |
|---|
| 1889 | | def __init__(self, other_field_names, other_file_field_name): |
|---|
| 1890 | | self.other_field_names = other_field_names |
|---|
| 1891 | | self.other_file_field_name = other_file_field_name |
|---|
| 1892 | | self.always_test = True |
|---|
| 1893 | | def __call__(self, field_data, all_data): |
|---|
| 1894 | | if not all_data.get(self.other_file_field_name, False): |
|---|
| 1895 | | c = validators.RequiredIfOtherFieldsGiven(self.other_field_names, "This field is required.") |
|---|
| 1896 | | c(field_data, all_data) |
|---|
| 1897 | | # First, get the core fields, if any. |
|---|
| 1898 | | core_field_names = [] |
|---|
| 1899 | | for f in opts.fields: |
|---|
| 1900 | | if f.core and f != self: |
|---|
| 1901 | | core_field_names.extend(f.get_manipulator_field_names(name_prefix)) |
|---|
| 1902 | | # Now, if there are any, add the validator to this FormField. |
|---|
| 1903 | | if core_field_names: |
|---|
| 1904 | | field_list[0].validator_list.append(RequiredFileField(core_field_names, field_list[1].field_name)) |
|---|
| 1905 | | else: |
|---|
| 1906 | | v = validators.RequiredIfOtherFieldNotGiven(field_list[1].field_name, "This field is required.") |
|---|
| 1907 | | v.always_test = True |
|---|
| 1908 | | field_list[0].validator_list.append(v) |
|---|
| 1909 | | field_list[0].is_required = field_list[1].is_required = False |
|---|
| 1910 | | |
|---|
| 1911 | | # If the raw path is passed in, validate it's under the MEDIA_ROOT. |
|---|
| 1912 | | def isWithinMediaRoot(field_data, all_data): |
|---|
| 1913 | | f = os.path.abspath(os.path.join(settings.MEDIA_ROOT, field_data)) |
|---|
| 1914 | | if not f.startswith(os.path.normpath(settings.MEDIA_ROOT)): |
|---|
| 1915 | | raise validators.ValidationError, "Enter a valid filename." |
|---|
| 1916 | | field_list[1].validator_list.append(isWithinMediaRoot) |
|---|
| 1917 | | return field_list |
|---|
| 1918 | | |
|---|
| 1919 | | def get_manipulator_field_objs(self): |
|---|
| 1920 | | return [formfields.FileUploadField, formfields.HiddenField] |
|---|
| 1921 | | |
|---|
| 1922 | | def get_manipulator_field_names(self, name_prefix): |
|---|
| 1923 | | return [name_prefix + self.name + '_file', name_prefix + self.name] |
|---|
| 1924 | | |
|---|
| 1925 | | def save_file(self, new_data, new_object, original_object, change, rel): |
|---|
| 1926 | | upload_field_name = self.get_manipulator_field_names('')[0] |
|---|
| 1927 | | if new_data.get(upload_field_name, False): |
|---|
| 1928 | | if rel: |
|---|
| 1929 | | getattr(new_object, 'save_%s_file' % self.name)(new_data[upload_field_name][0]["filename"], new_data[upload_field_name][0]["content"]) |
|---|
| 1930 | | else: |
|---|
| 1931 | | getattr(new_object, 'save_%s_file' % self.name)(new_data[upload_field_name]["filename"], new_data[upload_field_name]["content"]) |
|---|
| 1932 | | |
|---|
| 1933 | | def get_directory_name(self): |
|---|
| 1934 | | return os.path.normpath(datetime.datetime.now().strftime(self.upload_to)) |
|---|
| 1935 | | |
|---|
| 1936 | | def get_filename(self, filename): |
|---|
| 1937 | | from django.utils.text import get_valid_filename |
|---|
| 1938 | | f = os.path.join(self.get_directory_name(), get_valid_filename(os.path.basename(filename))) |
|---|
| 1939 | | return os.path.normpath(f) |
|---|
| 1940 | | |
|---|
| 1941 | | class FloatField(Field): |
|---|
| 1942 | | empty_strings_allowed = False |
|---|
| 1943 | | def __init__(self, name, verbose_name=None, max_digits=None, decimal_places=None, **kwargs): |
|---|
| 1944 | | self.max_digits, self.decimal_places = max_digits, decimal_places |
|---|
| 1945 | | Field.__init__(self, name, verbose_name, **kwargs) |
|---|
| 1946 | | |
|---|
| 1947 | | def get_manipulator_field_objs(self): |
|---|
| 1948 | | return [curry(formfields.FloatField, max_digits=self.max_digits, decimal_places=self.decimal_places)] |
|---|
| 1949 | | |
|---|
| 1950 | | class ImageField(FileField): |
|---|
| 1951 | | def __init__(self, name, verbose_name=None, width_field=None, height_field=None, **kwargs): |
|---|
| 1952 | | self.width_field, self.height_field = width_field, height_field |
|---|
| 1953 | | FileField.__init__(self, name, verbose_name, **kwargs) |
|---|
| 1954 | | |
|---|
| 1955 | | def get_manipulator_field_objs(self): |
|---|
| 1956 | | return [formfields.ImageUploadField, formfields.HiddenField] |
|---|
| 1957 | | |
|---|
| 1958 | | def save_file(self, new_data, new_object, original_object, change, rel): |
|---|
| 1959 | | FileField.save_file(self, new_data, new_object, original_object, change, rel) |
|---|
| 1960 | | # If the image has height and/or width field(s) and they haven't |
|---|
| 1961 | | # changed, set the width and/or height field(s) back to their original |
|---|
| 1962 | | # values. |
|---|
| 1963 | | if change and (self.width_field or self.height_field): |
|---|
| 1964 | | if self.width_field: |
|---|
| 1965 | | setattr(new_object, self.width_field, getattr(original_object, self.width_field)) |
|---|
| 1966 | | if self.height_field: |
|---|
| 1967 | | setattr(new_object, self.height_field, getattr(original_object, self.height_field)) |
|---|
| 1968 | | new_object.save() |
|---|
| 1969 | | |
|---|
| 1970 | | class IntegerField(Field): |
|---|
| 1971 | | empty_strings_allowed = False |
|---|
| 1972 | | def get_manipulator_field_objs(self): |
|---|
| 1973 | | return [formfields.IntegerField] |
|---|
| 1974 | | |
|---|
| 1975 | | class IPAddressField(Field): |
|---|
| 1976 | | def __init__(self, *args, **kwargs): |
|---|
| 1977 | | kwargs['maxlength'] = 15 |
|---|
| 1978 | | Field.__init__(self, *args, **kwargs) |
|---|
| 1979 | | |
|---|
| 1980 | | def get_manipulator_field_objs(self): |
|---|
| 1981 | | return [formfields.IPAddressField] |
|---|
| 1982 | | |
|---|
| 1983 | | class NullBooleanField(Field): |
|---|
| 1984 | | def __init__(self, *args, **kwargs): |
|---|
| 1985 | | kwargs['null'] = True |
|---|
| 1986 | | Field.__init__(self, *args, **kwargs) |
|---|
| 1987 | | |
|---|
| 1988 | | def get_manipulator_field_objs(self): |
|---|
| 1989 | | return [formfields.NullBooleanField] |
|---|
| 1990 | | |
|---|
| 1991 | | class PhoneNumberField(IntegerField): |
|---|
| 1992 | | def get_manipulator_field_objs(self): |
|---|
| 1993 | | return [formfields.PhoneNumberField] |
|---|
| 1994 | | |
|---|
| 1995 | | class PositiveIntegerField(IntegerField): |
|---|
| 1996 | | def get_manipulator_field_objs(self): |
|---|
| 1997 | | return [formfields.PositiveIntegerField] |
|---|
| 1998 | | |
|---|
| 1999 | | class PositiveSmallIntegerField(IntegerField): |
|---|
| 2000 | | def get_manipulator_field_objs(self): |
|---|
| 2001 | | return [formfields.PositiveSmallIntegerField] |
|---|
| 2002 | | |
|---|
| 2003 | | class SlugField(Field): |
|---|
| 2004 | | def __init__(self, *args, **kwargs): |
|---|
| 2005 | | kwargs['maxlength'] = 50 |
|---|
| 2006 | | kwargs.setdefault('validator_list', []).append(validators.isAlphaNumeric) |
|---|
| 2007 | | # Set db_index=True unless it's been set manually. |
|---|
| 2008 | | if not kwargs.has_key('db_index'): |
|---|
| 2009 | | kwargs['db_index'] = True |
|---|
| 2010 | | Field.__init__(self, *args, **kwargs) |
|---|
| 2011 | | |
|---|
| 2012 | | def get_manipulator_field_objs(self): |
|---|
| 2013 | | return [formfields.TextField] |
|---|
| 2014 | | |
|---|
| 2015 | | class SmallIntegerField(IntegerField): |
|---|
| 2016 | | def get_manipulator_field_objs(self): |
|---|
| 2017 | | return [formfields.SmallIntegerField] |
|---|
| 2018 | | |
|---|
| 2019 | | class TextField(Field): |
|---|
| 2020 | | def get_manipulator_field_objs(self): |
|---|
| 2021 | | return [formfields.LargeTextField] |
|---|
| 2022 | | |
|---|
| 2023 | | class TimeField(Field): |
|---|
| 2024 | | empty_strings_allowed = False |
|---|
| 2025 | | def __init__(self, name, verbose_name=None, auto_now=False, auto_now_add=False, **kwargs): |
|---|
| 2026 | | self.auto_now, self.auto_now_add = auto_now, auto_now_add |
|---|
| 2027 | | if auto_now or auto_now_add: |
|---|
| 2028 | | kwargs['editable'] = False |
|---|
| 2029 | | Field.__init__(self, name, verbose_name, **kwargs) |
|---|
| 2030 | | |
|---|
| 2031 | | def get_db_prep_lookup(self, lookup_type, value): |
|---|
| 2032 | | if lookup_type == 'range': |
|---|
| 2033 | | value = [str(v) for v in value] |
|---|
| 2034 | | else: |
|---|
| 2035 | | value = str(value) |
|---|
| 2036 | | return Field.get_db_prep_lookup(self, lookup_type, value) |
|---|
| 2037 | | |
|---|
| 2038 | | def pre_save(self, obj, value, add): |
|---|
| 2039 | | if self.auto_now or (self.auto_now_add and add): |
|---|
| 2040 | | setattr(obj, self.name, datetime.datetime.now().time()) |
|---|
| 2041 | | |
|---|
| 2042 | | def get_db_prep_save(self, value, add): |
|---|
| 2043 | | # Casts dates into string format for entry into database. |
|---|
| 2044 | | if value is not None: |
|---|
| 2045 | | value = value.strftime('%H:%M:%S') |
|---|
| 2046 | | return Field.get_db_prep_save(self, value, add) |
|---|
| 2047 | | |
|---|
| 2048 | | def get_manipulator_field_objs(self): |
|---|
| 2049 | | return [formfields.TimeField] |
|---|
| 2050 | | |
|---|
| 2051 | | class URLField(Field): |
|---|
| 2052 | | def __init__(self, name, verbose_name=None, verify_exists=True, **kwargs): |
|---|
| 2053 | | if verify_exists: |
|---|
| 2054 | | kwargs.setdefault('validator_list', []).append(validators.isExistingURL) |
|---|
| 2055 | | Field.__init__(self, name, verbose_name, **kwargs) |
|---|
| 2056 | | |
|---|
| 2057 | | def get_manipulator_field_objs(self): |
|---|
| 2058 | | return [formfields.URLField] |
|---|
| 2059 | | |
|---|
| 2060 | | class USStateField(Field): |
|---|
| 2061 | | def get_manipulator_field_objs(self): |
|---|
| 2062 | | return [formfields.USStateField] |
|---|
| 2063 | | |
|---|
| 2064 | | class XMLField(Field): |
|---|
| 2065 | | def __init__(self, name, verbose_name=None, schema_path=None, **kwargs): |
|---|
| 2066 | | self.schema_path = schema_path |
|---|
| 2067 | | Field.__init__(self, name, verbose_name, **kwargs) |
|---|
| 2068 | | |
|---|
| 2069 | | def get_manipulator_field_objs(self): |
|---|
| 2070 | | return [curry(formfields.XMLLargeTextField, schema_path=self.schema_path)] |
|---|
| 2071 | | |
|---|
| 2072 | | class ForeignKey(Field): |
|---|
| 2073 | | empty_strings_allowed = False |
|---|
| 2074 | | def __init__(self, to, to_field=None, rel_name=None, **kwargs): |
|---|
| 2075 | | try: |
|---|
| 2076 | | to_name = to._meta.object_name.lower() |
|---|
| 2077 | | except AttributeError: # to._meta doesn't exist, so it must be RECURSIVE_RELATIONSHIP_CONSTANT |
|---|
| 2078 | | assert to == 'self', "ForeignKey(%r) is invalid. First parameter to ForeignKey must be either a model or the string %r" % (to, RECURSIVE_RELATIONSHIP_CONSTANT) |
|---|
| 2079 | | kwargs['name'] = kwargs.get('name', '') |
|---|
| 2080 | | kwargs['verbose_name'] = kwargs.get('verbose_name', '') |
|---|
| 2081 | | else: |
|---|
| 2082 | | to_field = to_field or to._meta.pk.name |
|---|
| 2083 | | kwargs['name'] = kwargs.get('name', to_name + '_id') |
|---|
| 2084 | | kwargs['verbose_name'] = kwargs.get('verbose_name', to._meta.verbose_name) |
|---|
| 2085 | | rel_name = rel_name or to_name |
|---|
| 2086 | | kwargs['rel'] = ManyToOne(to, rel_name, to_field, |
|---|
| 2087 | | num_in_admin=kwargs.pop('num_in_admin', 0), |
|---|
| 2088 | | min_num_in_admin=kwargs.pop('min_num_in_admin', None), |
|---|
| 2089 | | max_num_in_admin=kwargs.pop('max_num_in_admin', None), |
|---|
| 2090 | | num_extra_on_change=kwargs.pop('num_extra_on_change', 1), |
|---|
| 2091 | | edit_inline=kwargs.pop('edit_inline', False), |
|---|
| 2092 | | edit_inline_type=kwargs.pop('edit_inline_type', STACKED), |
|---|
| 2093 | | related_name=kwargs.pop('related_name', None), |
|---|
| 2094 | | limit_choices_to=kwargs.pop('limit_choices_to', None), |
|---|
| 2095 | | lookup_overrides=kwargs.pop('lookup_overrides', None), |
|---|
| 2096 | | raw_id_admin=kwargs.pop('raw_id_admin', False)) |
|---|
| 2097 | | Field.__init__(self, **kwargs) |
|---|
| 2098 | | |
|---|
| 2099 | | def get_manipulator_field_objs(self): |
|---|
| 2100 | | return [formfields.IntegerField] |
|---|
| 2101 | | |
|---|
| 2102 | | class ManyToManyField(Field): |
|---|
| 2103 | | def __init__(self, to, rel_name=None, **kwargs): |
|---|
| 2104 | | kwargs['name'] = kwargs.get('name', to._meta.module_name) |
|---|
| 2105 | | kwargs['verbose_name'] = kwargs.get('verbose_name', to._meta.verbose_name_plural) |
|---|
| 2106 | | rel_name = rel_name or to._meta.object_name.lower() |
|---|
| 2107 | | kwargs['rel'] = ManyToMany(to, rel_name, |
|---|
| 2108 | | num_in_admin=kwargs.pop('num_in_admin', 0), |
|---|
| 2109 | | related_name=kwargs.pop('related_name', None), |
|---|
| 2110 | | filter_interface=kwargs.pop('filter_interface', None), |
|---|
| 2111 | | limit_choices_to=kwargs.pop('limit_choices_to', None)) |
|---|
| 2112 | | Field.__init__(self, **kwargs) |
|---|
| 2113 | | |
|---|
| 2114 | | def get_manipulator_field_objs(self): |
|---|
| 2115 | | choices = self.get_choices(include_blank=False) |
|---|
| 2116 | | return [curry(formfields.SelectMultipleField, size=min(max(len(choices), 5), 15), choices=choices)] |
|---|
| 2117 | | |
|---|
| 2118 | | def get_m2m_db_table(self, original_opts): |
|---|
| 2119 | | "Returns the name of the many-to-many 'join' table." |
|---|
| 2120 | | return '%s_%s' % (original_opts.db_table, self.name) |
|---|
| 2121 | | |
|---|
| 2122 | | class OneToOneField(IntegerField): |
|---|
| 2123 | | def __init__(self, to, to_field=None, rel_name=None, **kwargs): |
|---|
| 2124 | | kwargs['name'] = kwargs.get('name', 'id') |
|---|
| 2125 | | kwargs['verbose_name'] = kwargs.get('verbose_name', 'ID') |
|---|
| 2126 | | to_field = to_field or to._meta.pk.name |
|---|
| 2127 | | rel_name = rel_name or to._meta.object_name.lower() |
|---|
| 2128 | | kwargs['rel'] = OneToOne(to, rel_name, to_field, |
|---|
| 2129 | | num_in_admin=kwargs.pop('num_in_admin', 0), |
|---|
| 2130 | | edit_inline=kwargs.pop('edit_inline', False), |
|---|
| 2131 | | edit_inline_type=kwargs.pop('edit_inline_type', STACKED), |
|---|
| 2132 | | related_name=kwargs.pop('related_name', None), |
|---|
| 2133 | | limit_choices_to=kwargs.pop('limit_choices_to', None), |
|---|
| 2134 | | lookup_overrides=kwargs.pop('lookup_overrides', None), |
|---|
| 2135 | | raw_id_admin=kwargs.pop('raw_id_admin', False)) |
|---|
| 2136 | | kwargs['primary_key'] = True |
|---|
| 2137 | | IntegerField.__init__(self, **kwargs) |
|---|
| 2138 | | |
|---|
| 2139 | | #################### |
|---|
| 2140 | | # RELATIONSHIPS # |
|---|
| 2141 | | #################### |
|---|
| 2142 | | |
|---|
| 2143 | | class ManyToOne: |
|---|
| 2144 | | def __init__(self, to, name, field_name, num_in_admin=0, min_num_in_admin=None, |
|---|
| 2145 | | max_num_in_admin=None, num_extra_on_change=1, edit_inline=False, edit_inline_type=STACKED, |
|---|
| 2146 | | related_name=None, limit_choices_to=None, lookup_overrides=None, raw_id_admin=False): |
|---|
| 2147 | | try: |
|---|
| 2148 | | self.to = to._meta |
|---|
| 2149 | | except AttributeError: # to._meta doesn't exist, so it must be RECURSIVE_RELATIONSHIP_CONSTANT |
|---|
| 2150 | | assert to == RECURSIVE_RELATIONSHIP_CONSTANT, "'to' must be either a model or the string '%s'" % RECURSIVE_RELATIONSHIP_CONSTANT |
|---|
| 2151 | | self.to = to |
|---|
| 2152 | | self.name, self.field_name = name, field_name |
|---|
| 2153 | | self.num_in_admin, self.edit_inline = num_in_admin, edit_inline |
|---|
| 2154 | | self.min_num_in_admin, self.max_num_in_admin = min_num_in_admin, max_num_in_admin |
|---|
| 2155 | | self.num_extra_on_change = num_extra_on_change |
|---|
| 2156 | | self.edit_inline_type, self.related_name = edit_inline_type, related_name |
|---|
| 2157 | | self.limit_choices_to = limit_choices_to or {} |
|---|
| 2158 | | self.lookup_overrides = lookup_overrides or {} |
|---|
| 2159 | | self.raw_id_admin = raw_id_admin |
|---|
| 2160 | | |
|---|
| 2161 | | def get_cache_name(self): |
|---|
| 2162 | | return '_%s_cache' % self.name |
|---|
| 2163 | | |
|---|
| 2164 | | def get_related_field(self): |
|---|
| 2165 | | "Returns the Field in the 'to' object to which this relationship is tied." |
|---|
| 2166 | | return self.to.get_field(self.field_name) |
|---|
| 2167 | | |
|---|
| 2168 | | class ManyToMany: |
|---|
| 2169 | | def __init__(self, to, name, num_in_admin=0, related_name=None, |
|---|
| 2170 | | filter_interface=None, limit_choices_to=None): |
|---|
| 2171 | | self.to, self.name = to._meta, name |
|---|
| 2172 | | self.num_in_admin = num_in_admin |
|---|
| 2173 | | self.related_name = related_name |
|---|
| 2174 | | self.filter_interface = filter_interface |
|---|
| 2175 | | self.limit_choices_to = limit_choices_to or {} |
|---|
| 2176 | | self.edit_inline = False |
|---|
| 2177 | | |
|---|
| 2178 | | class OneToOne(ManyToOne): |
|---|
| 2179 | | def __init__(self, to, name, field_name, num_in_admin=0, edit_inline=False, |
|---|
| 2180 | | edit_inline_type=STACKED, related_name=None, limit_choices_to=None, lookup_overrides=None, |
|---|
| 2181 | | raw_id_admin=False): |
|---|
| 2182 | | self.to, self.name, self.field_name = to._meta, name, field_name |
|---|
| 2183 | | self.num_in_admin, self.edit_inline = num_in_admin, edit_inline |
|---|
| 2184 | | self.edit_inline_type, self.related_name = edit_inline_type, related_name |
|---|
| 2185 | | self.limit_choices_to = limit_choices_to or {} |
|---|
| 2186 | | self.lookup_overrides = lookup_overrides or {} |
|---|
| 2187 | | self.raw_id_admin = raw_id_admin |
|---|
| 2188 | | |
|---|
| 2189 | | class Admin: |
|---|
| 2190 | | def __init__(self, fields=None, js=None, list_display=None, list_filter=None, date_hierarchy=None, |
|---|
| 2191 | | save_as=False, ordering=None, search_fields=None, save_on_top=False): |
|---|
| 2192 | | self.fields = fields |
|---|
| 2193 | | self.js = js or [] |
|---|
| 2194 | | self.list_display = list_display or ['__repr__'] |
|---|
| 2195 | | self.list_filter = list_filter or [] |
|---|
| 2196 | | self.date_hierarchy = date_hierarchy |
|---|
| 2197 | | self.save_as, self.ordering = save_as, ordering |
|---|
| 2198 | | self.search_fields = search_fields or [] |
|---|
| 2199 | | self.save_on_top = save_on_top |
|---|
| 2200 | | |
|---|
| 2201 | | def get_field_objs(self, opts): |
|---|
| 2202 | | """ |
|---|
| 2203 | | Returns self.fields, except with fields as Field objects instead of |
|---|
| 2204 | | field names. If self.fields is None, defaults to putting every |
|---|
| 2205 | | non-AutoField field with editable=True in a single fieldset. |
|---|
| 2206 | | """ |
|---|
| 2207 | | if self.fields is None: |
|---|
| 2208 | | field_struct = ((None, {'fields': [f.name for f in opts.fields + opts.many_to_many if f.editable and not isinstance(f, AutoField)]}),) |
|---|
| 2209 | | else: |
|---|
| 2210 | | field_struct = self.fields |
|---|
| 2211 | | new_fieldset_list = [] |
|---|
| 2212 | | for fieldset in field_struct: |
|---|
| 2213 | | new_fieldset = [fieldset[0], {}] |
|---|
| 2214 | | new_fieldset[1].update(fieldset[1]) |
|---|
| 2215 | | admin_fields = [] |
|---|
| 2216 | | for field_name_or_list in fieldset[1]['fields']: |
|---|
| 2217 | | if isinstance(field_name_or_list, basestring): |
|---|
| 2218 | | admin_fields.append([opts.get_field(field_name_or_list)]) |
|---|
| 2219 | | else: |
|---|
| 2220 | | admin_fields.append([opts.get_field(field_name) for field_name in field_name_or_list]) |
|---|
| 2221 | | new_fieldset[1]['fields'] = admin_fields |
|---|
| 2222 | | new_fieldset_list.append(new_fieldset) |
|---|
| 2223 | | return new_fieldset_list |
|---|