Django Form Label for Many-to-Many with Extra Fields

January 12, 2017 11:36 am

I’m working on a Django application at work that has several Many-to-Many relationships that have extra fields attached to them. Setting this up using the “through” parameter on the field definition is described in the Django documentation.

My trouble came in when it came time to render this information out to the user in a form so they could update the extra fields.  From the user’s perspective the relationship can’t be changed, but the extra fields could be.

Extending Django’s example usage about band membership, if the user were viewing the information for “The Beatles” and including a formset for all band members the form would normally render something like this:

Group Name: The Beatles
Members:
    Group: The Beatles
    Person: Ringo Starr
    Date Joined: 14 August 1962
    -
    Group: The Beatles
    Person: John Lennon
    Date Joined: 01 August 1960
    -
    [etc.]

But this is a little obtuse if the purpose of the form is to allow the user to edit the “Date Joined” value for each band member.  We can whittle the form down by telling the formset to only render the “Date Joined” field [by passing fields=(‘date_joined’,) to modelformset_factory], but then we get this:

Group Name: The Beatles
Members:
    Date Joined: 14 August 1962
    -
    Date Joined: 01 August 1960
    -
    [etc.]

Now we can’t tell to which person each date applies.

Adjusting the form so that the label “Date Joined” was instead the appropriate band members name seems like such a simple thing to change.  But I didn’t want to hand-write the form as it was already being automatically built and rendered for me using using modelformset_factory and Crispy-Forms.

It took me most of a day to figure it out and in the end it was pretty simple.  I only need to implement a custom Form that overrides the constructor and sets the label using the object instance before it gets thrown away:

class MembershipForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super(MembershipForm, self).__init__(*args, **kwargs)
        if kwargs['instance'] and kwargs['instance'].person:
            self.fields['date_joined'].label = kwargs['instance'].person.name
        else:
            self.fields['date_joined'].label = 'No Person'
    class Meta:
        model = Membership
        fields = ['date_joined']

And now our output looks something like:

Group Name: The Beatles
Members:
    Ringo Starr: 14 August 1962
    -
    John Lennon: 01 August 1960
    -
    [etc.]

Since it took me most of a day to figure this out, and I couldn’t find anything specifically addressing this on the Internet, I wrote this up so hopefully the next person (or me in the future once I’ve forgotten this) will have an easier time figuring it out.

Christmas 2016

December 28, 2016 12:27 pm

Christmas was quiet at home this year.

We got a Christmas tree right after Thanksgiving.  We opted out of the cut-our-own route this year.  The trees haven’t been in good shape due to the drought, it’s a long drive, and it doesn’t save any money.  So we just grabbed one from the hardware store.

We wanted another Grand Fir, like we had last year, but no one seemed to have them.  So we ended up with a Nordmann Fir.  It seemed to hold its needles well, but it has no smell at all, and the needles have an almost plastic-y appearance.  We’re going to try for the Grand Fir in the future (they apparently start stocking them a few weeks after Thanksgiving).

I added some berry-like lights to the decorations this year.  I thought they’d look neat hanging from the trellis / wisteria.  The effect wasn’t quite what I had hoped, but I think I can re-work them next time around to have a better outcome.  The picture overexposes the lights hiding their color, so they’re more colorful looking in real life.

On Christmas Eve we got the girls to bed and awaited Santa’s arrival.

To discourage Heather from diving right in to the living room in the morning Jess set up streamers across the doorway:

Then it was to bed for the night….or so we thought.  At about 11:30 Heather got out of bed and came in to our room trying to tell us something, but refusing to open her mouth.  She then ran into the bathroom (thankfully) to throw up.  Once that was out of her system, she started freaking out about the streamers.  She was apparently interpreting them as locking us in or something.  We got her back to bed….and then Corinne woke up.  And around 4 she seemed to decide she was done sleeping.  And finally a little before 7 Heather got up, so we might as well all get up…

Surely Corinne doesn’t have the cognitive capability to have been anticipating getting up Christmas morning, but she was definitely feeding off of Heather’s energy throughout Christmas Eve day.  They were both completely loony.

Anyway, up we got, and much excitement was had.  But first with the requisite anticipation-building pictures:

Corinne ignored the shiny gifts and the colorful “Tote-a-fort” and bee-lined straight for the bowl of M&Ms on the desk (with lurking alligator) and starting shoveling them into her mouth (the kid is a chocolate fiend):

Heather, however, knows the routine and went for her stocking:

Gifts were opened, breakfast casserole was eaten, naps were taken, fun was had by all.

Corinne loves the fort:

Heather helps me open a gift (I think it’s Funny Bones!):

Jess got a new jewelry box:

The brain flakes are lots of fun:

Heather, of course, wanted to do some science and try out the first project from The Magic School Bus Science Club (12-month subscription service).  We built a model lung (balloon), chest cavity (plastic bottle), and diaphragm (plastic wrap).  It actually works too.  Pulling the plastic wrap will inflate the balloon.  This picture is Heather recording her observations about the experiment.

A nice ham dinner was had later on in the day with fresh rolls, of course, and many dessert options.  I had been having waves of mild nausea throughout the day, but my stomach seemed to settle down by dinner and I was able to enjoy the feast.

Corinne was thoroughly worn out by the day.  She napped twice, so we thought she’d be up later than usual, but at about 7pm she dragged a pillow up to me, climbed up in my lap, set the pillow on my legs, folded in half on to the pillow, and fell asleep.

Catch Up: Thanksgiving

December 27, 2016 9:37 am

Thanksgiving this year was just us at home.

I made roll dough the day before so it just needed to be shaped and let rise.

Heather helped me make pumpkin, chocolate-chip cookies:

Then we went outside so she could ride her bike for a bit:

And then it was dinner time.  Turkey, rolls, green-bean casserole, mashed potatoes, gravy, corn, and pies (of course).

Catch Up: Halloween

9:26 am

Heather loves The Magic School Bus and had been asking to be Ms. Frizzle for Halloween for months.  Luckily Grandma was willing to take a crack at making her a costume.  And it came out amazing!  Thanks, Mom!

Heather wanted to look like Ms. Frizzle in her favorite episode, the haunted house episode about sound.  Here is the source material:

And here’s the result:

Corinne got to make her Halloween-costume debut in the blanket costume Jess made when Heather was smaller.  I like this pictures because Corinne is so excited she’s vibrating (since she’s blurry, but Heather’s not).

Heather was a little hesitant about it at first, but she loved it.  And her new “Liz” is one of her core-group stuffed animals now.  Liz is always next to her in bed and is always taken out to the family room every morning.

The above pictures were taken a couple of days before Halloween.  Here’s a day-of picture.  Heather’s face paint was from the Halloween party they had at school.

I got my ghosties up again and bought some batteries to light them up properly with LEDs.  Still needs some work, but they’re getting better:

This was Corinne’s first experience trick-or-treating.  She caught on pretty quickly.  As soon as a door would open she would try to climb inside and reach for any candy she could see.  We did 5 or 6 houses with her and then dropped her off back at home while Heather and I did some more.

We got most of the street trick-or-treated before it started sprinkling.  This caused most people to head inside, even though it stopped before we made it back home.  But we were a bit soggy and Heather was worn out so we called it a night.