qs.exclude(something=123) should not exclude objects with something=None
    
    
    
      
      
      
        from django.db import models
class A(models.Model):
    str = models.CharField(null=True, blank=True, max_length=20)
    def __unicode__(self):
        return self.str or 'None'
In [1]: from test import models
In [2]: a = models.A.objects.create(str='a')
In [3]: b = models.A.objects.create(str=None)
In [4]: models.A.objects.exclude(str='a')
Out[4]: []
In [5]: models.A.objects.filter(str__isnull=True).exclude(str='a')
Out[5]: []
In [6]: models.A.objects.all()                                    
Out[6]: [<A: a>, <A: None>]
Expected output:
Out[4]: [<A: None>]  
Out[5]: [<A: None>]  
Tested with trunk & queryset-refactor.
       
     
   
 
      
        
        
          Change History
          (9)
        
          
  
  
  
    
      | Keywords: | qsrf-cleanup added | 
  
 
           
          
          
  
  
  
    
      | Has patch: | set | 
    
      | Needs documentation: | set | 
    
      | Needs tests: | set | 
    
      | Owner: | changed from nobody to anonymous | 
    
      | Patch needs improvement: | set | 
    
      | Status: | new → assigned | 
  
 
           
          
  
  
  
    
      | Owner: | anonymous removed | 
    
      | Status: | assigned → new | 
    
      | Triage Stage: | Unreviewed → Accepted | 
  
 
           
          
          
          
  
  
  
    
      | Resolution: | → fixed | 
    
      | Status: | new → closed | 
  
 
           
          
          
          
         
       
     
        
    
    
I can reproduce this (r7573 + postgres).
It could be solved easyly by making
__exactNULL-safe:%s IS NOT DISTINCT FROMhttp://postgresql.com.cn/docs/8.3/static/functions-comparison.html%s <=>http://dev.mysql.com/doc/refman/4.1/en/comparison-operators.htmlBut I couldn't find something comparable for sqlite and oracle (except for
(a=b OR (a IS NULL AND b IS NULL))) - and I don't know if anything depends onNULL==1=NULL==NOT (1=NULL)and would break withFALSE==1<=>NULL!=NOT(1<=>NULL)==TRUE.While trying to come up with a patch I found some dead code that should handle the issue for related tables (see patch, missing
[JOIN_TYPE]inif final > 1 ...) and just threw in a similar weakening for the unjoined case.This will be a backwards incompatible change.