<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Mackenzie</title>
    <description>The latest articles on DEV Community by Mackenzie (@maco).</description>
    <link>https://dev.to/maco</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F594147%2F5f35da8d-f2a8-4beb-9e5b-0e1f1bcc1c3b.jpeg</url>
      <title>DEV Community: Mackenzie</title>
      <link>https://dev.to/maco</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/maco"/>
    <language>en</language>
    <item>
      <title>How to Network</title>
      <dc:creator>Mackenzie</dc:creator>
      <pubDate>Mon, 20 Sep 2021 16:45:41 +0000</pubDate>
      <link>https://dev.to/maco/how-to-network-8kg</link>
      <guid>https://dev.to/maco/how-to-network-8kg</guid>
      <description>&lt;p&gt;Maybe you're about to graduate, just graduated, or have been teaching yourself to code for the last few years, and you don't know how to get your foot in the door with that first job. You see all those "entry-level" jobs that expect a year or three of experience. Networking is incredibly important, especially if you don't have any professional experience in the tech industry yet.&lt;/p&gt;

&lt;p&gt;We've all heard it: "it's not what you know; it's who you know." I, personally, have gotten only two jobs (in a 14-year career) from a cold start. And frankly, one wasn't a true cold start; a recruiter asked if he could show my 2017 resume to the company where I'd done my first internship, way back in 2007.&lt;/p&gt;

&lt;p&gt;The thing to remember is that a lot of resumes get thrown out before the phone screen phase. If you have a personal recommendation from someone inside the company saying "give this person a try," you pretty much automatically skip to the next round.&lt;/p&gt;

&lt;p&gt;Networking comes pretty natural to me. I come from a family of sales people. I was literally taught to talk to strangers.&lt;/p&gt;

&lt;p&gt;If that's not you, how do you network? How do you make a name for yourself in the tech community?&lt;/p&gt;

&lt;h2&gt;
  
  
  In person
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Where to go
&lt;/h3&gt;

&lt;p&gt;I'm a big fan of meetups. Go to &lt;a href="https://meetup.com/"&gt;Meetup.com&lt;/a&gt; and find the local meetups for the technologies you use. Maybe that's a Linux Users Group (I spent so much time with DCLUG). Maybe that's a Ruby Users Group. Maybe it's a frontend developer group. Whatever your thing is, there's probably a group. These are free. They might pass a hat if they rent space.&lt;/p&gt;

&lt;p&gt;I also like to go to conferences from time to time. These range from free (LinuxFests) to thousands of dollars (big corporate things where they expect your employer to pay). The ones with admission fees always have ways to lower the price.&lt;/p&gt;

&lt;p&gt;In either case, the primary purpose of the event is usually to learn something new from the presenter. Be sure to bring a notebook and take some good notes. You can write down questions as you think of them (and answers as they get answered). Still have a good question left at the end? If you were paying close enough attention to take notes, it's likely to be a good question. (There's always someone who gets the answer "I addressed that on slide 7.")&lt;/p&gt;

&lt;h3&gt;
  
  
  What to do
&lt;/h3&gt;

