{"id":6013,"library":"nplusone","title":"Nplusone","description":"Nplusone is a Python library designed to detect N+1 query problems in Object-Relational Mappers (ORMs) during development. It supports popular ORMs like SQLAlchemy, Peewee, and the Django ORM. The library monitors database interactions and emits warnings or raises exceptions when potentially inefficient lazy loads or unnecessary eager loads are detected. The current version is 1.0.0, released in May 2018, and it appears to have a low release cadence, indicating a mature and stable project.","status":"active","version":"1.0.0","language":"en","source_language":"en","source_url":"https://github.com/jmcarp/nplusone","tags":["ORM","N+1 query","performance","profiling","Django","SQLAlchemy","Peewee"],"install":[{"cmd":"pip install nplusone","lang":"bash","label":"Install nplusone"}],"dependencies":[{"reason":"Required for Django ORM integration if using Django.","package":"Django","optional":true},{"reason":"Required for SQLAlchemy ORM integration if using SQLAlchemy.","package":"SQLAlchemy","optional":true},{"reason":"Required for Peewee ORM integration if using Peewee.","package":"Peewee","optional":true}],"imports":[{"note":"Used for generic profiling outside of framework integrations.","symbol":"Profiler","correct":"from nplusone.core.profiler import Profiler"},{"note":"Used for Django framework integration.","symbol":"NPlusOneMiddleware","correct":"from nplusone.ext.django import NPlusOneMiddleware"},{"note":"Initializes SQLAlchemy integration within the profiler.","symbol":"ext.sqlalchemy","correct":"import nplusone.ext.sqlalchemy"}],"quickstart":{"code":"import logging\nfrom nplusone.core.profiler import Profiler\nimport nplusone.ext.sqlalchemy\n\n# Configure a logger to capture nplusone warnings\nlogger = logging.getLogger('nplusone')\nlogger.setLevel(logging.WARN)\nhandler = logging.StreamHandler()\nlogger.addHandler(handler)\n\n# --- Simulate an SQLAlchemy setup ---\nfrom sqlalchemy import create_engine, Column, Integer, String, ForeignKey\nfrom sqlalchemy.orm import sessionmaker, relationship\nfrom sqlalchemy.ext.declarative import declarative_base\n\nBase = declarative_base()\n\nclass Artist(Base):\n    __tablename__ = 'artists'\n    id = Column(Integer, primary_key=True)\n    name = Column(String)\n    songs = relationship('Song', back_populates='artist')\n\nclass Song(Base):\n    __tablename__ = 'songs'\n    id = Column(Integer, primary_key=True)\n    title = Column(String)\n    artist_id = Column(Integer, ForeignKey('artists.id'))\n    artist = relationship('Artist', back_populates='songs')\n\nengine = create_engine('sqlite:///:memory:')\nBase.metadata.create_all(engine)\nSession = sessionmaker(bind=engine)\nsession = Session()\n\n# Add some data\nartist1 = Artist(name='Artist One')\nartist2 = Artist(name='Artist Two')\nsession.add_all([artist1, artist2])\nsession.commit()\n\nsong1 = Song(title='Song A', artist=artist1)\nsong2 = Song(title='Song B', artist=artist1)\nsong3 = Song(title='Song C', artist=artist2)\nsession.add_all([song1, song2, song3])\nsession.commit()\n\n# --- Nplusone profiling ---\nprint('--- Starting nplusone profiling ---')\nwith Profiler():\n    songs = session.query(Song).all()\n    print(f'Fetched {len(songs)} songs.')\n    # This will trigger N+1 queries if artists are not eagerly loaded\n    for song in songs:\n        print(f'  Song: {song.title}, Artist: {song.artist.name}')\n\nprint('--- Profiling complete ---')\n\n# Example of how to raise an NPlusOneError for tests (optional)\n# from nplusone.core.exceptions import NPlusOneError\n# import os\n# os.environ['NPLUSONE_RAISE'] = 'True' # Set this environment variable or config option\n# try:\n#     with Profiler():\n#         songs = session.query(Song).all()\n#         for song in songs:\n#             _ = song.artist.name\n# except NPlusOneError as e:\n#     print(f'Caught expected NPlusOneError: {e}')\n# os.environ['NPLUSONE_RAISE'] = '' # Reset for other tests\n","lang":"python","description":"This quickstart demonstrates how to use `nplusone` with SQLAlchemy. It sets up a simple ORM model, adds some data, and then uses the `Profiler` context manager to detect N+1 queries when accessing related `Artist` objects within a loop without eager loading. Warnings will be logged to the console."},"warnings":[{"fix":"Ensure nplusone is only included in your development or test dependencies and configurations (e.g., `requirements-dev.txt`, `DEBUG=True` blocks in Django settings).","message":"Nplusone is intended for development and testing environments only. It should NOT be deployed to production environments as it can introduce performance overhead.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Set `NPLUSONE_RAISE = True` in your application's configuration or as an environment variable (e.g., `os.environ['NPLUSONE_RAISE'] = 'True'`). You can also specify the exception type using `NPLUSONE_ERROR`.","message":"By default, nplusone logs warnings. To make it raise an `NPlusOneError` (useful for failing tests), you need to set the `NPLUSONE_RAISE` configuration option (e.g., via an environment variable or Django settings).","severity":"gotcha","affected_versions":"All versions"},{"fix":"For Django, add `'nplusone.ext.django'` to `INSTALLED_APPS` and `'nplusone.ext.django.NPlusOneMiddleware'` to `MIDDLEWARE`. For generic WSGI apps or outside HTTP requests, use the `Profiler` context manager and import the relevant ORM extension (e.g., `import nplusone.ext.sqlalchemy`).","message":"When integrating with specific frameworks like Django or Flask-SQLAlchemy, remember to add the relevant middleware (`NPlusOneMiddleware`) and configure `INSTALLED_APPS` (for Django) to enable automatic detection within the request-response cycle.","severity":"gotcha","affected_versions":"All versions"}],"env_vars":null,"last_verified":"2026-04-14T00:00:00.000Z","next_check":"2026-07-13T00:00:00.000Z"}