Add support for prefixing query expressions

Review Request #7774 — Created Nov. 17, 2015 and submitted

Information

Djblets
master
850d88a...

Reviewers

A new utility method, prefix_q, has been added to facilitate
prefixing of query expressions. Query expressions, or (Q()
expressions) are Django's way of building the WHERE (and related)
clauses when querying for models.

If a foreign key fk exists from a model A to B (that is, A.fk
points at an instance of B), then a query expression that is used
to filter instances of B can be used with A via prefix_q:

q_a = prefix_q('fk', q_b)

This allows complex queries that select one model to be reused to
select related models very easily.

Ran unit tests.

Description From Last Updated

Col: 13 E122 continuation line missing indentation or outdented

reviewbotreviewbot

Col: 13 E122 continuation line missing indentation or outdented

reviewbotreviewbot

I think I'd like more explanation about what "Prefix a Q expression" means. Can you give an example?

daviddavid

Just calling six.binary_type will explode if there's any non-ascii characters in there. Maybe that's what you want, but otherwise, perhaps …

daviddavid

It's pretty weird to see the u'' in there. Is that just something funky with Q.__str__?

daviddavid

How about explaining that: B.objects.filter(prefix_q(Q(field='value'), 'a')) is the same as: B.objects.filter(Q(a__field='value'))

daviddavid

"Return," not "Get." I don't think it's worth using Sphinx references for things like "None" in a summary.

chipx86chipx86

