python_django_model_query

Django Reverse Query through ManyToManyField

This posts explains querying Django models with ManyToManyField relationships. 

let’s say we have the following two models for Country and News:

models.py

class Country(models.Model):
  country = models.CharField(max_length=100)
  continent = models.CharField(max_length=100)
  class Meta:
          ordering = ('country',) # helps in alphabetical listing. Sould be a tuple
  def __str__(self):
    return self.country+" : "+self.continent


class News(models.Model):
    news_title = models.CharField(max_length=200)
    news_link = models.CharField(max_length=100)
    news_date = models.DateField()
    news_country = models.ManyToManyField(Country)  
    def __str__(self):
        return self.news_title

 

A country can have more than one news, and a news can have more than one country. Therefore, in the News class, we have assigned a ManyToMany relationship with the Country class.

 

Now, once some data is populated, we can query the models through following commands.

 

First, we will run activate the shell

(venv) C:\django_venv\djangoproject>python manage.py shell
Python 3.5.1 (v3.5.1:37a07cee5969, Dec  6 2015, 01:38:48) [MSC v.1900 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>>

Next we will import the class to be queried, from the models

>>> from app.models import News, Country

Running News.objects.all() will output all the rows under the class News.

 

We will take the first news, and assign it a variable

>>> news1 = News.objects.all()[0]

# Alternatively, we can also get the first news by:

>>> news1 = News.objects.get(id=1)


>>> news1
<News: London fintech startup iwoca just got $20 million from German ...>
>>>

 

We can get different fields of the class by calling them

>>> news1.news_title
'London fintech startup iwoca just got $20 million from German ...'

>>> news1.news_date
datetime.date(2015, 7, 30)

>>>

 

However, when we call a field with ManytoMany relationships, we get the following response:

>>> news1.news_country
<django.db.models.fields.related_descriptors.create_forward_many_to_many_manager.<locals>.ManyRelatedManager object at 0x03E17CD0>
>>>

 

For calling a field with ManyToMany relationship, we will pass the following command, and assign it a variable:

 

>>> country1 = news1.news_country.all()
>>> country1
<QuerySet [<Country: UK : Europe>]>
>>>

 

Since the QuerySet has only one country, we can get the same by querying the index (starts from zero). Else, we would have used a For Loop to get all the results.

>>> country1[0]
<Country: UK : Europe>
>>>
>>> type(country1[0])
<class 'dashboard.models.Country'>
>>>

 

The QuerySet is actually pointing us the the Country class in our models. Calling the country, or continent  field of the call, we can retrieve the the country and continent name, respectively.

>>> country1[0].country
'UK'
>>>
>>> country1[0].continent
'Europe'
>>>