liveBook · Manning

SeekingAd

As explained in Django in Action

SeekingAd is the book's Django model representing a classified advertisement from a musician seeking a band or a band seeking a musician.

SeekingAd is a Django model for RiffMates classified advertisements: a musician can seek a band, or a band can seek a musician. It stores the ad's owner, date, direction, related musician or band, and written content. section 7.2.1

The model separates the advertisement's direction from the objects it connects:

  • Use a CharField with TextChoices: "M" represents a musician and "B" represents a band. section 7.2.1
  • Connect musician and band through nullable foreign keys, allowing the appropriate side of the advertisement to be populated. section 7.2.1
  • Record the creation date automatically, associate an owner, store the ad in a TextField, and order records by date. section 7.2.1

Testing SeekingAd through Django Admin

Register SeekingAd with a ModelAdmin and display its id, date, owner, seeking label, and a shortened ad description. Run makemigrations and migrate, then add ads in the Admin while trying different seeking, musician, and band combinations to check validation. section 7.2.2

Listing 7.5 The SeekingAd model stores a RiffMates classified ad
# RiffMates/content/models.py
from django.contrib.auth.models import User
from django.core.exceptions import ValidationError
from django.db import models

from bands.models import Musician, Band

class MusicianBandChoice(models.TextChoices):  #1
    MUSICIAN = "M"
    BAND = "B"

class SeekingAd(models.Model):
    date = models.DateField(auto_now_add=True)  #2
    owner = models.ForeignKey(User,
        on_delete=models.CASCADE)  #3
    seeking = models.CharField(max_length=1,
        choices=MusicianBandChoice.choices)  #4
    musician = models.ForeignKey(Musician, on_delete=models.SET_NULL,
        blank=True, null=True)  #5
    band = models.ForeignKey(Band, on_delete=models.SET_NULL,
        blank=True, null=True)  #6
    content = models.TextField()  #7

    class Meta:
        ordering = ["date", ]  #8

    def __str__(self):
        return f"SeekingAd(id={self.id}, seeking={self.seeking})"

    def clean(self):  #9
        if self.seeking == MusicianBandChoice.MUSICIAN:
            # Validate seeking musician case  #10
            if self.band is None:

                raise ValidationError(
                    "Band field required when seeking a musician")
            if self.musician is not None:
                raise ValidationError(
                    ("Musician field should be empty for a band "
                    "seeking a musician"))

        else:
            # Validate seeking band case  #11
            if self.musician is None:
                raise ValidationError(
                    "Musician field required when seeking a band")
            if self.band is not None:
                raise ValidationError(
                    ("Band field should be empty for a musician "
                    "seeking a band"))

        super().clean()

Inspect the complete SeekingAd model definition, including TextChoices, relationships, ownership, content, and ordering. section 7.2.1

Listing 7.6 Register SeekingAdAdmin in the Django Admin
# RiffMates/content/admin.py
from django.contrib import admin
from django.utils.text import Truncator #1

from content.models import SeekingAd


@admin.register(SeekingAd) #2
class SeekingAdAdmin(admin.ModelAdmin):
    list_display = ("id", "date", "owner", "seeking",
        "show_ad", )  #3

    def show_ad(self, obj):
        return Truncator(obj.content).words(5,
            truncate=' ...') #4
    show_ad.short_description = "Ad"  #5

Inspect the Django Admin registration that truncates long advertisement text for the summary listing. section 7.2.2

How Django in Action covers it

How deep it goes
Defines fields, constrained choices, relationships, ordering, Admin display, migrations, and validation checks without detailing the public submission flow.
Examples
Uses musician-seeking-band and band-seeking-musician ads, TextChoices values, Admin listings, and truncated five-word descriptions.
What you can do after
Operate/configure a SeekingAd model in Django Admin, migrate its database schema, and test combinations of related fields.
How it connects
Connects Django models, TextChoices, ForeignKey relationships, model validation, database migrations, and Django Admin.

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Django in Action. The section links point to the parts of the book it draws on.