Exemplo n.º 1
0
    def _check_fields(self, obj):
        """ Check that `fields` only refer to existing fields, doesn't contain
        duplicates. Check if at most one of `fields` and `fieldsets` is defined.
        """

        if obj.fields is None:
            return []
        elif not isinstance(obj.fields, (list, tuple)):
            return must_be('a list or tuple',
                           option='fields',
                           obj=obj,
                           id='admin.E004')
        elif obj.fieldsets:
            return [
                checks.Error(
                    "Both 'fieldsets' and 'fields' are specified.",
                    obj=obj.__class__,
                    id='admin.E005',
                )
            ]
        fields = flatten(obj.fields)
        if len(fields) != len(set(fields)):
            return [
                checks.Error(
                    "The value of 'fields' contains duplicate field(s).",
                    obj=obj.__class__,
                    id='admin.E006',
                )
            ]

        return list(
            chain.from_iterable(
                self._check_field_spec(obj, obj.model, field_name, 'fields')
                for field_name in obj.fields))
Exemplo n.º 2
0
    def _check_field_name(self):
        field_name = self._get_field_name()
        try:
            field = self.model._meta.get_field(field_name)
        except FieldDoesNotExist:
            return [
                checks.Error(
                    "CurrentSiteManager could not find a field named '%s'." %
                    field_name,
                    obj=self,
                    id='sites.E001',
                )
            ]

        if not field.many_to_many and not isinstance(field,
                                                     (models.ForeignKey)):
            return [
                checks.Error(
                    "CurrentSiteManager cannot use '%s.%s' as it is not a foreign key or a many-to-many field."
                    % (self.model._meta.object_name, field_name),
                    obj=self,
                    id='sites.E002',
                )
            ]

        return []
Exemplo n.º 3
0
    def _check_inlines_item(self, obj, model, inline, label):
        """ Check one inline model admin. """
        inline_label = inline.__module__ + '.' + inline.__name__

        from server.contrib.admin.options import InlineModelAdmin

        if not issubclass(inline, InlineModelAdmin):
            return [
                checks.Error(
                    "'%s' must inherit from 'InlineModelAdmin'." %
                    inline_label,
                    obj=obj.__class__,
                    id='admin.E104',
                )
            ]
        elif not inline.model:
            return [
                checks.Error(
                    "'%s' must have a 'model' attribute." % inline_label,
                    obj=obj.__class__,
                    id='admin.E105',
                )
            ]
        elif not issubclass(inline.model, models.Model):
            return must_be('a Model',
                           option='%s.model' % inline_label,
                           obj=obj,
                           id='admin.E106')
        else:
            return inline(model, obj.admin_site).check()
Exemplo n.º 4
0
    def _check_list_filter_item(self, obj, model, item, label):
        """
        Check one item of `list_filter`, i.e. check if it is one of three options:
        1. 'field' -- a basic field filter, possibly w/ relationships (e.g.
           'field__rel')
        2. ('field', SomeFieldListFilter) - a field-based list filter class
        3. SomeListFilter - a non-field list filter class
        """

        from server.contrib.admin import ListFilter, FieldListFilter

        if callable(item) and not isinstance(item, models.Field):
            # If item is option 3, it should be a ListFilter...
            if not issubclass(item, ListFilter):
                return must_inherit_from(parent='ListFilter',
                                         option=label,
                                         obj=obj,
                                         id='admin.E113')
            # ...  but not a FieldListFilter.
            elif issubclass(item, FieldListFilter):
                return [
                    checks.Error(
                        "The value of '%s' must not inherit from 'FieldListFilter'."
                        % label,
                        obj=obj.__class__,
                        id='admin.E114',
                    )
                ]
            else:
                return []
        elif isinstance(item, (tuple, list)):
            # item is option #2
            field, list_filter_class = item
            if not issubclass(list_filter_class, FieldListFilter):
                return must_inherit_from(parent='FieldListFilter',
                                         option='%s[1]' % label,
                                         obj=obj,
                                         id='admin.E115')
            else:
                return []
        else:
            # item is option #1
            field = item

            # Validate the field string
            try:
                get_fields_from_path(model, field)
            except (NotRelationField, FieldDoesNotExist):
                return [
                    checks.Error(
                        "The value of '%s' refers to '%s', which does not refer to a Field."
                        % (label, field),
                        obj=obj.__class__,
                        id='admin.E116',
                    )
                ]
            else:
                return []
