• Get Review Board
  • What's New
  • Products
  • Review Board Code review, image review, and document review
  • Documentation
  • Release Notes
  • Power Pack Enterprise integrations, reports, and enhanced document review
  • Try for 60 Days
  • Purchase
  • RBCommons Review Board as a Service, hosted by us
  • Pricing
  • RBTools Command line tools and Python API for Review Board
  • Documentation
  • Release Notes
  • Review Bot Automated code review, connecting tools you already use
  • Documentation
  • Release Notes
  • RB Gateway Manage Git and Mercurial repositories in your network
  • Documentation
  • Release Notes
  • Learn and Explore
  • What is Code Review?
  • Documentation
  • Frequently Asked Questions
  • Support Options
  • Third-Party Integrations
  • Demo
  • Review Board RBTools Power Pack Review Bot Djblets RB Gateway
    1. Djblets 6.x
    2. Version 6.x
    3. Version 5.x
    4. Version 4.x
    5. Version 3.x
    6. Version 2.x
    7. Version 2.0
    8. Version 1.0
    9. Version 0.9
    10. Djblets Documentation
    11. Guides
    12. Protection Guides
    13. Rate Limiting Operations
  • Home
  • Guides
  • Avatar Services Guides
  • Writing Avatar Services
  • Caching Guides
  • Caching Data
  • Working with Cache Keys
  • Cache Backends
  • Extension Guides
  • Writing Extensions
  • Testing Extensions
  • Feature Checks Guides
  • Introduction to Feature Checks
  • Writing Features
  • Writing Feature Checkers
  • Testing with Feature Checks
  • Integration Guides
  • Supporting Integrations
  • Writing Integrations
  • Dynamic Page Injections
  • Privacy Compliance Guides
  • Getting and Checking Consent
  • Working with Personally Identifiable Information
  • Service Integrations
  • Protection Guides
  • Rate Limiting Operations
  • reCAPTCHA Guides
  • Using reCAPTCHA
  • Registries Guides
  • Writing Registries
  • Web API Guides
  • Writing Web API Resources
  • Adding OAuth2 Support
  • Module and Class References
  • djblets
  • djblets.deprecation
  • djblets.auth.forms
  • djblets.auth.ratelimit
  • djblets.auth.signals
  • djblets.auth.util
  • djblets.auth.views
  • djblets.avatars.errors
  • djblets.avatars.forms
  • djblets.avatars.registry
  • djblets.avatars.services
  • djblets.avatars.services.base
  • djblets.avatars.services.fallback
  • djblets.avatars.services.file_upload
  • djblets.avatars.services.gravatar
  • djblets.avatars.services.url
  • djblets.avatars.settings
  • djblets.cache
  • djblets.cache.backend
  • djblets.cache.backend_compat
  • djblets.cache.context_processors
  • djblets.cache.errors
  • djblets.cache.forwarding_backend
  • djblets.cache.serials
  • djblets.cache.synchronizer
  • djblets.conditions
  • djblets.conditions.choices
  • djblets.conditions.conditions
  • djblets.conditions.errors
  • djblets.conditions.operators
  • djblets.conditions.values
  • djblets.configforms.forms
  • djblets.configforms.mixins
  • djblets.configforms.pages
  • djblets.configforms.registry
  • djblets.configforms.views
  • djblets.datagrid
  • djblets.datagrid.grids
  • djblets.db.backends.mysql.base
  • djblets.db.fields
  • djblets.db.fields.base64_field
  • djblets.db.fields.comma_separated_values_field
  • djblets.db.fields.counter_field
  • djblets.db.fields.json_field
  • djblets.db.fields.modification_timestamp_field
  • djblets.db.fields.relation_counter_field
  • djblets.db.managers
  • djblets.db.query
  • djblets.db.query_catcher
  • djblets.db.query_comparator
  • djblets.db.validators
  • djblets.pagestate
  • djblets.pagestate.injectors
  • djblets.pagestate.middleware
  • djblets.pagestate.state
  • djblets.pagestate.templatetags.djblets_pagestate
  • djblets.extensions
  • djblets.extensions.admin
  • djblets.extensions.errors
  • djblets.extensions.extension
  • djblets.extensions.forms
  • djblets.extensions.hooks
  • djblets.extensions.loaders
  • djblets.extensions.manager
  • djblets.extensions.middleware
  • djblets.extensions.models
  • djblets.extensions.packaging
  • djblets.extensions.resources
  • djblets.extensions.settings
  • djblets.extensions.signals
  • djblets.extensions.staticfiles
  • djblets.extensions.testing
  • djblets.extensions.testing.testcases
  • djblets.extensions.urls
  • djblets.extensions.views
  • djblets.extensions.templatetags.djblets_extensions
  • djblets.features
  • djblets.features.checkers
  • djblets.features.decorators
  • djblets.features.errors
  • djblets.features.feature
  • djblets.features.level
  • djblets.features.registry
  • djblets.features.testing
  • djblets.features.templatetags.features
  • djblets.forms.fields
  • djblets.forms.fieldsets
  • djblets.forms.forms
  • djblets.forms.forms.key_value_form
  • djblets.forms.widgets
  • djblets.gravatars
  • djblets.gravatars.templatetags.gravatars
  • djblets.http.middleware
  • djblets.http.requests
  • djblets.http.responses
  • djblets.integrations.errors
  • djblets.integrations.forms
  • djblets.integrations.hooks
  • djblets.integrations.integration
  • djblets.integrations.manager
  • djblets.integrations.mixins
  • djblets.integrations.models
  • djblets.integrations.urls
  • djblets.integrations.views
  • djblets.log
  • djblets.log.middleware
  • djblets.log.siteconfig
  • djblets.log.urls
  • djblets.log.views
  • djblets.mail.dmarc
  • djblets.mail.message
  • djblets.mail.testing
  • djblets.mail.utils
  • djblets.markdown
  • djblets.markdown.extensions.escape_html
  • djblets.markdown.extensions.wysiwyg
  • djblets.markdown.extensions.wysiwyg_email
  • djblets.pipeline.compilers.es6
  • djblets.pipeline.compilers.less
  • djblets.pipeline.compilers.mixins
  • djblets.pipeline.compilers.rollup
  • djblets.pipeline.compilers.typescript
  • djblets.pipeline.settings
  • djblets.privacy.consent
  • djblets.privacy.consent.base
  • djblets.privacy.consent.common
  • djblets.privacy.consent.errors
  • djblets.privacy.consent.forms
  • djblets.privacy.consent.hooks
  • djblets.privacy.consent.registry
  • djblets.privacy.consent.tracker
  • djblets.privacy.models
  • djblets.privacy.pii
  • djblets.privacy.templatetags.djblets_privacy
  • djblets.protect
  • djblets.protect.locks
  • djblets.protect.ratelimit
  • djblets.recaptcha.mixins
  • djblets.recaptcha.siteconfig
  • djblets.recaptcha.templatetags.djblets_recaptcha
  • djblets.recaptcha.widgets
  • djblets.registries
  • djblets.registries.errors
  • djblets.registries.importer
  • djblets.registries.mixins
  • djblets.registries.registry
  • djblets.registries.signals
  • djblets.secrets
  • djblets.secrets.crypto
  • djblets.secrets.token_generators
  • djblets.secrets.token_generators.base
  • djblets.secrets.token_generators.legacy_sha1
  • djblets.secrets.token_generators.registry
  • djblets.secrets.token_generators.vendor_checksum
  • djblets.siteconfig
  • djblets.siteconfig.admin
  • djblets.siteconfig.context_processors
  • djblets.siteconfig.django_settings
  • djblets.siteconfig.forms
  • djblets.siteconfig.managers
  • djblets.siteconfig.middleware
  • djblets.siteconfig.models
  • djblets.siteconfig.signals
  • djblets.siteconfig.views
  • djblets.template.caches
  • djblets.template.context
  • djblets.template.loaders.conditional_cached
  • djblets.template.loaders.namespaced_app_dirs
  • djblets.testing.decorators
  • djblets.testing.testcases
  • djblets.testing.testrunners
  • djblets.urls.context_processors
  • djblets.urls.decorators
  • djblets.urls.patterns
  • djblets.urls.resolvers
  • djblets.urls.root
  • djblets.urls.staticfiles
  • djblets.util.compat.django.core.cache
  • djblets.util.compat.python.past
  • djblets.util.contextmanagers
  • djblets.util.dates
  • djblets.util.decorators
  • djblets.util.filesystem
  • djblets.util.functional
  • djblets.util.html
  • djblets.util.http
  • djblets.util.humanize
  • djblets.util.json_utils
  • djblets.util.properties
  • djblets.util.serializers
  • djblets.util.symbols
  • djblets.util.templatetags.djblets_deco
  • djblets.util.templatetags.djblets_email
  • djblets.util.templatetags.djblets_forms
  • djblets.util.templatetags.djblets_images
  • djblets.util.templatetags.djblets_js
  • djblets.util.templatetags.djblets_utils
  • djblets.util.typing
  • djblets.util.views
  • djblets.views.generic.base
  • djblets.views.generic.etag
  • djblets.webapi.auth
  • djblets.webapi.auth.backends
  • djblets.webapi.auth.backends.api_tokens
  • djblets.webapi.auth.backends.base
  • djblets.webapi.auth.backends.basic
  • djblets.webapi.auth.backends.oauth2_tokens
  • djblets.webapi.auth.views
  • djblets.webapi.decorators
  • djblets.webapi.encoders
  • djblets.webapi.errors
  • djblets.webapi.fields
  • djblets.webapi.managers
  • djblets.webapi.models
  • djblets.webapi.oauth2_scopes
  • djblets.webapi.resources
  • djblets.webapi.resources.base
  • djblets.webapi.resources.group
  • djblets.webapi.resources.registry
  • djblets.webapi.resources.root
  • djblets.webapi.resources.user
  • djblets.webapi.resources.mixins.api_tokens
  • djblets.webapi.resources.mixins.forms
  • djblets.webapi.resources.mixins.oauth2_tokens
  • djblets.webapi.resources.mixins.queries
  • djblets.webapi.responses
  • djblets.webapi.signals
  • djblets.webapi.testing
  • djblets.webapi.testing.decorators
  • djblets.webapi.testing.testcases
  • General Index
  • Python Module Index
  • Release Notes
  • Rate Limiting Operations¶

    New in version 5.3.

    Djblets provides a generic, reusable mechanism for rate limiting any operation in your application, helping services fail gracefully when overloaded.

    This is useful for rate-limiting:

    • Expensive downloads or calculations

    • SMS-based two-factor auth setup

    • AI requests

    • Form submissions

    • Authentication and API requests (see djblets.auth.ratelimit for a pre-built implementation)

    djblets.protect.ratelimit lets you configure rate limit durations and to check or perform a hit against a rate limit.

    General Usage¶

    It’s up to the consumer to decide what will be rate limited and how.

    Rate limits are represented by RateLimit objects. These define how many hits are allowed in a given time period, and are passed to other rate limit functions.

    Rate limits are checked against keys using check_rate_limit(). These are strings (or, preferably, lists of strings) that identify the resource and entity being rate limited. They might include a username, IP address, or some other identifier.

    The result of a check is a RateLimitUsage object representing the number of hits against the key, the total number allowed, the time remaining until the limit resets, and whether the limit has been hit.

    Defining a RateLimit¶

    There are two ways to construct a RateLimit:

    1. Passing a rate limit string to RateLimit.parse().

      This allows you to express the rate limit in terms of seconds, minutes, hours, or days. This takes the following forms:

      • X/Ys – X hits in Y seconds

      • X/Ym – X hits in Y minutes

      • X/Yh – X hits in Y hours

      • X/Yd – X hits in Y days

      Y can be omitted if specifying just 1.

    2. Passing the hit limit and the period in seconds as arguments to the constructor.

      This is ideal if you already have the time period available in seconds, or want a period that isn’t expressed well through a rate limit string.

    Some examples:

    from djblets.protect.ratelimit import RateLimit
    
    
    # Define a rate limit of 100 lasting 30 minutes:
    rate_limit = RateLimit(
        period_secs=30 * 60,
        total_limit=100,
    )
    
    # 10 in 30 seconds.
    rate_limit = RateLimit.parse('10/30s')
    
    # 200 in 15 minutes.
    rate_limit = RateLimit.parse('200/15m')
    
    # 250 in 3 hours.
    rate_limit = RateLimit.parse('250/3h')
    
    # 1000 in 1 day.
    rate_limit = RateLimit.parse('1000/d')
    

    Choosing a Rate Limit Key¶

    When choosing a rate limit key, you’ll want to associate any information on both the resource and the entity being rate limited.

    A rate limit key can be a string or a list of strings. You’ll usually want to use lists, which will safely escape any dynamic content that make up the key (such as usernames).

    Some examples include:

    • ['reset-password', email]

    • ['api-request', username_or_ip]

    • ['sms-setup', phone_number, username_or_ip]

    When designing a key, follow these basic guidelines:

    1. Namespace your keys

      This will help avoid collisions. You can provide as many levels for the namespace as appropriate. The namespace should be placed at the start of the key, from most-general to most-specific category.

    2. Use stable keys

      Make sure the key for any given prefix always has the same number of elements so you don’t risk any unexpected collisions when using dynamic variables like usernames.

    3. Be specific with your keys

      Don’t make a key more broad or more fine-grained than it should be. Consider what exactly should be rate limited and what users or other targets should be considered.

    Tip

    Often, rate limits will be tied to a username or, if not logged in, an IP address.

    For this case, you may djblets.auth.ratelimit.get_user_id_or_ip(), which takes a HttpRequest and returns the user ID or IP address as appropriate.

    Checking a Rate Limit and Incrementing¶

    To check a rate limit, call check_rate_limit(), passing in the rate limit, key, and increment_count=True. This will increment the count towards the limit and return the results.

    from djblets.auth.ratelimit import get_user_id_or_ip
    from djblets.protect.ratelimit import RateLimit, check_rate_limit
    
    
    rate_limit = RateLimit.parse('10/h')
    username_or_ip = get_user_id_or_ip(request)
    
    # This will count toward the limit.
    result = check_rate_limit(
        rate_limit=rate_limit,
        key=['api-request', username_or_ip],
        increment_count=True,
    )
    

    The resulting RateLimitUsage will contain the details of that hit. The attributes include:

    count:

    The number of hits against the rate limit key.

    is_limited:

    Whether the limit has been exceeded.

    limit:

    The total number of attempts allowed for the rate limit.

    time_left_secs:

    The time remaining in seconds before the rate limit is reset for the key.

    The consumer is responsible for enforcing any rate limiting behavior based on the result.

    Tip

    As a convenience, you can pass a rate limit string instead of a RateLimit object:

    result = check_rate_limit(
        rate_limit='10/h',
        key=['api-request', username_or_ip],
        increment_count=True,
    )
    

    Passively Checking¶

    To passively check the number of hits remaining against a rate limit, call check_rate_limit() with just the rate limit and key. This will return a RateLimitUsage as above, but won’t count toward the limit.

    For example:

    from djblets.auth.ratelimit import get_user_id_or_ip
    from djblets.protect.ratelimit import RateLimit, check_rate_limit
    
    
    rate_limit = RateLimit.parse('10/h')
    username_or_ip = get_user_id_or_ip(request)
    
    # This won't count toward the limit.
    result = check_rate_limit(
        rate_limit=rate_limit,
        key=['api-request', username_or_ip],
    )
    

    Keep up with the latest Review Board releases, security updates, and helpful information.

    About
    News
    Demo
    RBCommons Hosting
    Integrations
    Happy Users
    Support Options
    Documentation
    FAQ
    User Manual
    RBTools
    Administration Guide
    Power Pack
    Release Notes
    Downloads
    Review Board
    RBTools
    Djblets
    Power Pack
    Package Store
    PGP Signatures
    Contributing
    Bug Tracker
    Submit Patches
    Development Setup
    Wiki
    Follow Us
    Mailing Lists
    Reddit
    Twitter
    Mastodon
    Facebook
    YouTube

    Copyright © 2006-2026 Beanbag, Inc. All rights reserved.

    Terms of Service — Privacy Policy — AI Ethics Policy — Branding

    On this page

    • [Top]
    • General Usage
    • Defining a RateLimit
    • Choosing a Rate Limit Key
    • Checking a Rate Limit and Incrementing
    • Passively Checking