🌐 Tiếng Việt — queryset rules (DOL001–DOL007)
Django ORM Lens ships two rule surfaces:
- Editor rules (
DOL###) — 16 line-oriented static checks that run inside the VS Code extension on every.pyfile. Findings appear in the Problems panel under the sourceDjango ORM Lens, link to these pages from the diagnostic code, and — where a fix is safe to express as a text edit — carry a QuickFix lightbulb. Detection is regex-based with bounded windows; no Python process is involved. - CLI / CI analyzers — AST-based checks in the Python package (
pip install django-orm-lens) for terminals and pipelines:migration-risk,nplusone,blast-radius— which joins migration risks with the code that still references what they change — anddrift, amakemigrations --checkthat needs no Django boot.
Severity mirrors VS Code's four diagnostic levels: error, warning, info, hint. Every rule has a default (listed below); override per rule in .vscode/settings.json via djangoOrmLens.rules — e.g. {"djangoOrmLens.rules": {"DOL013": "error", "DOL007": "off"}}.
Applicability follows Clippy's semantics. It is a property of each individual finding and gates whether an editor may apply the fix unattended:
| Applicability | Meaning |
|---|---|
safe |
Semantically equivalent, always correct to apply. Eligible for auto-apply and "Fix All". |
suggestion |
Usually right but may need review — offered as a QuickFix, never included in "Fix All". |
unsafe |
Likely-correct but breaks in edge cases — surfaced as a diagnostic only, never auto-applied. |
| Code | Rule | Category | Default severity | Applicability |
|---|---|---|---|---|
| DOL001 | Prefer .exists() over .count() > 0 |
queryset | info | safe |
| DOL002 | Prefer not .exists() over .count() == 0 |
queryset | info | safe |
| DOL003 | Prefer not .exists() over .first() is None |
queryset | info | safe |
| DOL004 | Prefer .exists() over .first() is not None |
queryset | info | safe |
| DOL005 | Consider Q(...) over .filter().exclude() chain |
queryset | hint | suggestion |
| DOL006 | Drop list() around a QuerySet in for-loop |
queryset | info | safe |
| DOL007 | Possible N+1: attribute access inside for-loop | queryset | warning | unsafe |
| DOL008 | Field name in a lookup looks misspelled | correctness | warning | suggestion |
| DOL011 | null=True on CharField/TextField |
model | warning | suggestion |
| DOL012 | Model without __str__ method |
model | info | suggestion |
| DOL013 | ForeignKey without on_delete |
model | error | suggestion |
| DOL014 | CharField without max_length |
model | error | suggestion |
| DOL015 | TextField with max_length has no DB effect |
model | hint | suggestion |
| DOL021 | datetime.now() should be timezone.now() |
datetime | warning | suggestion |
| DOL022 | datetime.utcnow() is deprecated |
datetime | warning | suggestion |
| DOL031 | render() with locals() as context |
forms | warning | suggestion |
| DOL032 | fields = '__all__' in Meta |
forms | warning | unsafe |
# django-orm-lens-disable-next-line DOL007 (next line; comma-separate for several codes)
qs.count() > 0 # django-orm-lens-disable-line DOL001
# django-orm-lens-disable DOL011 (own line — disables for the rest of the file)Ruff-style bulk selection is also available: djangoOrmLens.rulesSelect (e.g. ["DOL0"]) and djangoOrmLens.rulesIgnore (e.g. ["DOL03"]).
These run from the Python CLI, not the editor. Both exit non-zero on findings (see each page for exact semantics) and emit --format sarif (SARIF 2.1.0 for GitHub Code Scanning) or --format github (workflow commands for zero-setup PR annotations).
- Migration risk rules — 16 rules over
<app>/migrations/*.pyflagging operations that are dangerous on production databases. Run withdjango-orm-lens migration-risk. - Static N+1 detector — flags FK / O2O / M2M / reverse-manager access inside for-loops when the source queryset has no matching
select_related/prefetch_related. Run withdjango-orm-lens nplusone.