Exemplo n.º 5
0
 def _check_list_editable_item(self, obj, model, field_name, label):
     try:
         field = model._meta.get_field(field_name)
     except FieldDoesNotExist:
         return refer_to_missing_field(field=field_name,
                                       option=label,
                                       model=model,
                                       obj=obj,
                                       id='admin.E121')
     else:
         if field_name not in obj.list_display:
             return [
                 checks.Error(
                     "The value of '%s' refers to '%s', which is not "
                     "contained in 'list_display'." % (label, field_name),
                     obj=obj.__class__,
                     id='admin.E122',
                 )
             ]
         elif obj.list_display_links and field_name in obj.list_display_links:
             return [
                 checks.Error(
                     "The value of '%s' cannot be in both 'list_editable' and 'list_display_links'."
                     % field_name,
                     obj=obj.__class__,
                     id='admin.E123',
                 )
             ]
         # If list_display[0] is in list_editable, check that
         # list_display_links is set. See #22792 and #26229 for use cases.
         elif (obj.list_display[0] == field_name
               and not obj.list_display_links
               and obj.list_display_links is not None):
             return [
                 checks.Error(
                     "The value of '%s' refers to the first field in 'list_display' ('%s'), "
                     "which cannot be used unless 'list_display_links' is set."
                     % (label, obj.list_display[0]),
                     obj=obj.__class__,
                     id='admin.E124',
                 )
             ]
         elif not field.editable:
             return [
                 checks.Error(
                     "The value of '%s' refers to '%s', which is not editable through the admin."
                     % (label, field_name),
                     obj=obj.__class__,
                     id='admin.E125',
                 )
             ]
         else:
             return []
Exemplo n.º 6
0
    def _check_fieldsets_item(self, obj, model, fieldset, label, seen_fields):
        """ Check an item of `fieldsets`, i.e. check that this is a pair of a
        set name and a dictionary containing "fields" key. """

        if not isinstance(fieldset, (list, tuple)):
            return must_be('a list or tuple',
                           option=label,
                           obj=obj,
                           id='admin.E008')
        elif len(fieldset) != 2:
            return must_be('of length 2',
                           option=label,
                           obj=obj,
                           id='admin.E009')
        elif not isinstance(fieldset[1], dict):
            return must_be('a dictionary',
                           option='%s[1]' % label,
                           obj=obj,
                           id='admin.E010')
        elif 'fields' not in fieldset[1]:
            return [
                checks.Error(
                    "The value of '%s[1]' must contain the key 'fields'." %
                    label,
                    obj=obj.__class__,
                    id='admin.E011',
                )
            ]
        elif not isinstance(fieldset[1]['fields'], (list, tuple)):
            return must_be('a list or tuple',
                           option="%s[1]['fields']" % label,
                           obj=obj,
                           id='admin.E008')

        seen_fields.extend(flatten(fieldset[1]['fields']))
        if len(seen_fields) != len(set(seen_fields)):
            return [
                checks.Error(
                    "There are duplicate field(s) in '%s[1]'." % label,
                    obj=obj.__class__,
                    id='admin.E012',
                )
            ]
        return list(
            chain.from_iterable(
                self._check_field_spec(obj, model, fieldset_fields,
                                       '%s[1]["fields"]' % label)
                for fieldset_fields in fieldset[1]['fields']))