For these, maybe: :py;meth:`Manager.get <django.db.models.manager.Manager.get>

chipx86chipx86

""" is indented too far.

chipx86chipx86

I feel like this doesn't describe this well enough. The example does, but I'd like to see a bit more …

chipx86chipx86

This is backwards. It's title <reference>.

chipx86chipx86

This should be: Example: .. code-block:: python <example here> In other files, this is also after Args and Returns.

chipx86chipx86

Sentence casing.

chipx86chipx86

Sentence casing.

chipx86chipx86

Are you sure about this reference? The Django docs are showing it under django.db.models.Q.

chipx86chipx86

I don't know that :py:data: is really appropriate for things like True, False, or None. It's really intended for module-level …

chipx86chipx86

It's not clear to me, reading the unit tests and the code, whether all these cases are covered. Probably because …

chipx86chipx86

Any reason we don't just use isinstance? Generally, it's nice not to restrict to a specific base type, so long …

chipx86chipx86

Is this needed? Are we aware of cases where it must be a byte string? I thought Unicode strings were …

chipx86chipx86

Unit test suite docstrings are in the form of: "Unit tests for module.path.to.thing." Also, trailing period.

chipx86chipx86

The docstrings should all mention prefix_q.

chipx86chipx86

Should be "Return a model instance"

daviddavid
reviewbot
  1. Tool: Pyflakes
    Processed Files:
        djblets/db/query.py
        djblets/db/tests/test_query.py
    
    
    
    Tool: PEP8 Style Checker
    Processed Files:
        djblets/db/query.py
        djblets/db/tests/test_query.py
    
    
  2. 
      
brennie
reviewbot
  1. Tool: PEP8 Style Checker
    Processed Files:
        djblets/db/query.py
        djblets/db/tests/test_query.py
    
    
  2. djblets/db/tests/test_query.py (Diff revision 2)
     
     
    Show all issues
    Col: 13
     E122 continuation line missing indentation or outdented
    
  3. djblets/db/tests/test_query.py (Diff revision 2)
     
     
    Show all issues
    Col: 13
     E122 continuation line missing indentation or outdented
    
  4. 
      
brennie
reviewbot
  1. Tool: PEP8 Style Checker
    Processed Files:
        djblets/db/query.py
        djblets/db/tests/test_query.py
    
    
    
    Tool: Pyflakes
    Processed Files:
        djblets/db/query.py
        djblets/db/tests/test_query.py
    
    
  2. 
      
david
  1. 
      
  2. djblets/db/query.py (Diff revision 3)
     
     
    Show all issues

    I think I'd like more explanation about what "Prefix a Q expression" means. Can you give an example?

  3. djblets/db/query.py (Diff revision 3)
     
     
    Show all issues

    Just calling six.binary_type will explode if there's any non-ascii characters in there. Maybe that's what you want, but otherwise, perhaps use .encode('utf-8')?

  4. djblets/db/tests/test_query.py (Diff revision 3)
     
     
     
    Show all issues

    It's pretty weird to see the u'' in there. Is that just something funky with Q.__str__?

    1. It calls repr on its elements, and so it renders as a unicode string.

  5. 
      
brennie
reviewbot
  1. Tool: PEP8 Style Checker
    Processed Files:
        djblets/db/query.py
        djblets/db/tests/test_query.py
    
    
    
    Tool: Pyflakes
    Processed Files:
        djblets/db/query.py
        djblets/db/tests/test_query.py
    
    
  2. 
      
brennie
reviewbot
  1. Tool: PEP8 Style Checker
    Processed Files:
        djblets/db/query.py
        djblets/db/tests/test_query.py
    
    
    
    Tool: Pyflakes
    Processed Files:
        djblets/db/query.py
        djblets/db/tests/test_query.py
    
    
  2. 
      
david
  1. 
      
  2. djblets/db/query.py (Diff revision 5)
     
     
    Show all issues

    How about explaining that:

    B.objects.filter(prefix_q(Q(field='value'), 'a'))
    

    is the same as:

    B.objects.filter(Q(a__field='value'))
    
  3. 
      
brennie
reviewbot
  1. Tool: Pyflakes
    Processed Files:
        djblets/db/query.py
        djblets/db/tests/test_query.py
    
    
    
    Tool: PEP8 Style Checker
    Processed Files:
        djblets/db/query.py
        djblets/db/tests/test_query.py
    
    
  2. 
      
brennie
chipx86
  1. 
      
    1. The review request description should go into more detail on this. It feels to me to be descriptive only if you already know what this change is about.

  2. djblets/db/query.py (Diff revision 6)
     
     
    Show all issues

    "Return," not "Get."

    I don't think it's worth using Sphinx references for things like "None" in a summary.

  3. djblets/db/query.py (Diff revision 6)
     
     
    Show all issues

    For these, maybe:

    :py;meth:`Manager.get <django.db.models.manager.Manager.get>
    
  4. djblets/db/query.py (Diff revision 6)
     
     
    Show all issues

    """ is indented too far.

  5. djblets/db/query.py (Diff revision 6)
     
     
     
     
     
     
    Show all issues

    I feel like this doesn't describe this well enough. The example does, but I'd like to see a bit more about how this is useful.

    It should also go into the cloning behavior and defaults.

  6. djblets/db/query.py (Diff revision 6)
     
     
    Show all issues

    This is backwards. It's title <reference>.

  7. djblets/db/query.py (Diff revision 6)
     
     
     
     
    Show all issues

    This should be:

    Example:
        .. code-block:: python
    
           <example here>
    

    In other files, this is also after Args and Returns.

  8. djblets/db/query.py (Diff revision 6)
     
     
    Show all issues

    Sentence casing.

  9. djblets/db/query.py (Diff revision 6)
     
     
    Show all issues

    Sentence casing.

  10. djblets/db/query.py (Diff revision 6)
     
     
    Show all issues

    Are you sure about this reference? The Django docs are showing it under django.db.models.Q.

    1. https://github.com/django/django/blob/master/django/db/models/query_utils.py#L45

  11. djblets/db/query.py (Diff revision 6)
     
     
    Show all issues

    I don't know that :py:data: is really appropriate for things like True, False, or None. It's really intended for module-level data, with the implication being the current module. Does it result in actual links to the Python docs?

  12. djblets/db/query.py (Diff revision 6)
     
     
     
     
     
    Show all issues

    It's not clear to me, reading the unit tests and the code, whether all these cases are covered. Probably because parts involve internal Q knowledge, but I want to make sure we have 100% coverage of this.

  13. djblets/db/query.py (Diff revision 6)
     
     
    Show all issues

    Any reason we don't just use isinstance? Generally, it's nice not to restrict to a specific base type, so long as the thing coming in behaves like the expected type.

    Also, this shouldn't be an assertion, it should raise an exception if it's not a valid type. Assertions are for internal code that should always be correct, and are just to verify something isn't screwed up (like an internal function calling another internal function with some certain state).

    1. This should never ever be anything other than a tuple due to the internals of Q.

  14. djblets/db/query.py (Diff revision 6)
     
     
    Show all issues

    Is this needed? Are we aware of cases where it must be a byte string? I thought Unicode strings were fine here.

    If this is indeed required, we need to have a unit test for it.

    1. Q() objects created as Q(key=val) will have key as a bytestring.

  15. djblets/db/tests/test_query.py (Diff revision 6)
     
     
    Show all issues

    Unit test suite docstrings are in the form of: "Unit tests for module.path.to.thing." Also, trailing period.

  16. djblets/db/tests/test_query.py (Diff revision 6)
     
     
    Show all issues

    The docstrings should all mention prefix_q.

  17. 
      
brennie
reviewbot
  1. Tool: PEP8 Style Checker
    Processed Files:
        djblets/db/query.py
        djblets/db/tests/test_query.py
    
    
    
    Tool: Pyflakes
    Processed Files:
        djblets/db/query.py
        djblets/db/tests/test_query.py
    
    
  2. 
      
david
  1. 
      
  2. djblets/db/query.py (Diff revision 7)
     
     
    Show all issues

    Should be "Return a model instance"

  3. 
      
brennie
Review request changed
Status:
Completed
Change Summary:
Pushed to release-0.10.x (86a4b74)