Today I Learned
When I learn a random, useful thing I write it down. It's usually tweet-length and captures the insight I gleaned that day. I group them by year.
2023
- From the book "Thinking in Bets":
Fielding outcomes into the skill or luck bucket. Inherently backward looking. Helps you learn from outcomes but isn’t a framework for making decisions, only learning. We have a cognitive bias to attribute wins to skill and losses to luck. And we do the reverse when we observe others — luck when they win, lack of skill when they lose. Fight that self-serving bias by stepping into each others’ shoes. You can also use “wanna bet?” here to challenge your belief of whether the outcome was skill or luck.
- Re: starting a company
- Don't do it alone.
- Don't start with the solution. Care deeply about the problem and the customer.
2022
- Peculiarities about
django-hosts
.- The hosts file identified by
ROOT_HOSTCONF
is used to match an incoming request. - If there is a matching hostname, it will use the urlconf specified in the
ROOT_HOSTCONF
file. - If there is no matching hostname, it will use the host specified by
DEFAULT_HOST
for the incoming request. - When reverse resolving a url name using
{% host_url %}
tags orreverse
fromfrom django_hosts import reverse
, if you don’t pass ahost=
parameter, it will default to whatever is inDEFAULT_HOST
. - I don’t believe
ROOT_URLCONF
is used for anything, although it is still required for some reason, and I think thedjango-hosts
documentation is out of date. - A blank regex will match nothing, so you must use
\w*
for matching nothing (or anything). Otherwise, it will never match incoming requests.
- The hosts file identified by
- The POST/redirect/GET pattern in general recommends that you 302 GET redirect after a POST to avoid browsers attempting to submit forms twice.
- There's an issue that I can't seem to find an authoritative answer to: Unsuccessful POSTs, like in the case of a form that fails validation on the server side. If you redirect to a GET after an unsuccessful POST, you lose the submitted information in the form that was invalid and then you can't show the errors to the user.
- Googling around suggests that the POST/Redirect/GET pattern should only be used on successful POSTs, the thinking being that unsuccessful POSTs shouldn't mutate data anyway and so they are harmless.
- However, I don't think that's right. If the validity of a form submission can change based on factors outside that same form, then a user clicking the back button might accidentally save and overwrite the information on that form inadvertently.
- An example: you have a form where you can submit restaurants, descriptions, and the date you visited. If the date is in the future, the form is invalid. But if the date occurs and you click the back button, it will successfully submit the form, even though it was invalid the first time you submitted that. That's unexpected, and if you submitted the restaurant with a description in a different tab or device, it will overwrite your second submission with your first one, potentially without even warning you.
- A solution for invalid forms: always redirect on POST, no matter what, successful or not. For invalid forms, save the form to the user's session in some way and the redirected GET view should rehydrate it and display it to the user. This isn't the most elegant solution I can think of, but it's the only one I can think of that doesn't have obvious drawbacks.
- You can probably get away with just rendering and not redirecting on POST if (1) the POST "fails", by which I mean that the database isn't mutated and there aren't any side effects, and (2) you are very sure that the POST can't suddenly succeed in the future due to actions taken outside of the specific user intention associated with the failing POST request. This can be tricky and not totally obvious!
- For example, you POST to an endpoint that has side effects like sending emails, but the POST fails because some form in another part of the app is invalid. The app helpfully renders the form in its invalid state and tells you to fix it. You update that form to make it valid and submit it so its now in a valid state. But you haven't yet decided to re-trigger the side effect from the initial POST. You click the back button, and accidentally trigger it! The action of updating the form is different than the action of the user to trigger the POST that has the side effect that sends the email.
- If, on the other hand, the actions are one in the same -- i.e., it's the valid submission of the form that triggers the side effect -- you can probably get away without the PRG pattern.
2021
- To install Office 365 on Linux with Crossover Office, you have to download the "offline installer" via the My Account page on account.microsoft.com. But if you're on Linux, it won't let you download it. It keeps telling you to refresh the page. You can get around this by spoofing your User Agent in your browser with a browser extension to make it look like you're on Microsoft Windows. Once you have the .iso file, mount it. The Crossover installer should then be able to see it and install from it. I got to the end of the install and it wouldn't work, so I abandoned it. Will use LibreOffice for now.
How a Django Form chooses what to display in its fields.
- In
ModelForm
,initial
is constructed by taking the instances' dictionarified attributes and overriding them with theinitial
provided. - If you pass
data
, on cleaning, it puts the field cleaned data inform.cleaned_data
, but this is actually irrelevant for form rendering purposes, butModelForm.save
will save the cleaned_data to the instances' fields. - Iterating over a form's fields actually yields a
BoundField
instance because of howField.__getitem__
is written. I thinkBoundField
is kind of a misnomer and it should really be namedBindableField
since it is yielded even if the form is not bound with any data. - Rendering a form field renders a
BoundField.data
if theForm
is bound, otherwise it rendersBoundField.initial
. - The key is where
BoundField
getsinitial
anddata
.BoundField
getsinitial
by reaching back into theform
instance (which it gets in its__init__
).BoundField
getsdata
by reaching back into theform
instance in the following way:BoundField
passes a copy of the widget to a function on theform
, which then reaches into the widget with the form'sdata
to pull out the data value sitting on the widget.
- This whole scheme works because when you iterate into a
form
, it instantiatesBoundField
instances with 3 arguments: theform
instance itself, thefield
instance, and the name of variable thefield
instance is assigned to in the model.- E.g.,
ice_cream = forms.CharField()
would provide the parentform
, the instance ofCharField()
and the stringice_cream
.
- E.g.,
- That
BoundField
instance -- and even theField
instances -- don't actually know anything about the data represented by theField
orBoundField
.BoundField
just contains some functions for reaching back into theForm
to see if any data is sitting on a widget or ininitial
, depending on if theform
is bound or not.
2020
- There appears to be a bug in Google Analytics 4 where linked analytics.js properties don't properly receive pageview events if your GA tracking ID is the GA4 id. The flip side works fine though: If your GA tracking ID is the
UA-XXX
-type ID, linked GA 4 properties receive pageview events fine. - When you are trying to JOIN models in Django that are not related via the ORM, you have to use a
Subquery
andOuterRef
and can only join one column at a time. #django - When telling a story, a useful tactic is to describe "how did I feel then?" and "how do I feel now?" #storytelling
- When telling a story, give us a quirk of each character in a story. For example, if I were telling a story about my friend Jared, I would comment on his fascination with law firm bathrooms. #storytelling
usePaginatedQuery
is the same asuseQuery
butstatus
is alwayssuccess
after the first load andresolvedData
andlatestData
take the place ofdata
. #reactjs- A ManytoMany relationship in Django will not allow duplicate relations. I.e., the same exact relation can't appear twice in the join table. If you use
Model.add()
to add the same relation twice, it will just ignore it and not duplicate the relation. #django - In Django Rest Framework,
rest_framework.exceptions.ValidationError === rest_framework.serializers.ValidationError
. If you raise the error in a serializer, you get the non_field_error/field formulation. If you raise it outside, you just get whatever you raised. According to inline comments in DRF, you should actually always referenceserializers.ValidationError
to avoid confusion with the django named ValidationError. #django - Django Rest Framework Serializers
Serializer(data=XXX)
used to run validation on writable fields and pass a.validated_data
to.create()
of those writable fields. That same.validated_data
gets run back through to_representation to get a.data
to return back to the browser.Serializer(instance)
does not validate and should be used when (1) your fetching an instance from the db and returning it serialized or (2) you just need to normalize an object into a different representation (e.g., convertingaccount_ids
from a pure python object to account slugs).- Passing both instance and data to Serializer is for PUT/update operations.
.validated_data
is generated fromto_internal_value
..data
is generated fromto_representation
.