Exemplo n.º 7
0
 def _check_autocomplete_fields_item(self, obj, model, field_name, label):
     """
     Check that an item in `autocomplete_fields` is a ForeignKey or a
     ManyToManyField and that the item has a related ModelAdmin with
     search_fields defined.
     """
     try:
         field = model._meta.get_field(field_name)
     except FieldDoesNotExist:
         return refer_to_missing_field(field=field_name,
                                       option=label,
                                       model=model,
                                       obj=obj,
                                       id='admin.E037')
     else:
         if not field.many_to_many and not isinstance(
                 field, models.ForeignKey):
             return must_be('a foreign key or a many-to-many field',
                            option=label,
                            obj=obj,
                            id='admin.E038')
         related_admin = obj.admin_site._registry.get(
             field.remote_field.model)
         if related_admin is None:
             return [
                 checks.Error(
                     'An admin for model "%s" has to be registered '
                     'to be referenced by %s.autocomplete_fields.' % (
                         field.remote_field.model.__name__,
                         type(obj).__name__,
                     ),
                     obj=obj.__class__,
                     id='admin.E039',
                 )
             ]
         elif not related_admin.search_fields:
             return [
                 checks.Error(
                     '%s must define "search_fields", because it\'s '
                     'referenced by %s.autocomplete_fields.' % (
                         related_admin.__class__.__name__,
                         type(obj).__name__,
                     ),
                     obj=obj.__class__,
                     id='admin.E040',
                 )
             ]
         return []
Exemplo n.º 8
0
 def _check_action_permission_methods(self, obj):
     """
     Actions with an allowed_permission attribute require the ModelAdmin to
     implement a has_<perm>_permission() method for each permission.
     """
     actions = obj._get_base_actions()
     errors = []
     for func, name, _ in actions:
         if not hasattr(func, 'allowed_permissions'):
             continue
         for permission in func.allowed_permissions:
             method_name = 'has_%s_permission' % permission
             if not hasattr(obj, method_name):
                 errors.append(
                     checks.Error(
                         '%s must define a %s() method for the %s action.' %
                         (
                             obj.__class__.__name__,
                             method_name,
                             func.__name__,
                         ),
                         obj=obj.__class__,
                         id='admin.E129',
                     ))
     return errors
Exemplo n.º 9
0
    def _check_exclude_of_parent_model(self, obj, parent_model):
        # Do not perform more specific checks if the base checks result in an
        # error.
        errors = super()._check_exclude(obj)
        if errors:
            return []

        # Skip if `fk_name` is invalid.
        if self._check_relation(obj, parent_model):
            return []

        if obj.exclude is None:
            return []

        fk = _get_foreign_key(parent_model, obj.model, fk_name=obj.fk_name)
        if fk.name in obj.exclude:
            return [
                checks.Error(
                    "Cannot exclude the field '%s', because it is the foreign key "
                    "to the parent model '%s.%s'." %
                    (fk.name, parent_model._meta.app_label,
                     parent_model._meta.object_name),
                    obj=obj.__class__,
                    id='admin.E201',
                )
            ]
        else:
            return []
Exemplo n.º 10
0
    def _check_prepopulated_fields_key(self, obj, model, field_name, label):
        """ Check a key of `prepopulated_fields` dictionary, i.e. check that it
        is a name of existing field and the field is one of the allowed types.
        """

        try:
            field = model._meta.get_field(field_name)
        except FieldDoesNotExist:
            return refer_to_missing_field(field=field_name,
                                          option=label,
                                          model=model,
                                          obj=obj,
                                          id='admin.E027')
        else:
            if isinstance(field, (models.DateTimeField, models.ForeignKey,
                                  models.ManyToManyField)):
                return [
                    checks.Error(
                        "The value of '%s' refers to '%s', which must not be a DateTimeField, "
                        "a ForeignKey, a OneToOneField, or a ManyToManyField."
                        % (label, field_name),
                        obj=obj.__class__,
                        id='admin.E028',
                    )
                ]
            else:
                return []
