Last active
July 5, 2025 13:06
-
-
Save hakib/e2e50d41d19a6984dc63bd94580c8647 to your computer and use it in GitHub Desktop.
Revisions
-
hakib revised this gist
Aug 27, 2018 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -86,7 +86,7 @@ def check_model(model): else: value = verbose_name.value.args[0].s # type: ignore if not all(w.islower() or w.isupper() or w.isdigit() for w in value.split(' ')): yield django.core.checks.Warning( 'Words in verbose name must be all upper case or all lower case', hint='Change verbose name to "{}".'.format(value.lower()), -
hakib created this gist
Jun 1, 2018 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,191 @@ """ Custom django checks. H001: Field has no verbose name. H002: Verbose name should use gettext. H003: Words in verbose name must be all upper case or all lower case. H004: Help text should use gettext. H005: Model must define class Meta. H006: Model has no verbose name. H007: Model has no verbose name plural. H008: Must set db_index explicitly on a ForeignKey field. """ import inspect import ast import django.apps import django.core.checks from django.db.models import FieldDoesNotExist def get_argument(node, arg): for kw in node.value.keywords: if kw.arg == arg: return kw return None def is_gettext_node(node): if not isinstance(node, ast.Call): return False # We assume gettext is aliased '_'. if not node.func.id == '_': # type: ignore return False return True def check_model(model): """Check a single model. Yields (django.checks.CheckMessage) """ model_source = inspect.getsource(model) model_node = ast.parse(model_source) assert isinstance(model_node, ast.Module) class_meta = None for node in model_node.body[0].body: # type: ignore if isinstance(node, ast.ClassDef): # class Meta if node.name == 'Meta': class_meta = node # Fields elif isinstance(node, ast.Assign): if len(node.targets) != 1: continue if not isinstance(node.targets[0], ast.Name): continue field_name = node.targets[0].id try: field = model._meta.get_field(field_name) except FieldDoesNotExist: continue verbose_name = get_argument(node, 'verbose_name') if verbose_name is None: yield django.core.checks.Warning( 'Field has no verbose name', hint='Set verbose name on the field.', obj=field, id='H001', ) else: if not is_gettext_node(verbose_name.value): yield django.core.checks.Warning( 'Verbose name should use gettext', hint='Use gettext on the verbose name.', obj=field, id='H002', ) else: value = verbose_name.value.args[0].s # type: ignore if not all(w.islower() or w.isupper() for w in value.split(' ')): yield django.core.checks.Warning( 'Words in verbose name must be all upper case or all lower case', hint='Change verbose name to "{}".'.format(value.lower()), obj=field, id='H003', ) help_text = get_argument(node, 'help_text') if help_text is not None: if not is_gettext_node(help_text.value): yield django.core.checks.Warning( 'Help text should use gettext', hint='Use gettext on the help text.', obj=field, id='H004', ) if field.many_to_one: db_index = get_argument(node, 'db_index') if db_index is None: yield django.core.checks.Warning( 'Must set db_index explicitly on a ForeignKey field', hint='Set db_index on the field.', obj=field, id='H008', ) if class_meta is None: yield django.core.checks.Warning( 'Model "{}" must define class Meta'.format(model._meta.model_name), hint='Add class Meta to model "{}".'.format(model._meta.model_name), obj=model, id='H005', ) else: verbose_name = None verbose_name_plural = None for node in ast.iter_child_nodes(class_meta): if not isinstance(node, ast.Assign): continue if not isinstance(node.targets[0], ast.Name): continue attr = node.targets[0].id if attr == 'verbose_name': verbose_name = node if attr == 'verbose_name_plural': verbose_name_plural = node if verbose_name is None: yield django.core.checks.Warning( 'Model has no verbose name', hint='Add verbose_name to class Meta.', obj=model, id='H006', ) elif not is_gettext_node(verbose_name.value): yield django.core.checks.Warning( 'Verbose name in class Meta should use gettext', hint='Use gettext on the verbose_name of class Meta "{}".'.format(model._meta.model_name), obj=model, id='H002', ) if verbose_name_plural is None: yield django.core.checks.Warning( 'Model has no verbose name plural', hint='Add verbose_name_plural to class Meta.', obj=model, id='H007', ) elif not is_gettext_node(verbose_name_plural.value): yield django.core.checks.Warning( 'Verbose name plural in class Meta should use gettext', hint='Use gettext on the verbose_name_plural of class Meta "{}".'.format(model._meta.model_name), obj=model, id='H002', ) @django.core.checks.register(django.core.checks.Tags.models) def check_models(app_configs, **kwargs): errors = [] for app in django.apps.apps.get_app_configs(): # Skip third party apps. if app.path.find('site-packages') > -1: continue for model in app.get_models(): for check_message in check_model(model): errors.append(check_message) return errors