0

I realize that select_related only works on foreign key and one-to-one relationships, but it seems there should be a simple, select_related-like way to join over many-to-many relations that are unique together provided all but one of the unique_together parameters is given.

class User(models.Model):
  article_access_set = models.ManyToManyField(Article,
      through='UserArticleAccess', related_name='user_access_set')
  # User Information ...

class Article(models.Model):
  # Article Information ...

class UserArticleAccess(models.Model):

  user = models.ForeignKey(User)
  article = models.ForeignKey(Article)

  # UserArticleAccess Information: flags, liked, last_access_time, ... 

  class Meta:
      unique_together = ('user', 'article')

I'm looking for a magical method:

qs = Article.objects.all().magical_select_related(select={
    'user_access_set': {'user': request.user}})

print qs[0].user_access_set
# <UserArticleAccess ...>
print qs[1].user_access_set # No Access
# None

Or maybe:

qs = Article.objects.all().magical_select_related(select = {
    'user_access_set': {'user': request.user}},
  as = {'user_access_set': 'user_access'})

print qs[0].user_access
# <UserArticleAccess ...>
print qs[1].user_access # No Access
# None

Is there any way to do this? (Or a reason that this shouldn't be implemented in this way or a similar way?)

Austin New
  • 113
  • 1
  • 6
  • You know that `prefetch_related` is a performance tuning tool that doesn't actually change what data is available, right? It just preloads it, trading off some extra memory and immediate processing time to avoid making further database queries as needed. Are you specifically trying to optimize access here, or are you' just unsure how to get related objects through the many-to-many field? – Peter DeGlopper Jul 17 '13 at 20:41
  • I'm specifically trying to optimize. I'm expecting all user accesses (for some selected set of articles) will take a debilitating amount of memory for relatively few queries. – Austin New Jul 17 '13 at 20:49
  • Hmm. Are you doing something like expecting to go through a query set of articles, then figure out which users have access to them? `prefetch_related` increases the amount of memory required, so if it's memory you're most worried about it it's the wrong tool. If you're willing to trade off increased memory use, https://docs.djangoproject.com/en/1.4/ref/models/querysets/#prefetch-related is the best I know of. – Peter DeGlopper Jul 17 '13 at 20:54
  • Thanks, Peter. I do know about `prefetch_related`, it's what I'm using currently. I'm expecting to go through a query set of articles and contextualize them to the user. If the user has never accessed the article it looks a certain way, if they have accessed it will be presented another way, if they've liked the article... etc. These articles are presented in a list. Given a user I'm expecting so many articles with a single access or no access for each article (the access containing data for each contextualization). Perhaps Access was bad word choice. – Austin New Jul 17 '13 at 21:22
  • Bah, you're right about my proposed answer not handling articles with no related access instances. Bother, I thought that was clever. – Peter DeGlopper Jul 17 '13 at 22:22

2 Answers2

0

Please, look at this post Django : select_related with ManyToManyField.

prefetch_related() can join data but in python.

Community
  • 1
  • 1
twil
  • 6,032
  • 1
  • 30
  • 28
0

With Django 1.10 you can use django.db.models.fields.related.ForeignObject class (it's not a public API).

See the conversation about this issue in https://groups.google.com/forum/#!topic/django-users/pGGHKb4Y8ZY

You can see examples in tests/foreign_object/tests.py of the following commit: https://github.com/django/django/commit/80dac8c33e7f6f22577e4346f44e4c5ee89b648c

epineda
  • 442
  • 7
  • 13