Search code examples
djangourlmany-to-manymodels

Access one element from ManyToMany Field in models.py in order to construct get_absolute_url


I have this in my models.py:

 def get_absolute_url(self):
         return "/subject/%s/graphs/%s/" % (self.subject, self.slug)

where subject and slug are accordingly:

subject = models.ManyToManyField(Subject)
slug = models.SlugField(max_length=120, unique=True)

and I know that the approach I have in the get_absolute_url() function is wrong, and returns the list of Subject objects.

I want to access only one element (it doesn't matter which one it will be) so I can construct the url of the graph, but I don't know how to do that. I've tried several things, but they don't work.

Update:

Got the solution:

def get_absolute_url(self):
         for e in self.subject.all():
             return "/subject/%s/graphs/%s/" % (e.url_id, self.slug)

It works like this. There is no need to check if there is a subject because there will always be.


Solution

  • Your ManyToMany field is a relationship that returns a QuerySet of multiple objects, so you need to choose one object from that queryset to use to construct your URL. You can do this many ways.

    For example, if your Subject model has a date field, you could return the latest Subject:

    return "/subject/%s/graphs/%s/" % (self.subject.all().latest("my_date_field"), self.slug)
    

    alternatively, you could just try and get the first Subject of the queryset:

    return "/subject/%s/graphs/%s/" % (self.subject.all()[0], self.slug)
    

    Have a look at the QuerySet API to see what might be most appropriate for you.

    You should also remember that your get_absolute_url method will likely throw an exception if there are no Subject objects associated with your model so you should do:

    def get_absolute_url(self):
        try:
            return "/subject..."
        except:
            return "/another-url/"