&lt;p&gt;You're going to want to have some cards printed up to bring with you. You can get more than you need for $10 from VistaPrint. Get the kind that aren't shiny, so you can write on the back. (Making them memorable doesn't hurt. My first set had my name in pastel pink binary on the back.)&lt;/p&gt;

&lt;p&gt;Show up a bit early. That gives you time to chat with the other early arrivers. Stay late. If some folks go out for food or drinks afterward, tag along. It gives you more time to chat with people, and often it'll be the same group going out to the same place each time, so you'll be able to build a stronger connection with those folks.&lt;/p&gt;

&lt;p&gt;"Chat with folks" isn't helpful advice for everyone, so here are some tips:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"What have you been working on lately?" is a question you want to feel comfortable both asking and answering. Maybe your answer sounds like "I've been working on a {tech}-based app that {verbs} with data from {source}. Trying to get into {specialization}, you know?"&lt;/li&gt;
&lt;li&gt;At a conference, good hallway conversation starters include: "so what talk did you just go to?" and "what's your favorite talk so far?" You can learn a lot that way. Be sure you have an answer to "how about you?"&lt;/li&gt;
&lt;li&gt;If someone tells you where they work, "how do you like it there?" is a good follow-up. If they like it, then "do you know of any openings?" is your next question.&lt;/li&gt;
&lt;li&gt;Ask good technical questions. If you can relate the tech topic to something else and ask how X affects Y, great.&lt;/li&gt;
&lt;li&gt;Be helpful. If you can solve a problem someone is having, they'll remember that. Fix their wifi. Recommend a library.&lt;/li&gt;
&lt;li&gt;"Hey, by the way, do you have a card?" while holding out yours is a fine note on which to end a conversation.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Online
&lt;/h2&gt;

&lt;p&gt;In these, the plague years, many meetups are happening online. Folks are attending meetups in other cities via Zoom and Google Meet. That's great! Definitely take advantage of that.&lt;/p&gt;

&lt;p&gt;But there are other options too, mainly in the form of what we used to call chat rooms but now call Slack, IRC, and Discord.&lt;/p&gt;

&lt;p&gt;Here in the DC area, we have the &lt;a href="http://www.dctechslack.com/"&gt;DC Tech Slack&lt;/a&gt;. And there's the &lt;a href="https://witchat.github.io/"&gt;Women in Tech Chat on Slack&lt;/a&gt; too. Back in 2006, I was on &lt;a href="https://www.linuxchix.org/"&gt;LinuxChix&lt;/a&gt;'s IRC server all the time and spent a ton of time on FreeNode IRC.&lt;/p&gt;

&lt;p&gt;Forums and message boards may seem a bit 90s, but languages still have them. (I know &lt;a href="https://elixirforum.com/"&gt;Elixir has a forum&lt;/a&gt;.)&lt;/p&gt;

&lt;h2&gt;
  
  
  Building a reputation
&lt;/h2&gt;

&lt;p&gt;Don't neglect to make your work easy to find online. Most importantly: do you have a homepage? Do you blog, tweet, or stream?&lt;/p&gt;

&lt;p&gt;I started tech blogging probably in 2006 when I started using Ubuntu. I wanted somewhere to put the things I was learning and the records of "how did I fix that the first time?" If I broke my computer, I wanted the instructions to be online for when I set it back up!&lt;/p&gt;

&lt;p&gt;That blog became one of the most popular Ubuntu blogs out there. You know whose blogs you land on repeatedly when trying to solve a problem, right? And if their resume came across your desk, you'd say "oh yeah, they know their stuff. Bring them in!"&lt;/p&gt;

&lt;p&gt;Speaking at meetups and conferences is also a great way to get a solid reputation. I've never spoken at a meetup, only at conferences, but I hear doing your talk once at a meetup before the conference can be a good way to work out the timing and the kinks. It's a much smaller crowd, and meetups always need more speakers.&lt;/p&gt;

&lt;p&gt;Good luck with your job hunt!&lt;/p&gt;

</description>
      <category>career</category>
      <category>networking</category>
    </item>
    <item>
      <title>Elixir Wizards Talk: "Dealing With a Monster Ecto Query"</title>
      <dc:creator>Mackenzie</dc:creator>
      <pubDate>Fri, 30 Jul 2021 14:19:36 +0000</pubDate>
      <link>https://dev.to/maco/elixir-wizards-talk-dealing-with-a-monster-ecto-query-1k52</link>
      <guid>https://dev.to/maco/elixir-wizards-talk-dealing-with-a-monster-ecto-query-1k52</guid>
      <description>&lt;p&gt;Last month, I spoke at the first-ever &lt;a href="https://smartlogic.io/about/community/elixir-wizards-conference/"&gt;Elixir Wizards Conference&lt;/a&gt;. It was a lightning talk walking through a refactor I did before the 2020 US Presidential Election, titled "Dealing With a Monster Ecto Query."&lt;/p&gt;

&lt;p&gt;I work for a news company, so the presidential election is a huge deal; we can't have downtime. I knew which query was our bottleneck, so I optimized it right before the election. This took advantage of a few Elixir features, like atoms, the pin operator, and concurrency primitives.&lt;/p&gt;

&lt;p&gt;You can watch the talk below:&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/-82nj9rWSwc"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/maco/slides/tree/main/monster_ecto_query"&gt;Source code for slides&lt;/a&gt;&lt;/p&gt;

</description>
      <category>elixir</category>
      <category>conferencetalk</category>
      <category>ecto</category>
    </item>
    <item>
      <title>Start of a List</title>
      <dc:creator>Mackenzie</dc:creator>
      <pubDate>Thu, 29 Jul 2021 04:41:53 +0000</pubDate>
      <link>https://dev.to/maco/start-of-a-list-mbc</link>
      <guid>https://dev.to/maco/start-of-a-list-mbc</guid>
      <description>&lt;p&gt;Elixir has a &lt;em&gt;lot&lt;/em&gt; of ways to get the first thing in a list. One of the first things you learn from the basic syntax guide on the Elixir website is that &lt;code&gt;hd(foo)&lt;/code&gt; gets the first thing in a list, and &lt;code&gt;tl(foo)&lt;/code&gt; gets the rest. You also learn &lt;code&gt;[ head | tail ] = foo&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;But what happens when it's an empty list?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;foo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;hd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;ArgumentError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;argument&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt;
    &lt;span class="ss"&gt;:erlang&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hd&lt;/span&gt;&lt;span class="p"&gt;([])&lt;/span&gt;
&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;tl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;ArgumentError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;argument&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt;
    &lt;span class="ss"&gt;:erlang&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tl&lt;/span&gt;&lt;span class="p"&gt;([])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Those first bits of syntax you learned will throw errors if given empty lists. That means you need to only use them after confirming the list has stuff in it, such as with a conditional or by pattern-matching.&lt;/p&gt;

&lt;p&gt;If you aren't guaranteed the list has anything at all in it (such as after piping through an &lt;code&gt;Enum.filter/2&lt;/code&gt; or &lt;code&gt;Enum.reject/2&lt;/code&gt;), you need to go deeper into the standard library.&lt;/p&gt;

&lt;p&gt;Three ways I know to get the first item are &lt;code&gt;Enum.at/2&lt;/code&gt;, &lt;code&gt;List.first/1&lt;/code&gt;, and &lt;code&gt;Enum.take/2&lt;/code&gt;. At this point the question is: &lt;strong&gt;what kind of output do you need?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you want to get back the actual item itself (like you'd get from &lt;code&gt;hd/1&lt;/code&gt;), two ways to ensure you get &lt;code&gt;nil&lt;/code&gt; (instead of an error) when it's empty are to use &lt;code&gt;Enum.at/2&lt;/code&gt; or &lt;code&gt;List.first/1&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;foo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Enum&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;at&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="no"&gt;nil&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;foo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="no"&gt;nil&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If, on the other hand, you need a list (albeit, a potentially empty one) to make later functions in your pipeline happy? In that case, try &lt;code&gt;Enum.take/2&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;foo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Enum&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;take&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;[]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(&lt;code&gt;Enum.take/2&lt;/code&gt; will return a list with length &lt;em&gt;up to&lt;/em&gt; the number you specified, as available from the list. Give it a list of length 3 and ask for 5? You'll get all 3 items back.)&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Django Admin color picker</title>
      <dc:creator>Mackenzie</dc:creator>
      <pubDate>Wed, 31 Mar 2021 08:14:56 +0000</pubDate>
      <link>https://dev.to/maco/django-admin-color-picker-4g43</link>
      <guid>https://dev.to/maco/django-admin-color-picker-4g43</guid>
      <description>&lt;p&gt;When I add a new model to the Django app at work, I try to make sure the results in the Django admin have good usability, too. Just because it'll be mainly developers (and a few project managers) seeing it doesn't mean I can neglect usability. Consequently, I spend some time on hacking the Django admin. My manager says I've been making it do things he didn't even realize were possible.&lt;/p&gt;

&lt;p&gt;The most recent thing I did was add a color field to a model. I considered &lt;a href="https://github.com/fabiocaccamo/django-colorfield"&gt;Django Colorfield&lt;/a&gt;, but there's an open issue about it using GPLv3-licensed code while being MIT-licensed. 😬  So, I dug around a bit.&lt;/p&gt;

&lt;h2&gt;
  
  
  Basic color picker
&lt;/h2&gt;

&lt;p&gt;First, I set up the model to have a &lt;code&gt;primary_color&lt;/code&gt; that's a &lt;code&gt;CharField&lt;/code&gt; of length 7, to accommodate a standard&lt;code&gt;"#FF00FF"&lt;/code&gt; RGB HEX code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyModel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Model&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
     &lt;span class="n"&gt;primary_color&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CharField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"#FFFFFF"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, I found a &lt;a href="https://stackoverflow.com/questions/39859224/how-to-use-html5-color-picker-in-django-admin"&gt;StackOverflow answer&lt;/a&gt; that pointed out that the Django docs include how to override the widget used for a form element, so you can change which HTML5 rendering is used for &lt;code&gt;&amp;lt;input&amp;gt;&lt;/code&gt; fields. Cool! So I just needed to add a &lt;code&gt;forms.py&lt;/code&gt; like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;django.forms&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ModelForm&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;django.forms.widgets&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;TextInput&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;myapp.models&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;MyModel&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyModelForm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ModelForm&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Meta&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MyModel&lt;/span&gt;
        &lt;span class="n"&gt;fields&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"__all__"&lt;/span&gt;
        &lt;span class="n"&gt;widgets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="s"&gt;"primary_color"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;TextInput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;attrs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"color"&lt;/span&gt;&lt;span class="p"&gt;}),&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and update the &lt;code&gt;admin.py&lt;/code&gt; to use it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;myapp.forms&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;MyModelForm&lt;/span&gt;

&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;admin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MyModel&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyModel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;admin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ModelAdmin&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;form&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MyModelForm&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and I'd be all set, right? Indeed, it did now show me a filled-in color block in the admin!&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding a tooltip
&lt;/h2&gt;

&lt;p&gt;But I still wasn't happy. I wanted a way to see the HEX code for the color just by looking at it in the admin. With the HTML5 element's behavior, you have to click on the color block to get a pop-up color picker and go from there to find the HEX. In Chrome on my Mac, I had to click two more times to get it to HEX mode. Ugh.&lt;/p&gt;

&lt;p&gt;So, I dug around some more. I wasn't able to find a way to display the HEX alongside the color block, so I decided to try for putting it in a tooltip. I needed a way to get the instance of the form field, so I could read its value. With further searching, I stumbled upon a &lt;a href="https://stackoverflow.com/a/5129454"&gt;mostly-unrelated StackOverflow answer&lt;/a&gt; that mentioned &lt;code&gt;self.instance&lt;/code&gt;. Great, now I just had to figure out where &lt;code&gt;self&lt;/code&gt; was accessible from in &lt;code&gt;ModelForm&lt;/code&gt;. Almost there! After consulting the Django docs to see which methods have access to &lt;code&gt;self&lt;/code&gt;, I landed on this solution. In that same &lt;code&gt;MyModelForm&lt;/code&gt; class in &lt;code&gt;forms.py&lt;/code&gt;, I added:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nb"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MyModelForm&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"primary_color"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;widget&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TextInput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;attrs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"color"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;primary_color&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This grabs the value of the color field and sets it as the title attribute on the element. Title attributes display as tooltips in the browser.&lt;/p&gt;

</description>
      <category>django</category>
      <category>usability</category>
    </item>
  </channel>
</rss>
