Your Django code review copilot

Django Doctor suggests Django improvements right inside your pull request.

django-doctorbotsuggested changes just now
migration.py
+
class Migration(migrations.Migration):
+
    dependencies = [("core", "0001_initial.py")]
+
    operations = [RunPython(forwards)]
Suggested changes
-
    operations = [RunPython(forwards)]
+
    operations = [RunPython(forwards, RunPython.noop)]
Commit suggestion

It's good to, as a minimum, specify noop in RunPython so the migration can be skipped when going backwards, and even better to specify a function that undoes the migration.

Read more
template.html
+
<img src="/static/logo.png" />
Suggested changes
-
<img src="/static/logo.png" />
+
{% load static %}
+
<img src="{% static 'logo.png' %}" />
Commit suggestion

Hard-coding static asset urls is brittle because the place the files are stored depends on the `STATICFILES_STORAGE` used - so if in prod the storage backend uploads to S3 or even renames the file then this hard-coded URL will break.

Using "{% static ... %}" solves that as it knows exactly where the files are stored.

Read more
tasks.py
+
def trigger_tasks(queryset):
+
    for item in queryset:
+
        run_async_task(item.page.id)
Suggested changes
-
        run_async_task(item.page.id)
+
        run_async_task(item.page_id)
Commit suggestion

When working with foreign keys, accessing the related field will result in a database read. That can be eliminated by using *_id, which is the foreign key value that Django has already cached on the object to make this scenario more efficient.

Read more
settings.py
+
MIDDLEWARE = [
+
    'django.middleware.common.CommonMiddleware',
+
    'django.contrib.sessions.middleware.SessionMiddleware',
+
    ...
Suggested changes
+
    'django.middleware.csrf.CsrfViewMiddleware',
Expand 2 lines ...
Commit suggestion

Your website is vulnerable to CSRF attacks because the MIDDLEWARE setting is missing CsrfViewMiddleware - so a hacker can fool your website into thinking a request is coming from a logged in user.

Read more
+
]
views.py
+
def my_view(request):
+
    url = reverse_lazy('foo')
Suggested changes
-
    url = reverse_lazy('foo')
+
    url = reverse('foo')
Commit suggestion

Using reverse(...) is better than using reverse_lazy(...) when the url is being reversed after URLConf has been loaded.

Read more
Update views.py
Over 3000 teams use Django Doctor to write better code, release faster, and save time.
  • Department for International Trade
  • Giant
  • Motley fool
  • Lift Interactive
  • Lightmatter
  • Media Interactive
  • We Make Services
  • Sumo

Protect every code change automatically

Django Doctor reviews your GitHub pull requests to prevent adding vulnerabilities, performance, or maintainability issues to your code. The core review runs in the cloud so there is nothing to install locally. Cutting edge technology achieves near-zero noise for developers so you can follow best practices without changing how you work.

"Extremely positive. Django Doctor suggested useful changes, giving our senior developers time back."

Jon Atkinson, Technical Director at Giant

More than a linter

Django Doctor gives clear and actionable advice, which you can commit to your branch directly from your pull request. No more waiting the CI build to finish then reading error logs, tabbing to your text editor, committing the fixes and pushing. Accept the changes right inside your pull request with no context switching.
+
from django.conf import settings
+
from django.contrib import admin
+
+
	
+
urlpatterns = [...]
+
	
+
if settings.DEBUG:
Suggested changes
-
if settings.DEBUG:
+
if settings.FEATURE_ADMIN_ENABLED:
Expand 2 lines ...
Commit suggestion

Your code is harder to test in isolation because the value of settings.DEBUG affects other Django behaviours including error handling. Consider using a feature flag instead.

Read more
+
    # not exposing admin to prod so it can't be hacked
+
    urlpatterns.append(path('admin/', admin.site.urls))
Enforce best practice. Skip the docs and stay confident you're following best practice. With Django Doctor you stay focused right in your pull request.
+
def task(admin_blog_ids):
+
    queryset = CommentModel.objects.all()
+
    if len(queryset) > 100:
Suggested changes
-
    if len(queryset) > 100:
+
    if queryset.count() > 100:
Commit suggestion

len(queryset) performs the count at application level. That is much less efficient than doing queryset.count(), which does the calculation at database level and just returns the count.

Read more
+
        send_email_to_admin(queryset)
+
from example.config import settings
Suggested changes
-
from example.config import settings
+
from django.conf import settings
Commit suggestion

Using from django.conf import settings simplifies the code and makes it more maintainable.

Read more
+
from django.db import models
Reclaim time. Django Doctor works great for quickly detecting mistakes humans might miss, and even links you to the deep archive of best practice articles to upskill devs.
Prevent bugs. Django Doctor knows when code looks fishy and will raise the alarm. With Django Doctor you can deploy to prod knowing you've got a code reviewer on your side with the consistency and concentration of a robot.
+
urlpatterns = [
+
    path('', Home.as_view(), name="index"),
+
    path('index/', Index.as_view(), name="index"),
Suggested changes
-
    path('index/', Index.as_view(), name="index"),
+
    path('index/', Index.as_view(), name="index-list"),
Commit suggestion

URL names must be unique otherwise reverse('url_name') and {% url 'url_name' %} will link to the "wrong" page half of the time.

Read more
+
]

Improve your productivity

Simplify upgrading Django with our changelog comparison tool. View all changes between two releases: bug fixes, features, and deprecations all in one place rather than manually tabbing through multiple release notes and risking missing something important.

Our price

Individual

Free

forever

Protects every PR: Yes

Suggests the fix: Yes

Codebase audit: Yes

Public repositories: Unlimited

Private repositories: No

Support: No

Add to GitHub
Popular

Organization

$49

per month

Protects every PR: Yes

Suggests the fix: Yes

Codebase audit: Yes

Public repositories: Unlimited

Private repositories: 10

Support: 24/7 email and chat

Unlimited

$99

per month

Protects every PR: Yes

Suggests the fix: Yes

Codebase audit: Yes

Public repositories: Unlimited

Private repositories: Unlimited

Support: 24/7 email and chat