Get all sites (ManyToManyField) of an article

https://docs.djangoproject.com/en/4.0/ref/contrib/sites/#associating-content-with-multiple-sites
How do I get all sites of an article ?

from django.contrib.sites.models import Site
from django.db import models

class Article(models.Model):
    headline = models.CharField(max_length=200)
    # ...
    sites = models.ManyToManyField(Site)

    def __str__(self):
        print(self.sites) # Always prints sites.None and not siteName1, siteName2
        return self.headline

There are all sorts of examples at Many-to-many relationships | Django documentation | Django, with some technical detail at Related objects reference | Django documentation | Django.

Briefly, sites is a ManyToManyField, which means it’s not one object. It’s a reference to a set of objects, represented in Django as a queryset. So, the complete set of referenced sites should be self.sites.all(). (The reverse case, where given a site and you want all the articles associated with it would be some_site.article_set.all().)

However, if you’re printing None, that makes me think that you don’t have any sites associated with that article. It should print the reference to the related manager.

I thought I had tried this. I had my class variable name as site. Now I’ve renamed it to website and its all good. Wonder if using site and sites conflicted with the classname Site ?

class Portal(models.Model):
    site = models.OneToOneField(Site, on_delete=models.CASCADE)    
    email = models.EmailField(max_length=100)
    google_analytics_code = models.CharField(max_length=25)
    created = models.DateTimeField(auto_now_add=True)
    active = models.BooleanField(default=True)

    def __str__(self):
        return self.site.name


class Article(models.Model):
    headline = models.CharField(max_length=200)
    sites = models.ManyToManyField(Portal)    

No, that wouldn’t be it. Names are context and case-sensitive.

In the example you’ve shown immediately above, Article.sites isn’t a reference to sites, it’s a reference to Portal. So article.sites.all() is a reference to all the Portal associated with an Article named article. You could then iterate over that queryset to get the Site object for each Portal.

Got it - I ended up doing ", ".join(str(p) for p in self.websites.all())

1 Like