Quantcast

Adding UNION/INTERSECT/EXCEPT to the ORM

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
10 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Adding UNION/INTERSECT/EXCEPT to the ORM

Florian Apolloner
Hi,

I have a currently WIP PR at https://github.com/django/django/pull/7727

The usage is currently something like this:

qs1 = User.objects.all().values('username')
qs2 = Group.objects.all().values('name')
results = qs1.union(qs).distinct().order_by('name')[:10]

(order_by does not work though yet)

So far I have a few questions:

 * Should .union/.intersect etc return a new type of queryset or stay with the base QuerySet class (probably less code duplication)
 * We currently have a few methods which check can_filter and error out accordingly (ie you cannot filter after slicing), but as the error message in https://github.com/django/django/blob/master/django/db/models/query.py#L579 shows, this strongly relies on knowledge of the implementation of the filter. For combined querysets I basically need to limit everything aside from order by and limit/offset. Would a method like this make some sense (on the Query class):

def is_allowed(self, action):
  if self.combinatorial and action not in ('set_operation', 'order_by', 'slicing'):
    raise SomeError('Cannot use this method on an combinatorial queryset')
  elif action == 'filter' and (self.low_mark or self.high_mark):
    raise SomeError('Cannot filter after slicing')

 * set_operator in base.py feels a bit weird (https://github.com/django/django/pull/7727/files#diff-53fcf3ac0535307033e0cfabb85c5301) -- any better options?
 * How can I change the generated order_by clause to reference the columns "unqualified" (ie without table name), can I somehow just realias every column?

Cheers,
Florian

--
You received this message because you are subscribed to the Google Groups "Django developers (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To post to this group, send email to [hidden email].
Visit this group at https://groups.google.com/group/django-developers.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-developers/1850fec7-2bcc-4efb-b0a4-2dea373592c2%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Adding UNION/INTERSECT/EXCEPT to the ORM

Simon Charette
Hey Florian!

> How can I change the generated order_by clause to reference the columns "unqualified" (ie without table name), can I somehow just realias every column?

Now that we have F() aliasing working in iterator() I would suggest to restrict
all combined queries to have the same set on fields. e.g.

users = User.objects.values(name=F('username'))
groups = Group.objects.values('name')

results = users.union(groups).distinct().order_by('name')[:10]

This should make things easier.

Thanks for working on that!

Simon

Le vendredi 23 décembre 2016 09:12:40 UTC-5, Florian Apolloner a écrit :
Hi,

I have a currently WIP PR at <a href="https://github.com/django/django/pull/7727" target="_blank" rel="nofollow" onmousedown="this.href=&#39;https://www.google.com/url?q\x3dhttps%3A%2F%2Fgithub.com%2Fdjango%2Fdjango%2Fpull%2F7727\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNHahCoQjYDy0Q2J9ocfWPPfsKKjBw&#39;;return true;" onclick="this.href=&#39;https://www.google.com/url?q\x3dhttps%3A%2F%2Fgithub.com%2Fdjango%2Fdjango%2Fpull%2F7727\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNHahCoQjYDy0Q2J9ocfWPPfsKKjBw&#39;;return true;">https://github.com/django/django/pull/7727

The usage is currently something like this:

qs1 = User.objects.all().values('username')
qs2 = Group.objects.all().values('name')
results = qs1.union(qs).distinct().order_by('name')[:10]

(order_by does not work though yet)

So far I have a few questions:

 * Should .union/.intersect etc return a new type of queryset or stay with the base QuerySet class (probably less code duplication)
 * We currently have a few methods which check can_filter and error out accordingly (ie you cannot filter after slicing), but as the error message in <a href="https://github.com/django/django/blob/master/django/db/models/query.py#L579" target="_blank" rel="nofollow" onmousedown="this.href=&#39;https://www.google.com/url?q\x3dhttps%3A%2F%2Fgithub.com%2Fdjango%2Fdjango%2Fblob%2Fmaster%2Fdjango%2Fdb%2Fmodels%2Fquery.py%23L579\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNHcvxsaP47dZNNK88lfNcSFDPWU8Q&#39;;return true;" onclick="this.href=&#39;https://www.google.com/url?q\x3dhttps%3A%2F%2Fgithub.com%2Fdjango%2Fdjango%2Fblob%2Fmaster%2Fdjango%2Fdb%2Fmodels%2Fquery.py%23L579\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNHcvxsaP47dZNNK88lfNcSFDPWU8Q&#39;;return true;">https://github.com/django/django/blob/master/django/db/models/query.py#L579 shows, this strongly relies on knowledge of the implementation of the filter. For combined querysets I basically need to limit everything aside from order by and limit/offset. Would a method like this make some sense (on the Query class):

def is_allowed(self, action):
  if self.combinatorial and action not in ('set_operation', 'order_by', 'slicing'):
    raise SomeError('Cannot use this method on an combinatorial queryset')
  elif action == 'filter' and (self.low_mark or self.high_mark):
    raise SomeError('Cannot filter after slicing')

 * set_operator in base.py feels a bit weird (<a href="https://github.com/django/django/pull/7727/files#diff-53fcf3ac0535307033e0cfabb85c5301" target="_blank" rel="nofollow" onmousedown="this.href=&#39;https://www.google.com/url?q\x3dhttps%3A%2F%2Fgithub.com%2Fdjango%2Fdjango%2Fpull%2F7727%2Ffiles%23diff-53fcf3ac0535307033e0cfabb85c5301\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNFQ3Vjjs8Qxz7CRIkz_0vLiQvn99A&#39;;return true;" onclick="this.href=&#39;https://www.google.com/url?q\x3dhttps%3A%2F%2Fgithub.com%2Fdjango%2Fdjango%2Fpull%2F7727%2Ffiles%23diff-53fcf3ac0535307033e0cfabb85c5301\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNFQ3Vjjs8Qxz7CRIkz_0vLiQvn99A&#39;;return true;">https://github.com/django/django/pull/7727/files#diff-53fcf3ac0535307033e0cfabb85c5301) -- any better options?
 * How can I change the generated order_by clause to reference the columns "unqualified" (ie without table name), can I somehow just realias every column?

Cheers,
Florian

--
You received this message because you are subscribed to the Google Groups "Django developers (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To post to this group, send email to [hidden email].
Visit this group at https://groups.google.com/group/django-developers.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-developers/40af7cae-d6cc-4a3c-a777-95115125773f%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Adding UNION/INTERSECT/EXCEPT to the ORM

Florian Apolloner
Hi Simon,

On Friday, December 23, 2016 at 3:27:46 PM UTC+1, charettes wrote:
users = User.objects.values(name=F('username'))
groups = Group.objects.values('name')

results = users.union(groups).distinct().order_by('name')[:10]

That does indeed work already, but it would be nice if it worked without .values so you can get out model objects again. Think of a union query giving you users which signed up in 2014 or 2016, surely one can easily do that via OR, but if I can get order_by to either return column numbers or realias every field from it's name to it's unqualified name (like you suggested with values, but internally in Query), that would be a massive win.

Cheers,
Florian

--
You received this message because you are subscribed to the Google Groups "Django developers (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To post to this group, send email to [hidden email].
Visit this group at https://groups.google.com/group/django-developers.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-developers/b0c8b6aa-29c6-4d8d-baf1-2068a183a313%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Adding UNION/INTERSECT/EXCEPT to the ORM

Florian Apolloner
In reply to this post by Florian Apolloner
Ok, everything seems to be working so far, I'll try adding `is_allowed` over the next few days, then I can get rid of the extra `QuerySet` class.

On Friday, December 23, 2016 at 3:12:40 PM UTC+1, Florian Apolloner wrote:
Hi,

I have a currently WIP PR at <a href="https://github.com/django/django/pull/7727" target="_blank" rel="nofollow" onmousedown="this.href=&#39;https://www.google.com/url?q\x3dhttps%3A%2F%2Fgithub.com%2Fdjango%2Fdjango%2Fpull%2F7727\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNHahCoQjYDy0Q2J9ocfWPPfsKKjBw&#39;;return true;" onclick="this.href=&#39;https://www.google.com/url?q\x3dhttps%3A%2F%2Fgithub.com%2Fdjango%2Fdjango%2Fpull%2F7727\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNHahCoQjYDy0Q2J9ocfWPPfsKKjBw&#39;;return true;">https://github.com/django/django/pull/7727

The usage is currently something like this:

qs1 = User.objects.all().values('username')
qs2 = Group.objects.all().values('name')
results = qs1.union(qs).distinct().order_by('name')[:10]

(order_by does not work though yet)

So far I have a few questions:

 * Should .union/.intersect etc return a new type of queryset or stay with the base QuerySet class (probably less code duplication)
 * We currently have a few methods which check can_filter and error out accordingly (ie you cannot filter after slicing), but as the error message in <a href="https://github.com/django/django/blob/master/django/db/models/query.py#L579" target="_blank" rel="nofollow" onmousedown="this.href=&#39;https://www.google.com/url?q\x3dhttps%3A%2F%2Fgithub.com%2Fdjango%2Fdjango%2Fblob%2Fmaster%2Fdjango%2Fdb%2Fmodels%2Fquery.py%23L579\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNHcvxsaP47dZNNK88lfNcSFDPWU8Q&#39;;return true;" onclick="this.href=&#39;https://www.google.com/url?q\x3dhttps%3A%2F%2Fgithub.com%2Fdjango%2Fdjango%2Fblob%2Fmaster%2Fdjango%2Fdb%2Fmodels%2Fquery.py%23L579\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNHcvxsaP47dZNNK88lfNcSFDPWU8Q&#39;;return true;">https://github.com/django/django/blob/master/django/db/models/query.py#L579 shows, this strongly relies on knowledge of the implementation of the filter. For combined querysets I basically need to limit everything aside from order by and limit/offset. Would a method like this make some sense (on the Query class):

def is_allowed(self, action):
  if self.combinatorial and action not in ('set_operation', 'order_by', 'slicing'):
    raise SomeError('Cannot use this method on an combinatorial queryset')
  elif action == 'filter' and (self.low_mark or self.high_mark):
    raise SomeError('Cannot filter after slicing')

 * set_operator in base.py feels a bit weird (<a href="https://github.com/django/django/pull/7727/files#diff-53fcf3ac0535307033e0cfabb85c5301" target="_blank" rel="nofollow" onmousedown="this.href=&#39;https://www.google.com/url?q\x3dhttps%3A%2F%2Fgithub.com%2Fdjango%2Fdjango%2Fpull%2F7727%2Ffiles%23diff-53fcf3ac0535307033e0cfabb85c5301\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNFQ3Vjjs8Qxz7CRIkz_0vLiQvn99A&#39;;return true;" onclick="this.href=&#39;https://www.google.com/url?q\x3dhttps%3A%2F%2Fgithub.com%2Fdjango%2Fdjango%2Fpull%2F7727%2Ffiles%23diff-53fcf3ac0535307033e0cfabb85c5301\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNFQ3Vjjs8Qxz7CRIkz_0vLiQvn99A&#39;;return true;">https://github.com/django/django/pull/7727/files#diff-53fcf3ac0535307033e0cfabb85c5301) -- any better options?
 * How can I change the generated order_by clause to reference the columns "unqualified" (ie without table name), can I somehow just realias every column?

Cheers,
Florian

--
You received this message because you are subscribed to the Google Groups "Django developers (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To post to this group, send email to [hidden email].
Visit this group at https://groups.google.com/group/django-developers.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-developers/16a470fe-e8cf-49b1-ad14-95226cb25baa%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Adding UNION/INTERSECT/EXCEPT to the ORM

Cristiano Coelho
In reply to this post by Florian Apolloner
Is this going to be different from the pipe ( | ) and and ( & ) operators on querysets? If I'm not wrong those can already result in a union query (but not necessary, sometimes it just returns a query with an or/and condition)

El viernes, 23 de diciembre de 2016, 11:12:40 (UTC-3), Florian Apolloner escribió:
Hi,

I have a currently WIP PR at <a href="https://github.com/django/django/pull/7727" target="_blank" rel="nofollow" onmousedown="this.href=&#39;https://www.google.com/url?q\x3dhttps%3A%2F%2Fgithub.com%2Fdjango%2Fdjango%2Fpull%2F7727\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNHahCoQjYDy0Q2J9ocfWPPfsKKjBw&#39;;return true;" onclick="this.href=&#39;https://www.google.com/url?q\x3dhttps%3A%2F%2Fgithub.com%2Fdjango%2Fdjango%2Fpull%2F7727\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNHahCoQjYDy0Q2J9ocfWPPfsKKjBw&#39;;return true;">https://github.com/django/django/pull/7727

The usage is currently something like this:

qs1 = User.objects.all().values('username')
qs2 = Group.objects.all().values('name')
results = qs1.union(qs).distinct().order_by('name')[:10]

(order_by does not work though yet)

So far I have a few questions:

 * Should .union/.intersect etc return a new type of queryset or stay with the base QuerySet class (probably less code duplication)
 * We currently have a few methods which check can_filter and error out accordingly (ie you cannot filter after slicing), but as the error message in <a href="https://github.com/django/django/blob/master/django/db/models/query.py#L579" target="_blank" rel="nofollow" onmousedown="this.href=&#39;https://www.google.com/url?q\x3dhttps%3A%2F%2Fgithub.com%2Fdjango%2Fdjango%2Fblob%2Fmaster%2Fdjango%2Fdb%2Fmodels%2Fquery.py%23L579\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNHcvxsaP47dZNNK88lfNcSFDPWU8Q&#39;;return true;" onclick="this.href=&#39;https://www.google.com/url?q\x3dhttps%3A%2F%2Fgithub.com%2Fdjango%2Fdjango%2Fblob%2Fmaster%2Fdjango%2Fdb%2Fmodels%2Fquery.py%23L579\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNHcvxsaP47dZNNK88lfNcSFDPWU8Q&#39;;return true;">https://github.com/django/django/blob/master/django/db/models/query.py#L579 shows, this strongly relies on knowledge of the implementation of the filter. For combined querysets I basically need to limit everything aside from order by and limit/offset. Would a method like this make some sense (on the Query class):

def is_allowed(self, action):
  if self.combinatorial and action not in ('set_operation', 'order_by', 'slicing'):
    raise SomeError('Cannot use this method on an combinatorial queryset')
  elif action == 'filter' and (self.low_mark or self.high_mark):
    raise SomeError('Cannot filter after slicing')

 * set_operator in base.py feels a bit weird (<a href="https://github.com/django/django/pull/7727/files#diff-53fcf3ac0535307033e0cfabb85c5301" target="_blank" rel="nofollow" onmousedown="this.href=&#39;https://www.google.com/url?q\x3dhttps%3A%2F%2Fgithub.com%2Fdjango%2Fdjango%2Fpull%2F7727%2Ffiles%23diff-53fcf3ac0535307033e0cfabb85c5301\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNFQ3Vjjs8Qxz7CRIkz_0vLiQvn99A&#39;;return true;" onclick="this.href=&#39;https://www.google.com/url?q\x3dhttps%3A%2F%2Fgithub.com%2Fdjango%2Fdjango%2Fpull%2F7727%2Ffiles%23diff-53fcf3ac0535307033e0cfabb85c5301\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNFQ3Vjjs8Qxz7CRIkz_0vLiQvn99A&#39;;return true;">https://github.com/django/django/pull/7727/files#diff-53fcf3ac0535307033e0cfabb85c5301) -- any better options?
 * How can I change the generated order_by clause to reference the columns "unqualified" (ie without table name), can I somehow just realias every column?

Cheers,
Florian

--
You received this message because you are subscribed to the Google Groups "Django developers (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To post to this group, send email to [hidden email].
Visit this group at https://groups.google.com/group/django-developers.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-developers/d38358ca-c97f-4bb0-a390-e38f3b4b8f6c%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Adding UNION/INTERSECT/EXCEPT to the ORM

Adam Johnson-2
Yes it's different, they cannot be changed due to backwards compatibility issues. They don't result in UNION in SQL, they union the filters on two querysets that are on the same exact model.

On 26 December 2016 at 21:00, Cristiano Coelho <[hidden email]> wrote:
Is this going to be different from the pipe ( | ) and and ( & ) operators on querysets? If I'm not wrong those can already result in a union query (but not necessary, sometimes it just returns a query with an or/and condition)


El viernes, 23 de diciembre de 2016, 11:12:40 (UTC-3), Florian Apolloner escribió:
Hi,

I have a currently WIP PR at https://github.com/django/django/pull/7727

The usage is currently something like this:

qs1 = User.objects.all().values('username')
qs2 = Group.objects.all().values('name')
results = qs1.union(qs).distinct().order_by('name')[:10]

(order_by does not work though yet)

So far I have a few questions:

 * Should .union/.intersect etc return a new type of queryset or stay with the base QuerySet class (probably less code duplication)
 * We currently have a few methods which check can_filter and error out accordingly (ie you cannot filter after slicing), but as the error message in https://github.com/django/django/blob/master/django/db/models/query.py#L579 shows, this strongly relies on knowledge of the implementation of the filter. For combined querysets I basically need to limit everything aside from order by and limit/offset. Would a method like this make some sense (on the Query class):

def is_allowed(self, action):
  if self.combinatorial and action not in ('set_operation', 'order_by', 'slicing'):
    raise SomeError('Cannot use this method on an combinatorial queryset')
  elif action == 'filter' and (self.low_mark or self.high_mark):
    raise SomeError('Cannot filter after slicing')

 * set_operator in base.py feels a bit weird (https://github.com/django/django/pull/7727/files#diff-53fcf3ac0535307033e0cfabb85c5301) -- any better options?
 * How can I change the generated order_by clause to reference the columns "unqualified" (ie without table name), can I somehow just realias every column?

Cheers,
Florian

--
You received this message because you are subscribed to the Google Groups "Django developers (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To post to this group, send email to [hidden email].
Visit this group at https://groups.google.com/group/django-developers.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-developers/d38358ca-c97f-4bb0-a390-e38f3b4b8f6c%40googlegroups.com.

For more options, visit https://groups.google.com/d/optout.



--
Adam

--
You received this message because you are subscribed to the Google Groups "Django developers (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To post to this group, send email to [hidden email].
Visit this group at https://groups.google.com/group/django-developers.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-developers/CAMyDDM3E1jb%2BXvddT%2BcKzsf127y9kDw30xCKoRgiVwy6Dcwmxg%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Adding UNION/INTERSECT/EXCEPT to the ORM

Tim Graham-2
We cannot use the name "QuerySet.except()" since except is a reserved word in Python. Do you prefer minus() (as suggested by Florian), except_() (as done by SQLAlchemy), or something else?

On Monday, December 26, 2016 at 6:28:15 PM UTC-5, Adam Johnson wrote:
Yes it's different, they cannot be changed due to backwards compatibility issues. They don't result in UNION in SQL, they union the filters on two querysets that are on the same exact model.

On 26 December 2016 at 21:00, Cristiano Coelho <<a href="javascript:" target="_blank" gdf-obfuscated-mailto="_CWOG2SbEQAJ" rel="nofollow" onmousedown="this.href=&#39;javascript:&#39;;return true;" onclick="this.href=&#39;javascript:&#39;;return true;">cristia...@...> wrote:
Is this going to be different from the pipe ( | ) and and ( & ) operators on querysets? If I'm not wrong those can already result in a union query (but not necessary, sometimes it just returns a query with an or/and condition)


El viernes, 23 de diciembre de 2016, 11:12:40 (UTC-3), Florian Apolloner escribió:
Hi,

I have a currently WIP PR at <a href="https://github.com/django/django/pull/7727" rel="nofollow" target="_blank" onmousedown="this.href=&#39;https://www.google.com/url?q\x3dhttps%3A%2F%2Fgithub.com%2Fdjango%2Fdjango%2Fpull%2F7727\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNHahCoQjYDy0Q2J9ocfWPPfsKKjBw&#39;;return true;" onclick="this.href=&#39;https://www.google.com/url?q\x3dhttps%3A%2F%2Fgithub.com%2Fdjango%2Fdjango%2Fpull%2F7727\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNHahCoQjYDy0Q2J9ocfWPPfsKKjBw&#39;;return true;">https://github.com/django/django/pull/7727

The usage is currently something like this:

qs1 = User.objects.all().values('username')
qs2 = Group.objects.all().values('name')
results = qs1.union(qs).distinct().order_by('name')[:10]

(order_by does not work though yet)

So far I have a few questions:

 * Should .union/.intersect etc return a new type of queryset or stay with the base QuerySet class (probably less code duplication)
 * We currently have a few methods which check can_filter and error out accordingly (ie you cannot filter after slicing), but as the error message in <a href="https://github.com/django/django/blob/master/django/db/models/query.py#L579" rel="nofollow" target="_blank" onmousedown="this.href=&#39;https://www.google.com/url?q\x3dhttps%3A%2F%2Fgithub.com%2Fdjango%2Fdjango%2Fblob%2Fmaster%2Fdjango%2Fdb%2Fmodels%2Fquery.py%23L579\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNHcvxsaP47dZNNK88lfNcSFDPWU8Q&#39;;return true;" onclick="this.href=&#39;https://www.google.com/url?q\x3dhttps%3A%2F%2Fgithub.com%2Fdjango%2Fdjango%2Fblob%2Fmaster%2Fdjango%2Fdb%2Fmodels%2Fquery.py%23L579\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNHcvxsaP47dZNNK88lfNcSFDPWU8Q&#39;;return true;">https://github.com/django/django/blob/master/django/db/models/query.py#L579 shows, this strongly relies on knowledge of the implementation of the filter. For combined querysets I basically need to limit everything aside from order by and limit/offset. Would a method like this make some sense (on the Query class):

def is_allowed(self, action):
  if self.combinatorial and action not in ('set_operation', 'order_by', 'slicing'):
    raise SomeError('Cannot use this method on an combinatorial queryset')
  elif action == 'filter' and (self.low_mark or self.high_mark):
    raise SomeError('Cannot filter after slicing')

 * set_operator in base.py feels a bit weird (<a href="https://github.com/django/django/pull/7727/files#diff-53fcf3ac0535307033e0cfabb85c5301" rel="nofollow" target="_blank" onmousedown="this.href=&#39;https://www.google.com/url?q\x3dhttps%3A%2F%2Fgithub.com%2Fdjango%2Fdjango%2Fpull%2F7727%2Ffiles%23diff-53fcf3ac0535307033e0cfabb85c5301\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNFQ3Vjjs8Qxz7CRIkz_0vLiQvn99A&#39;;return true;" onclick="this.href=&#39;https://www.google.com/url?q\x3dhttps%3A%2F%2Fgithub.com%2Fdjango%2Fdjango%2Fpull%2F7727%2Ffiles%23diff-53fcf3ac0535307033e0cfabb85c5301\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNFQ3Vjjs8Qxz7CRIkz_0vLiQvn99A&#39;;return true;">https://github.com/django/django/pull/7727/files#diff-53fcf3ac0535307033e0cfabb85c5301) -- any better options?
 * How can I change the generated order_by clause to reference the columns "unqualified" (ie without table name), can I somehow just realias every column?

Cheers,
Florian

--
You received this message because you are subscribed to the Google Groups "Django developers (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email to <a href="javascript:" target="_blank" gdf-obfuscated-mailto="_CWOG2SbEQAJ" rel="nofollow" onmousedown="this.href=&#39;javascript:&#39;;return true;" onclick="this.href=&#39;javascript:&#39;;return true;">django-develop...@googlegroups.com.
To post to this group, send email to <a href="javascript:" target="_blank" gdf-obfuscated-mailto="_CWOG2SbEQAJ" rel="nofollow" onmousedown="this.href=&#39;javascript:&#39;;return true;" onclick="this.href=&#39;javascript:&#39;;return true;">django-d...@googlegroups.com.
Visit this group at <a href="https://groups.google.com/group/django-developers" target="_blank" rel="nofollow" onmousedown="this.href=&#39;https://groups.google.com/group/django-developers&#39;;return true;" onclick="this.href=&#39;https://groups.google.com/group/django-developers&#39;;return true;">https://groups.google.com/group/django-developers.
To view this discussion on the web visit <a href="https://groups.google.com/d/msgid/django-developers/d38358ca-c97f-4bb0-a390-e38f3b4b8f6c%40googlegroups.com?utm_medium=email&amp;utm_source=footer" target="_blank" rel="nofollow" onmousedown="this.href=&#39;https://groups.google.com/d/msgid/django-developers/d38358ca-c97f-4bb0-a390-e38f3b4b8f6c%40googlegroups.com?utm_medium\x3demail\x26utm_source\x3dfooter&#39;;return true;" onclick="this.href=&#39;https://groups.google.com/d/msgid/django-developers/d38358ca-c97f-4bb0-a390-e38f3b4b8f6c%40googlegroups.com?utm_medium\x3demail\x26utm_source\x3dfooter&#39;;return true;">https://groups.google.com/d/msgid/django-developers/d38358ca-c97f-4bb0-a390-e38f3b4b8f6c%40googlegroups.com.

For more options, visit <a href="https://groups.google.com/d/optout" target="_blank" rel="nofollow" onmousedown="this.href=&#39;https://groups.google.com/d/optout&#39;;return true;" onclick="this.href=&#39;https://groups.google.com/d/optout&#39;;return true;">https://groups.google.com/d/optout.



--
Adam

--
You received this message because you are subscribed to the Google Groups "Django developers (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To post to this group, send email to [hidden email].
Visit this group at https://groups.google.com/group/django-developers.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-developers/3084faa0-e097-4227-9a34-f870c8be6809%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Adding UNION/INTERSECT/EXCEPT to the ORM

Sean Bleier
We cannot use the name "QuerySet.except()" since except is a reserved word in Python. Do you prefer minus() (as suggested by Florian), except_() (as done by SQLAlchemy), or something else?


Can I suggest using "QuerySet.difference"?   It's what python's sets use for achieving the same functionality.

On Monday, December 26, 2016 at 6:28:15 PM UTC-5, Adam Johnson wrote:
Yes it's different, they cannot be changed due to backwards compatibility issues. They don't result in UNION in SQL, they union the filters on two querysets that are on the same exact model.

On 26 December 2016 at 21:00, Cristiano Coelho <[hidden email]> wrote:
Is this going to be different from the pipe ( | ) and and ( & ) operators on querysets? If I'm not wrong those can already result in a union query (but not necessary, sometimes it just returns a query with an or/and condition)


El viernes, 23 de diciembre de 2016, 11:12:40 (UTC-3), Florian Apolloner escribió:
Hi,

I have a currently WIP PR at https://github.com/django/django/pull/7727

The usage is currently something like this:

qs1 = User.objects.all().values('username')
qs2 = Group.objects.all().values('name')
results = qs1.union(qs).distinct().order_by('name')[:10]

(order_by does not work though yet)

So far I have a few questions:

 * Should .union/.intersect etc return a new type of queryset or stay with the base QuerySet class (probably less code duplication)
 * We currently have a few methods which check can_filter and error out accordingly (ie you cannot filter after slicing), but as the error message in https://github.com/django/django/blob/master/django/db/models/query.py#L579 shows, this strongly relies on knowledge of the implementation of the filter. For combined querysets I basically need to limit everything aside from order by and limit/offset. Would a method like this make some sense (on the Query class):

def is_allowed(self, action):
  if self.combinatorial and action not in ('set_operation', 'order_by', 'slicing'):
    raise SomeError('Cannot use this method on an combinatorial queryset')
  elif action == 'filter' and (self.low_mark or self.high_mark):
    raise SomeError('Cannot filter after slicing')

 * set_operator in base.py feels a bit weird (https://github.com/django/django/pull/7727/files#diff-53fcf3ac0535307033e0cfabb85c5301) -- any better options?
 * How can I change the generated order_by clause to reference the columns "unqualified" (ie without table name), can I somehow just realias every column?

Cheers,
Florian

--
You received this message because you are subscribed to the Google Groups "Django developers (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-develop...@googlegroups.com.
To post to this group, send email to [hidden email].
Visit this group at https://groups.google.com/group/django-developers.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-developers/d38358ca-c97f-4bb0-a390-e38f3b4b8f6c%40googlegroups.com.

For more options, visit https://groups.google.com/d/optout.



--
Adam

--
You received this message because you are subscribed to the Google Groups "Django developers (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To post to this group, send email to [hidden email].
Visit this group at https://groups.google.com/group/django-developers.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-developers/3084faa0-e097-4227-9a34-f870c8be6809%40googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "Django developers (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To post to this group, send email to [hidden email].
Visit this group at https://groups.google.com/group/django-developers.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-developers/CAKFtT_1wLo_6kX%3DxJ6H_Y0YtFnR2RTTOuZ241QTrf47k61q6mw%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Adding UNION/INTERSECT/EXCEPT to the ORM

Simon Charette
+1 to QuerySet.difference()

Le mercredi 11 janvier 2017 17:00:12 UTC-5, sebleier a écrit :
We cannot use the name "QuerySet.except()" since except is a reserved word in Python. Do you prefer minus() (as suggested by Florian), except_() (as done by SQLAlchemy), or something else?


Can I suggest using "QuerySet.difference"?   It's what python's sets use for achieving the same functionality.

On Monday, December 26, 2016 at 6:28:15 PM UTC-5, Adam Johnson wrote:
Yes it's different, they cannot be changed due to backwards compatibility issues. They don't result in UNION in SQL, they union the filters on two querysets that are on the same exact model.

On 26 December 2016 at 21:00, Cristiano Coelho <[hidden email]> wrote:
Is this going to be different from the pipe ( | ) and and ( & ) operators on querysets? If I'm not wrong those can already result in a union query (but not necessary, sometimes it just returns a query with an or/and condition)


El viernes, 23 de diciembre de 2016, 11:12:40 (UTC-3), Florian Apolloner escribió:
Hi,

I have a currently WIP PR at <a href="https://github.com/django/django/pull/7727" rel="nofollow" target="_blank" onmousedown="this.href=&#39;https://www.google.com/url?q\x3dhttps%3A%2F%2Fgithub.com%2Fdjango%2Fdjango%2Fpull%2F7727\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNHahCoQjYDy0Q2J9ocfWPPfsKKjBw&#39;;return true;" onclick="this.href=&#39;https://www.google.com/url?q\x3dhttps%3A%2F%2Fgithub.com%2Fdjango%2Fdjango%2Fpull%2F7727\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNHahCoQjYDy0Q2J9ocfWPPfsKKjBw&#39;;return true;">https://github.com/django/django/pull/7727

The usage is currently something like this:

qs1 = User.objects.all().values('username')
qs2 = Group.objects.all().values('name')
results = qs1.union(qs).distinct().order_by('name')[:10]

(order_by does not work though yet)

So far I have a few questions:

 * Should .union/.intersect etc return a new type of queryset or stay with the base QuerySet class (probably less code duplication)
 * We currently have a few methods which check can_filter and error out accordingly (ie you cannot filter after slicing), but as the error message in <a href="https://github.com/django/django/blob/master/django/db/models/query.py#L579" rel="nofollow" target="_blank" onmousedown="this.href=&#39;https://www.google.com/url?q\x3dhttps%3A%2F%2Fgithub.com%2Fdjango%2Fdjango%2Fblob%2Fmaster%2Fdjango%2Fdb%2Fmodels%2Fquery.py%23L579\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNHcvxsaP47dZNNK88lfNcSFDPWU8Q&#39;;return true;" onclick="this.href=&#39;https://www.google.com/url?q\x3dhttps%3A%2F%2Fgithub.com%2Fdjango%2Fdjango%2Fblob%2Fmaster%2Fdjango%2Fdb%2Fmodels%2Fquery.py%23L579\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNHcvxsaP47dZNNK88lfNcSFDPWU8Q&#39;;return true;">https://github.com/django/django/blob/master/django/db/models/query.py#L579 shows, this strongly relies on knowledge of the implementation of the filter. For combined querysets I basically need to limit everything aside from order by and limit/offset. Would a method like this make some sense (on the Query class):

def is_allowed(self, action):
  if self.combinatorial and action not in ('set_operation', 'order_by', 'slicing'):
    raise SomeError('Cannot use this method on an combinatorial queryset')
  elif action == 'filter' and (self.low_mark or self.high_mark):
    raise SomeError('Cannot filter after slicing')

 * set_operator in base.py feels a bit weird (<a href="https://github.com/django/django/pull/7727/files#diff-53fcf3ac0535307033e0cfabb85c5301" rel="nofollow" target="_blank" onmousedown="this.href=&#39;https://www.google.com/url?q\x3dhttps%3A%2F%2Fgithub.com%2Fdjango%2Fdjango%2Fpull%2F7727%2Ffiles%23diff-53fcf3ac0535307033e0cfabb85c5301\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNFQ3Vjjs8Qxz7CRIkz_0vLiQvn99A&#39;;return true;" onclick="this.href=&#39;https://www.google.com/url?q\x3dhttps%3A%2F%2Fgithub.com%2Fdjango%2Fdjango%2Fpull%2F7727%2Ffiles%23diff-53fcf3ac0535307033e0cfabb85c5301\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNFQ3Vjjs8Qxz7CRIkz_0vLiQvn99A&#39;;return true;">https://github.com/django/django/pull/7727/files#diff-53fcf3ac0535307033e0cfabb85c5301) -- any better options?
 * How can I change the generated order_by clause to reference the columns "unqualified" (ie without table name), can I somehow just realias every column?

Cheers,
Florian

--
You received this message because you are subscribed to the Google Groups "Django developers (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-develop...@googlegroups.com.
To post to this group, send email to [hidden email].
Visit this group at <a href="https://groups.google.com/group/django-developers" rel="nofollow" target="_blank" onmousedown="this.href=&#39;https://groups.google.com/group/django-developers&#39;;return true;" onclick="this.href=&#39;https://groups.google.com/group/django-developers&#39;;return true;">https://groups.google.com/group/django-developers.
To view this discussion on the web visit <a href="https://groups.google.com/d/msgid/django-developers/d38358ca-c97f-4bb0-a390-e38f3b4b8f6c%40googlegroups.com?utm_medium=email&amp;utm_source=footer" rel="nofollow" target="_blank" onmousedown="this.href=&#39;https://groups.google.com/d/msgid/django-developers/d38358ca-c97f-4bb0-a390-e38f3b4b8f6c%40googlegroups.com?utm_medium\x3demail\x26utm_source\x3dfooter&#39;;return true;" onclick="this.href=&#39;https://groups.google.com/d/msgid/django-developers/d38358ca-c97f-4bb0-a390-e38f3b4b8f6c%40googlegroups.com?utm_medium\x3demail\x26utm_source\x3dfooter&#39;;return true;">https://groups.google.com/d/msgid/django-developers/d38358ca-c97f-4bb0-a390-e38f3b4b8f6c%40googlegroups.com.

For more options, visit <a href="https://groups.google.com/d/optout" rel="nofollow" target="_blank" onmousedown="this.href=&#39;https://groups.google.com/d/optout&#39;;return true;" onclick="this.href=&#39;https://groups.google.com/d/optout&#39;;return true;">https://groups.google.com/d/optout.



--
Adam

--
You received this message because you are subscribed to the Google Groups "Django developers (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email to <a href="javascript:" target="_blank" gdf-obfuscated-mailto="Zfk2348vAwAJ" rel="nofollow" onmousedown="this.href=&#39;javascript:&#39;;return true;" onclick="this.href=&#39;javascript:&#39;;return true;">django-develop...@googlegroups.com.
To post to this group, send email to <a href="javascript:" target="_blank" gdf-obfuscated-mailto="Zfk2348vAwAJ" rel="nofollow" onmousedown="this.href=&#39;javascript:&#39;;return true;" onclick="this.href=&#39;javascript:&#39;;return true;">django-d...@googlegroups.com.
Visit this group at <a href="https://groups.google.com/group/django-developers" target="_blank" rel="nofollow" onmousedown="this.href=&#39;https://groups.google.com/group/django-developers&#39;;return true;" onclick="this.href=&#39;https://groups.google.com/group/django-developers&#39;;return true;">https://groups.google.com/group/django-developers.
To view this discussion on the web visit <a href="https://groups.google.com/d/msgid/django-developers/3084faa0-e097-4227-9a34-f870c8be6809%40googlegroups.com?utm_medium=email&amp;utm_source=footer" target="_blank" rel="nofollow" onmousedown="this.href=&#39;https://groups.google.com/d/msgid/django-developers/3084faa0-e097-4227-9a34-f870c8be6809%40googlegroups.com?utm_medium\x3demail\x26utm_source\x3dfooter&#39;;return true;" onclick="this.href=&#39;https://groups.google.com/d/msgid/django-developers/3084faa0-e097-4227-9a34-f870c8be6809%40googlegroups.com?utm_medium\x3demail\x26utm_source\x3dfooter&#39;;return true;">https://groups.google.com/d/msgid/django-developers/3084faa0-e097-4227-9a34-f870c8be6809%40googlegroups.com.

For more options, visit <a href="https://groups.google.com/d/optout" target="_blank" rel="nofollow" onmousedown="this.href=&#39;https://groups.google.com/d/optout&#39;;return true;" onclick="this.href=&#39;https://groups.google.com/d/optout&#39;;return true;">https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "Django developers (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To post to this group, send email to [hidden email].
Visit this group at https://groups.google.com/group/django-developers.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-developers/1285c4d6-25d1-4c3f-8664-654ed6ccf9eb%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Adding UNION/INTERSECT/EXCEPT to the ORM

Florian Apolloner
Jupp, sounds good to me too -- will see that I get the PR updated this afternoon

On Thursday, January 12, 2017 at 1:20:04 AM UTC+1, charettes wrote:
+1 to QuerySet.difference()

Le mercredi 11 janvier 2017 17:00:12 UTC-5, sebleier a écrit :
We cannot use the name "QuerySet.except()" since except is a reserved word in Python. Do you prefer minus() (as suggested by Florian), except_() (as done by SQLAlchemy), or something else?


Can I suggest using "QuerySet.difference"?   It's what python's sets use for achieving the same functionality.

On Monday, December 26, 2016 at 6:28:15 PM UTC-5, Adam Johnson wrote:
Yes it's different, they cannot be changed due to backwards compatibility issues. They don't result in UNION in SQL, they union the filters on two querysets that are on the same exact model.

On 26 December 2016 at 21:00, Cristiano Coelho <[hidden email]> wrote:
Is this going to be different from the pipe ( | ) and and ( & ) operators on querysets? If I'm not wrong those can already result in a union query (but not necessary, sometimes it just returns a query with an or/and condition)


El viernes, 23 de diciembre de 2016, 11:12:40 (UTC-3), Florian Apolloner escribió:
Hi,

I have a currently WIP PR at <a href="https://github.com/django/django/pull/7727" rel="nofollow" target="_blank" onmousedown="this.href=&#39;https://www.google.com/url?q\x3dhttps%3A%2F%2Fgithub.com%2Fdjango%2Fdjango%2Fpull%2F7727\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNHahCoQjYDy0Q2J9ocfWPPfsKKjBw&#39;;return true;" onclick="this.href=&#39;https://www.google.com/url?q\x3dhttps%3A%2F%2Fgithub.com%2Fdjango%2Fdjango%2Fpull%2F7727\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNHahCoQjYDy0Q2J9ocfWPPfsKKjBw&#39;;return true;">https://github.com/django/django/pull/7727

The usage is currently something like this:

qs1 = User.objects.all().values('username')
qs2 = Group.objects.all().values('name')
results = qs1.union(qs).distinct().order_by('name')[:10]

(order_by does not work though yet)

So far I have a few questions:

 * Should .union/.intersect etc return a new type of queryset or stay with the base QuerySet class (probably less code duplication)
 * We currently have a few methods which check can_filter and error out accordingly (ie you cannot filter after slicing), but as the error message in <a href="https://github.com/django/django/blob/master/django/db/models/query.py#L579" rel="nofollow" target="_blank" onmousedown="this.href=&#39;https://www.google.com/url?q\x3dhttps%3A%2F%2Fgithub.com%2Fdjango%2Fdjango%2Fblob%2Fmaster%2Fdjango%2Fdb%2Fmodels%2Fquery.py%23L579\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNHcvxsaP47dZNNK88lfNcSFDPWU8Q&#39;;return true;" onclick="this.href=&#39;https://www.google.com/url?q\x3dhttps%3A%2F%2Fgithub.com%2Fdjango%2Fdjango%2Fblob%2Fmaster%2Fdjango%2Fdb%2Fmodels%2Fquery.py%23L579\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNHcvxsaP47dZNNK88lfNcSFDPWU8Q&#39;;return true;">https://github.com/django/django/blob/master/django/db/models/query.py#L579 shows, this strongly relies on knowledge of the implementation of the filter. For combined querysets I basically need to limit everything aside from order by and limit/offset. Would a method like this make some sense (on the Query class):

def is_allowed(self, action):
  if self.combinatorial and action not in ('set_operation', 'order_by', 'slicing'):
    raise SomeError('Cannot use this method on an combinatorial queryset')
  elif action == 'filter' and (self.low_mark or self.high_mark):
    raise SomeError('Cannot filter after slicing')

 * set_operator in base.py feels a bit weird (<a href="https://github.com/django/django/pull/7727/files#diff-53fcf3ac0535307033e0cfabb85c5301" rel="nofollow" target="_blank" onmousedown="this.href=&#39;https://www.google.com/url?q\x3dhttps%3A%2F%2Fgithub.com%2Fdjango%2Fdjango%2Fpull%2F7727%2Ffiles%23diff-53fcf3ac0535307033e0cfabb85c5301\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNFQ3Vjjs8Qxz7CRIkz_0vLiQvn99A&#39;;return true;" onclick="this.href=&#39;https://www.google.com/url?q\x3dhttps%3A%2F%2Fgithub.com%2Fdjango%2Fdjango%2Fpull%2F7727%2Ffiles%23diff-53fcf3ac0535307033e0cfabb85c5301\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNFQ3Vjjs8Qxz7CRIkz_0vLiQvn99A&#39;;return true;">https://github.com/django/django/pull/7727/files#diff-53fcf3ac0535307033e0cfabb85c5301) -- any better options?
 * How can I change the generated order_by clause to reference the columns "unqualified" (ie without table name), can I somehow just realias every column?

Cheers,
Florian

--
You received this message because you are subscribed to the Google Groups "Django developers (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-develop...@googlegroups.com.
To post to this group, send email to [hidden email].
Visit this group at <a href="https://groups.google.com/group/django-developers" rel="nofollow" target="_blank" onmousedown="this.href=&#39;https://groups.google.com/group/django-developers&#39;;return true;" onclick="this.href=&#39;https://groups.google.com/group/django-developers&#39;;return true;">https://groups.google.com/group/django-developers.
To view this discussion on the web visit <a href="https://groups.google.com/d/msgid/django-developers/d38358ca-c97f-4bb0-a390-e38f3b4b8f6c%40googlegroups.com?utm_medium=email&amp;utm_source=footer" rel="nofollow" target="_blank" onmousedown="this.href=&#39;https://groups.google.com/d/msgid/django-developers/d38358ca-c97f-4bb0-a390-e38f3b4b8f6c%40googlegroups.com?utm_medium\x3demail\x26utm_source\x3dfooter&#39;;return true;" onclick="this.href=&#39;https://groups.google.com/d/msgid/django-developers/d38358ca-c97f-4bb0-a390-e38f3b4b8f6c%40googlegroups.com?utm_medium\x3demail\x26utm_source\x3dfooter&#39;;return true;">https://groups.google.com/d/msgid/django-developers/d38358ca-c97f-4bb0-a390-e38f3b4b8f6c%40googlegroups.com.

For more options, visit <a href="https://groups.google.com/d/optout" rel="nofollow" target="_blank" onmousedown="this.href=&#39;https://groups.google.com/d/optout&#39;;return true;" onclick="this.href=&#39;https://groups.google.com/d/optout&#39;;return true;">https://groups.google.com/d/optout.



--
Adam

--
You received this message because you are subscribed to the Google Groups "Django developers (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-develop...@googlegroups.com.
To post to this group, send email to [hidden email].
Visit this group at <a href="https://groups.google.com/group/django-developers" rel="nofollow" target="_blank" onmousedown="this.href=&#39;https://groups.google.com/group/django-developers&#39;;return true;" onclick="this.href=&#39;https://groups.google.com/group/django-developers&#39;;return true;">https://groups.google.com/group/django-developers.
To view this discussion on the web visit <a href="https://groups.google.com/d/msgid/django-developers/3084faa0-e097-4227-9a34-f870c8be6809%40googlegroups.com?utm_medium=email&amp;utm_source=footer" rel="nofollow" target="_blank" onmousedown="this.href=&#39;https://groups.google.com/d/msgid/django-developers/3084faa0-e097-4227-9a34-f870c8be6809%40googlegroups.com?utm_medium\x3demail\x26utm_source\x3dfooter&#39;;return true;" onclick="this.href=&#39;https://groups.google.com/d/msgid/django-developers/3084faa0-e097-4227-9a34-f870c8be6809%40googlegroups.com?utm_medium\x3demail\x26utm_source\x3dfooter&#39;;return true;">https://groups.google.com/d/msgid/django-developers/3084faa0-e097-4227-9a34-f870c8be6809%40googlegroups.com.

For more options, visit <a href="https://groups.google.com/d/optout" rel="nofollow" target="_blank" onmousedown="this.href=&#39;https://groups.google.com/d/optout&#39;;return true;" onclick="this.href=&#39;https://groups.google.com/d/optout&#39;;return true;">https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "Django developers (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To post to this group, send email to [hidden email].
Visit this group at https://groups.google.com/group/django-developers.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-developers/d211752a-5a25-486c-a0b8-f458821101b2%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Loading...