Mr. Editor-in-chief Mr. Editor-in-chief 2 min read 269 words 394 views

Clear Model Relationship API Usage

Django ORM could seem complex and daunting when different kinds of model relationships are combined together. To keep sanity, I devised a basic schema in differentiating different kind of model relationships.

Many-to-many relationships

python
class Publication(models.Model):
    title = models.CharField(max_length=30)

    class Meta:
        ordering = ["title"]

    def __str__(self):
        return self.title

class Article(models.Model):
    headline = models.CharField(max_length=100)
    publication_set = models.ManyToManyField(Publication, related_query_name='article_set')
    # By naming many to many field with _set suffix and setting 'related_query_name' with _set suffix,  I know both     article_obj.publication_set.all() and publication_obj.article_set.all() work and Article and Publication are ManyToMany-related to each other. Both Article.object.filter(publication_set__tile__istartswith='Science') and Publication.objects.filter(article_set__pk=1) work, too.

    class Meta:
        ordering = ["headline"]

    def __str__(self):
        return self.headline

Many-to-one relationships

python
class Reporter(models.Model):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)
    email = models.EmailField()

    def __str__(self):
        return f"{self.first_name} {self.last_name}"


class Report(models.Model):
    headline = models.CharField(max_length=100)
    pub_date = models.DateField()
    reporter = models.ForeignKey(Reporter, related_name='reports', on_delete=models.CASCADE)
    # By set 'related_name' with 's' suffix or other plural form,  It is clear to me this is a one to many relation.
    # Now both reporter_obj.reports.all() and Reporter.objects.filter(reports__headline__icontains='This') work.

    def __str__(self):
        return self.headline

    class Meta:
        ordering = ["headline"]

One-to-one relationships

python
class Place(models.Model):
    name = models.CharField(max_length=50)
    address = models.CharField(max_length=80)

    def __str__(self):
        return f"{self.name} the place"


class Restaurant(models.Model):
    place = models.OneToOneField(
        Place,
        on_delete=models.CASCADE,
        primary_key=True,
    )
    # Queries such as restaurant_obj.place, place_obj.restaurant, Restaurant.objects.filter(place__name__startswith='Demon) and Place.objects.filter(restaurant__serves_pizza=True) will work.
    serves_hot_dogs = models.BooleanField(default=False)
    serves_pizza = models.BooleanField(default=False)

    def __str__(self):
        return "%s the restaurant" % self.place.name


class Waiter(models.Model):
    restaurant = models.ForeignKey(Restaurant, related_name='waiters', on_delete=models.CASCADE)
    name = models.CharField(max_length=50)

    def __str__(self):
        return "%s the waiter at %s" % (self.name, self.restaurant)

Please refer to Django Documentation: Examples of model relationship API usage for detailed query examples and try out yourself.

Copied to clipboard

Share this post

Related Posts