diff --git a/core/management/commands/find_empty_fields.py b/core/management/commands/find_empty_fields.py new file mode 100644 index 0000000..09f2496 --- /dev/null +++ b/core/management/commands/find_empty_fields.py @@ -0,0 +1,124 @@ +from django.core.management.base import BaseCommand +from django.apps import apps +from django.db.models import Q, CharField, TextField + +"""Completely written by https://gemini.google.com/ 2.5 +""" + +def get_all_project_models(): + """ + Returns a list of all concrete model.Model classes in the Django project. + It ignores abstract models and models from third-party apps that aren't + part of the project's own apps. + """ + # You can customize this list to include/exclude specific apps + # For example: installed_apps = settings.INSTALLED_APPS + all_models = [] + # This gathers all models from all installed apps. + for app_config in apps.get_app_configs(): + all_models.extend(list(app_config.get_models())) + return all_models + + +def find_empty_or_null_fields(model_class): + """ + Takes a model class and checks every field. + + Returns a list of field names for which all database entries + are either NULL or an empty string. + """ + completely_empty_fields = [] + + # Get the total number of records for this model. + total_records = model_class.objects.count() + + # If there are no records, all fields are technically "empty". + # We return an empty list to avoid reporting every field from an empty table. + if total_records == 0: + return [] + + # Iterate over all concrete fields of the model. + for field in model_class._meta.get_fields(): + # We only want to check actual database columns, not relations. + if not hasattr(field, 'column'): + continue + + field_name = field.name + + # Build a query to find records that have a meaningful value. + # This is more efficient than counting all null/empty records. + # We exclude records that are NULL. + query_has_value = model_class.objects.exclude(Q(**{f'{field_name}__isnull': True})) + + # For text-based fields, we also exclude empty strings. + if isinstance(field, (CharField, TextField)): + query_has_value = query_has_value.exclude(Q(**{f'{field_name}': ''})) + + # If the query for records WITH a value returns FALSE (no such records exist), + # it means all records for this field are empty or null. + if not query_has_value.exists(): + completely_empty_fields.append(field_name) + + return completely_empty_fields + + +class Command(BaseCommand): + help = "Scans all project models to find fields where all entries are empty or null." + + def handle(self, *args, **options): + self.stdout.write(self.style.SUCCESS("šŸš€ Starting scan for empty or null fields across all models...")) + + all_models = get_all_project_models() + found_any = False + + for model in all_models: + total_records = model.objects.count() + model_name = f"{model._meta.app_label}.{model._meta.object_name}" + self.stdout.write(f"\nšŸ” Checking model: {self.style.HTTP_INFO(model_name)} ({total_records} instances found)") + + empty_fields = find_empty_or_null_fields(model) + + if empty_fields: + found_any = True + for field_name in empty_fields: + self.stdout.write( + self.style.WARNING(f" -> Field '{field_name}' is completely empty or null.") + ) + else: + self.stdout.write(self.style.SUCCESS(" āœ… All fields contain data.")) + + if not found_any: + self.stdout.write(self.style.SUCCESS("\nšŸŽ‰ Scan complete. No fields were found to be universally empty or null.")) + + +""" + +### How to Run the Command + +After saving the file, you can run your new command from your project's root directory (where `manage.py` is located): + +bash +uv run manage.py find_empty_fields + + +### Example Output + +The output in your terminal will look something like this: + +``` +šŸš€ Starting scan for empty or null fields across all models... + +šŸ” Checking model: auth.Group + āœ… All fields contain data. + +šŸ” Checking model: auth.User + -> Field 'last_name' is completely empty or null. + -> Field 'first_name' is completely empty or null. + +šŸ” Checking model: products.Product + -> Field 'notes' is completely empty or null. + -> Field 'discount_code' is completely empty or null. + +šŸ” Checking model: products.Category + āœ… All fields contain data. +""" \ No newline at end of file