Exemplo n.º 11
0
    def _check_date_hierarchy(self, obj):
        """ Check that date_hierarchy refers to DateField or DateTimeField. """

        if obj.date_hierarchy is None:
            return []
        else:
            try:
                field = get_fields_from_path(obj.model, obj.date_hierarchy)[-1]
            except (NotRelationField, FieldDoesNotExist):
                return [
                    checks.Error(
                        "The value of 'date_hierarchy' refers to '%s', which "
                        "does not refer to a Field." % obj.date_hierarchy,
                        obj=obj.__class__,
                        id='admin.E127',
                    )
                ]
            else:
                if not isinstance(field,
                                  (models.DateField, models.DateTimeField)):
                    return must_be('a DateField or DateTimeField',
                                   option='date_hierarchy',
                                   obj=obj,
                                   id='admin.E128')
                else:
                    return []
Exemplo n.º 12
0
    def _check_radio_fields_key(self, obj, model, field_name, label):
        """ Check that a key of `radio_fields` dictionary is name of existing
        field and that the field is a ForeignKey or has `choices` defined. """

        try:
            field = model._meta.get_field(field_name)
        except FieldDoesNotExist:
            return refer_to_missing_field(field=field_name,
                                          option=label,
                                          model=model,
                                          obj=obj,
                                          id='admin.E022')
        else:
            if not (isinstance(field, models.ForeignKey) or field.choices):
                return [
                    checks.Error(
                        "The value of '%s' refers to '%s', which is not an "
                        "instance of ForeignKey, and does not have a 'choices' definition."
                        % (label, field_name),
                        obj=obj.__class__,
                        id='admin.E023',
                    )
                ]
            else:
                return []
Exemplo n.º 13
0
    def check_field_type(self, field, field_type):
        """
        MySQL has the following field length restriction:
        No character (varchar) fields can have a length exceeding 255
        characters if they have a unique index on them.
        MySQL doesn't support a database index on some data types.
        """
        errors = []
        if (field_type.startswith('varchar') and field.unique and
                (field.max_length is None or int(field.max_length) > 255)):
            errors.append(
                checks.Error(
                    'MySQL does not allow unique CharFields to have a max_length > 255.',
                    obj=field,
                    id='mysql.E001',
                )
            )

        if field.db_index and field_type.lower() in self.connection._limited_data_types:
            errors.append(
                checks.Warning(
                    'MySQL does not support a database index on %s columns.'
                    % field_type,
                    hint=(
                        "An index won't be created. Silence this warning if "
                        "you don't care about it."
                    ),
                    obj=field,
                    id='fields.W162',
                )
            )
        return errors
Exemplo n.º 14
0
 def _check_field_spec_item(self, obj, model, field_name, label):
     if field_name in obj.readonly_fields:
         # Stuff can be put in fields that isn't actually a model field if
         # it's in readonly_fields, readonly_fields will handle the
         # validation of such things.
         return []
     else:
         try:
             field = model._meta.get_field(field_name)
         except FieldDoesNotExist:
             # If we can't find a field on the model that matches, it could
             # be an extra field on the form.
             return []
         else:
             if (isinstance(field, models.ManyToManyField)
                     and not field.remote_field.through._meta.auto_created):
                 return [
                     checks.Error(
                         "The value of '%s' cannot include the ManyToManyField '%s', "
                         "because that field manually specifies a relationship model."
                         % (label, field_name),
                         obj=obj.__class__,
                         id='admin.E013',
                     )
                 ]
             else:
                 return []
