title: Using Python 3.7 contextvars to pass state between Django views
body: <p>I'm building a single database/shared schema multi-tenant application using Django 2.2 and Python 3.7.</p>
  
  <p>I'm attempting to use the new <code>contextvars</code> api to share the tenant state (an <code>Organization</code>) between views.</p>
  
  <p>I'm setting the state in a custom middleware like this:</p>
  
  <pre><code># tenant_middleware.py
  
  from organization.models import Organization
  import contextvars
  import tenant.models as tenant_model
  
  
  tenant = contextvars.ContextVar('tenant', default=None)
  
  class TenantMiddleware:
     def __init__(self, get_response):
          self.get_response = get_response
  
      def __call__(self, request):
          response = self.get_response(request)
          user = request.user
  
          if user.is_authenticated:
              organization = Organization.objects.get(organizationuser__is_current_organization=True, organizationuser__user=user)
              tenant_object = tenant_model.Tenant.objects.get(organization=organization)
              tenant.set(tenant_object)
  
          return response
  </code></pre>
  
  <p>I'm using this state by having my app's models inherit from a <code>TenantAwareModel</code> like this:</p>
  
  <pre><code># tenant_models.py
  
  from django.contrib.auth import get_user_model
  from django.db import models
  from django.db.models.signals import pre_save
  from django.dispatch import receiver
  from organization.models import Organization
  from tenant_middleware import tenant
  
  User = get_user_model()
  
  
  class TenantManager(models.Manager):
      def get_queryset(self, *args, **kwargs):
          tenant_object = tenant.get()
  
          if tenant_object:
              return super(TenantManager, self).get_queryset(*args, **kwargs).filter(tenant=tenant_object)
          else:
              return None
  
      @receiver(pre_save)
      def pre_save_callback(sender, instance, **kwargs):
          tenant_object = tenant.get()
          instance.tenant = tenant_object
  
  
  class Tenant(models.Model):
      organization = models.ForeignKey(Organization, null=False, on_delete=models.CASCADE)
  
      def __str__(self):
          return self.organization.name
  
  
  class TenantAwareModel(models.Model):
      tenant = models.ForeignKey(Tenant, on_delete=models.CASCADE, related_name='%(app_label)s_%(class)s_related', related_query_name='%(app_label)s_%(class)ss')
      objects = models.Manager()
      tenant_objects = TenantManager()
  
      class Meta:
          abstract = True
  
  </code></pre>
  
  <p>In my application the business logic can then retrieve querysets using <code>.tenant_objects...</code> on a model class rather than <code>.objects...</code></p>
  
  <p>The problem I'm having is that it doesn't always work - specifically in these cases:</p>
  
  <ol>
  <li><p>In my login view after <code>login()</code> is called, the middleware runs and I can see the tenant is set correctly. When I redirect from my login view to my home view, however, the state is (initially) empty again and seems to get set properly after the home view executes. If I reload the home view, everything works fine.</p></li>
  <li><p>If I logout and then login again as a different user, the state from the previous user is retained, again until a do a reload of the page. This seems related to the previous issue, as it almost seems like the state is lagging (for lack of a better word).</p></li>
  <li><p>I use Celery to spin off <code>shared_tasks</code> for processing. I have to manually pass the tenant to these, as they don't pick up the context.</p></li>
  </ol>
  
  <p>Questions:</p>
  
  <ol>
  <li><p>Am I doing this correctly?</p></li>
  <li><p>Do I need to manually reload the state somehow in each module?</p></li>
  </ol>
  
  <p>Frustrated, as I can find almost no examples of doing this and very little discussion of <code>contextvars</code>. I'm trying to avoid passing the tenant around manually everywhere or using <code>thread.locals</code>.</p>
  
  <p>Thanks.</p>