Search code examples
djangodjango-modelsmany-to-manydjango-querysetdjango-orm

How to get 1 list when using django queries with a M2M relationship


This question is very similar(if not the same to): Django query — how to get list of dictionaries with M2M relation? .

I am just asking this question to be able to learn if there has been any improvements to djagno that include functionality for this since 11 yrs ago


I have a M2M relationship:

class RandomObject(models.Model):
    name = models.CharField(max_length=50,blank=False) 
    description = models.TextField(blank=False)
    features = models.ManyToManyField('Features',blank=False,db_table='RandomObjectFeatures')

class Features(models.Model):

    LIGHTING = "LIT" 
    SECURE = "SGE"
    COVERED ="CVP" 
    
    FEATURE_NAME_CHOICES = [
                    (LIGHTING,"Lighting"),   
                    (SECURE,"Secured Well"),
                    (COVERED,"Covered"),
    ]
    
    feature_name = models.CharField(max_length=3,choices=FEATURE_NAME_CHOICES,blank=False,null=True)
    
    def __str__(self):
        for code, display_name in self.FEATURE_NAME_CHOICES:
            if self.feature_name == code:
                return display_name
        return self.feature_name

I have populated the database and now want to query the database to be able to show the features of a randomObject in a template

random_objects = RandomObjects.objects.all()
random_objects_data = random_objects.values('name','features__feature_name') 

Now when I print random_objects_data I get the following: (I have truncated it as it is long, but it makes the point)

{'name': 'object1', 'features__feature_name': 'SGE'}, {'name': 'object1', 'features__feature_name': 'LIT'},{'name': 'object1', 'features__feature_name': 'CVP'}

This is unhelpful as objects not in the database are created. I would like to get (or something similar to):

 {'name': 'object1', 'features__feature_name': ['SGE','LIT','CVP']}

This means in the template I can iterate though each feature in features__feature_name.

Thanks!


Solution

  • If from your views.py your context is like this..

    {'random_objects': RandomObject.objects.all()}
    

    In your template:

    {% for random in random_objects %}
      # render some things
      {% for feature in random.features_list.features %}
         {{feature}}
      {% endfor %}
    {% endfor %}
    

    In your models:

       class RandomObject(models.Model):
           name = models.CharField(max_length=50,blank=False)
          description = models.TextField(blank=False)
          features = models.ManyToManyField('Features')
          
         @property
         def features_list(self):
           return {
             'name': self.name
             'features': [feature.feature_name for feature in self.features.all()]
           }