Exemplo n.º 15
0
 def _check_content_type_field(self):
     """
     Check if field named `field_name` in model `model` exists and is a
     valid content_type field (is a ForeignKey to ContentType).
     """
     try:
         field = self.model._meta.get_field(self.ct_field)
     except FieldDoesNotExist:
         return [
             checks.Error(
                 "The GenericForeignKey content type references the "
                 "nonexistent field '%s.%s'." %
                 (self.model._meta.object_name, self.ct_field),
                 obj=self,
                 id='contenttypes.E002',
             )
         ]
     else:
         if not isinstance(field, models.ForeignKey):
             return [
                 checks.Error(
                     "'%s.%s' is not a ForeignKey." %
                     (self.model._meta.object_name, self.ct_field),
                     hint=
                     ("GenericForeignKeys must use a ForeignKey to "
                      "'contenttypes.ContentType' as the 'content_type' field."
                      ),
                     obj=self,
                     id='contenttypes.E003',
                 )
             ]
         elif field.remote_field.model != ContentType:
             return [
                 checks.Error(
                     "'%s.%s' is not a ForeignKey to 'contenttypes.ContentType'."
                     % (self.model._meta.object_name, self.ct_field),
                     hint=
                     ("GenericForeignKeys must use a ForeignKey to "
                      "'contenttypes.ContentType' as the 'content_type' field."
                      ),
                     obj=self,
                     id='contenttypes.E004',
                 )
             ]
         else:
             return []
Exemplo n.º 16
0
def must_inherit_from(parent, option, obj, id):
    return [
        checks.Error(
            "The value of '%s' must inherit from '%s'." % (option, parent),
            obj=obj.__class__,
            id=id,
        ),
    ]
Exemplo n.º 17
0
def must_be(type, option, obj, id):
    return [
        checks.Error(
            "The value of '%s' must be %s." % (option, type),
            obj=obj.__class__,
            id=id,
        ),
    ]
Exemplo n.º 18
0
 def _check_relation(self, obj, parent_model):
     try:
         _get_foreign_key(parent_model, obj.model, fk_name=obj.fk_name)
     except ValueError as e:
         return [
             checks.Error(e.args[0], obj=obj.__class__, id='admin.E202')
         ]
     else:
         return []
Exemplo n.º 19
0
def refer_to_missing_field(field, option, model, obj, id):
    return [
        checks.Error(
            "The value of '%s' refers to '%s', which is not an attribute of '%s.%s'."
            % (option, field, model._meta.app_label, model._meta.object_name),
            obj=obj.__class__,
            id=id,
        ),
    ]
Exemplo n.º 20
0
 def check(self, **kwargs):
     errors = super().check(**kwargs)
     if self.base_field.remote_field:
         errors.append(
             checks.Error('Base field for array cannot be a related field.',
                          obj=self,
                          id='postgres.E002'))
     else:
         # Remove the field name checks as they are not needed here.
         base_errors = self.base_field.check()
         if base_errors:
             messages = '\n    '.join('%s (%s)' % (error.msg, error.id)
                                      for error in base_errors)
             errors.append(
                 checks.Error('Base field for array has errors:\n    %s' %
                              messages,
                              obj=self,
                              id='postgres.E001'))
     return errors
Exemplo n.º 21
0
 def _check_field_name(self):
     if self.name.endswith("_"):
         return [
             checks.Error(
                 'Field names must not end with an underscore.',
                 obj=self,
                 id='fields.E001',
             )
         ]
     else:
         return []
Exemplo n.º 22
0
 def _check_primary_key(self):
     if self._primary_key_set_explicitly:
         return [
             checks.Error(
                 "'primary_key' is not a valid argument for a %s." % self.__class__.__name__,
                 obj=self,
                 id='fields.E201',
             )
         ]
     else:
         return []
Exemplo n.º 23
0
 def _check_view_on_site_url(self, obj):
     if not callable(obj.view_on_site) and not isinstance(
             obj.view_on_site, bool):
         return [
             checks.Error(
                 "The value of 'view_on_site' must be a callable or a boolean value.",
                 obj=obj.__class__,
                 id='admin.E025',
             )
         ]
     else:
         return []
Exemplo n.º 24
0
 def _check_list_display_links_item(self, obj, field_name, label):
     if field_name not in obj.list_display:
         return [
             checks.Error(
                 "The value of '%s' refers to '%s', which is not defined in 'list_display'."
                 % (label, field_name),
                 obj=obj.__class__,
                 id='admin.E111',
             )
         ]
     else:
         return []
