Search code examples
pythondjangodjango-2.2

Django many to many relation, include all IDs in queryset in both directions


I have 2 models connected via M2M relation

class Paper(models.Model):
  title = models.CharField(max_length=70)
  authors = models.ManyToManyField(B, related_name='papers')

class Author():
  name = models.CharField(max_length=70)
  • Is there a way to include authors as all related authors' IDs (and maybe name somehow)?

  • Is there a way to include papers IDs as reverse relation (and maybe title as well)?

Author.objects.all().annotate(related_papers=F('papers'))

this only adds id of one paper, first one it finds I think.

Furthermore, changing related_papers to papers gives an error:

ValueError: The annotation ‘papers’ conflicts with a field on the
model.

Solution

  • From what I understand in your comments, you're using DRF. I will give you 2 answers.

    1) If you're talking about model serializer, you can use PrimaryKeyRelatedField :

    class AuthorSerializer(serializers.ModelSerializer):
        papers=serializers.PrimaryKeyRelatedField(many=True, read_only=True)
    
        class Meta:
            model = Author
            fields = ['name', 'papers']
    
    class PaperSerializer(serializers.ModelSerializer):
        class Meta:
            model = Paper
            fields = '__all__'
    
    

    This will return the IDs for the other side of the relationship whether you're on Paper or Author side. That will return the primary keys, not a representation of the object itself.

    2) Now you're also talking about performance (e.g. database hit at each iteration).

    Django (not DRF-specific) has a queryset method to handle preloading related objects. It's called prefetch_related.

    For example, if you know you're going to need the relation object attributes and want to avoid re-querying the database, do as follow:

    Author.objects.all().prefetch_related('papers') 
    # papers will be already loaded, thus won't need another database hit if you iterate over them.