Exemplo n.º 25
0
 def _check_upload_to(self):
     if isinstance(self.upload_to, str) and self.upload_to.startswith('/'):
         return [
             checks.Error(
                 "%s's 'upload_to' argument must be a relative path, not an "
                 "absolute path." % self.__class__.__name__,
                 obj=self,
                 id='fields.E202',
                 hint='Remove the leading slash.',
             )
         ]
     else:
         return []
Exemplo n.º 26
0
 def _check_object_id_field(self):
     try:
         self.model._meta.get_field(self.fk_field)
     except FieldDoesNotExist:
         return [
             checks.Error(
                 "The GenericForeignKey object ID references the "
                 "nonexistent field '%s'." % self.fk_field,
                 obj=self,
                 id='contenttypes.E001',
             )
         ]
     else:
         return []
Exemplo n.º 27
0
def check_dependencies(**kwargs):
    """
    Check that the admin's dependencies are correctly installed.
    """
    errors = []
    # contrib.contenttypes must be installed.
    if not apps.is_installed('server.contrib.contenttypes'):
        missing_app = checks.Error(
            "'server.contrib.contenttypes' must be in INSTALLED_APPS in order "
            "to use the admin application.",
            id="admin.E401",
        )
        errors.append(missing_app)
    # The auth context processor must be installed if using the default
    # authentication backend.
    try:
        default_template_engine = Engine.get_default()
    except Exception:
        # Skip this non-critical check:
        # 1. if the user has a non-trivial TEMPLATES setting and Server
        #    can't find a default template engine
        # 2. if anything goes wrong while loading template engines, in
        #    order to avoid raising an exception from a confusing location
        # Catching ImproperlyConfigured suffices for 1. but 2. requires
        # catching all exceptions.
        pass
    else:
        if ('server.contrib.auth.context_processors.auth'
                not in default_template_engine.context_processors
                and 'server.contrib.auth.backends.ModelBackend'
                in settings.AUTHENTICATION_BACKENDS):
            missing_template = checks.Error(
                "'server.contrib.auth.context_processors.auth' must be in "
                "TEMPLATES in order to use the admin application.",
                id="admin.E402")
            errors.append(missing_template)
    return errors
Exemplo n.º 28
0
 def _check_list_display_item(self, obj, model, item, label):
     if callable(item):
         return []
     elif hasattr(obj, item):
         return []
     elif hasattr(model, item):
         try:
             field = model._meta.get_field(item)
         except FieldDoesNotExist:
             return []
         else:
             if isinstance(field, models.ManyToManyField):
                 return [
                     checks.Error(
                         "The value of '%s' must not be a ManyToManyField."
                         % label,
                         obj=obj.__class__,
                         id='admin.E109',
                     )
                 ]
             return []
     else:
         return [
             checks.Error(
                 "The value of '%s' refers to '%s', which is not a callable, "
                 "an attribute of '%s', or an attribute or method on '%s.%s'."
                 % (
                     label,
                     item,
                     obj.__class__.__name__,
                     model._meta.app_label,
                     model._meta.object_name,
                 ),
                 obj=obj.__class__,
                 id='admin.E108',
             )
         ]
Exemplo n.º 29
0
 def _check_image_library_installed(self):
     try:
         from PIL import Image  # NOQA
     except ImportError:
         return [
             checks.Error(
                 'Cannot use ImageField because Pillow is not installed.',
                 hint=('Get Pillow at https://pypi.org/project/Pillow/ '
                       'or run command "pip install Pillow".'),
                 obj=self,
                 id='fields.E210',
             )
         ]
     else:
         return []
Exemplo n.º 30
0
    def _check_radio_fields_value(self, obj, val, label):
        """ Check type of a value of `radio_fields` dictionary. """

        from server.contrib.admin.options import HORIZONTAL, VERTICAL

        if val not in (HORIZONTAL, VERTICAL):
            return [
                checks.Error(
                    "The value of '%s' must be either admin.HORIZONTAL or admin.VERTICAL."
                    % label,
                    obj=obj.__class__,
                    id='admin.E024',
                )
            ]
        else:
            return []