There is a grand myth about requirements–if you write them down, users will get exactly what they want. That’s not true. At best, users will get exactly what was written down, which may or may not be anything like what they really want.
– Mike Cohn, “Succeeding with Agile”
Author: Jack Slingerland
Founder of Kernl.us. Working and living in Raleigh, NC. I manage teams of software engineers and work in Python, Django, TypeScript, Node.js, React+Redux, Angular, and PHP. I enjoy hanging out with my wife and kids, lifting weights, and PC gaming in my free time.
One of the more useful features of the Django framework is it’s extensive signaling capabilities. The ORM throws off a handful of signals every time a model is initialized, modified, saved, or deleted. They include:
- pre_init
- post_init
- pre_save
- post_save
- pre_delete
- post_delete
- m2m_changed
- class_prepared
I tend to use the post_save signal fairly often as a good way to get around overriding the default save method on models. Recently though I ran into an issue where I was hitting the “maximum recursion depth exceeded” error when I was saving the current model from within the post_save signal. If you think about it, that makes a lot of sense. You save once, then save again in the signal and then it triggers the signal again. BOOM, infinite loop.
To get around the saving within a post_save signal problem, you just need to disconnect the post_save signal before you call save. After save, you can re-connect it.
from django.db.models import signals signals.post_save.disconnect(some_method, sender=SomeModel) some_instance.save() signals.post_save.connect(some_method, sender=SomeModel) |
I recently needed to add a large number of users to a permission group in Django. I had a hard time finding a way to do this in the documentation, so I thought I’d share my solution.
from django.contrib.auth.models import Group, User g = Group.objects.get(name='My Group Name') users = User.objects.all() for u in users: g.user_set.add(u) |
Easy as pie. I originally attempted to do this from the perspective of a user, but as it turns out, doing it from the group perspective is much easier.
Django’s ORM is top notch. It provides facilities to do almost anything you can think of with a database, and if it doesn’t, it still lets you execute arbitrary SQL to your hearts content. I’ve been developing Django for close to 2 years now, and still discover facets of it that I never knew existed. For instance, I had a need to duplicate a row in a table, but give it a different primary key. After a quick Google search, I discovered that Django allows you to do the following to copy instantiated model objects.
my_model = MyModel.objects.get(pk=4) my_model.id = None my_model.save() |
There are a few caveats with doing things this way.
- Unique Constraints – If you have any unique constraints on the model, the save will not pass validation and fail.
- ManyToMany Fields – If you need new copies of ManyToMany field values, you’ll need to handle this yourself.
That being said, in many cases duplicating a model instance is as easy as changing it’s ID and saving.
Revisiting an old Python + Django project made me realize that I needed to upgrade it’s PIP packages. Unfortunately, PIP doesn’t provide a way out of the box to update all of your installed packages at once. To update all of the PIP packages at once, use the following script.
import pip from subprocess import call for dist in pip.get_installed_distributions(): call("pip install --upgrade " + dist.project_name, shell=True) |
For more detail, check out this question on Stack Overflow.
28 Questions
Over the past few years I’ve tried my hand at launching a couple of different start ups. Over this time period, I’ve collected a set of questions from many different sources (HN, YCombinator, TechStars, etc) that I ask myself before proceeding. They help be decided if this is a real or manufactured problem, if it can be profitable, and if people will buy what I’m selling. My latest project idea is the only idea I’ve had that passes all of these questions to my satisfaction. How do yours hold up?
- What are you going to build?
- What is the actual problem?
- How will you sell your product/service?
- What are some potential obstacles?
- What are some existing options that solve this problem? How are you different?
- Who needs what you’re making?
- How do you know that they need it?
- How is the problem being solved now? Is it being solved now?
- Why isn’t this being done your way already?
- How will customers find out about you?
- What resistance will they have to trying your product?
- What are some key things about your project that outsiders don’t understand?
- Who will your first paying customer be?
- How might you expand if your initial idea succeeds?
- Why did you choose to work on this idea?
- Six months from now, what will be you biggest problem?
- What are the hard parts of this idea?
- Who would you hire/add to your team?
- What is the next step in product evolution?
- How does your product work?
- How big is the opportunity? [market]
- How do you know customers need what you’re making?
- What domain expertise do you have? Why should you be the one to do this?
- What part of your project will you build first? (could be business connections, hardware, software, etc)
- How much money could you make per year?
- How will you make money?
- What have you built in the past?
- How would you spend $5,000, how would you use it?
I just started a new project using the latest release candidate of Django 1.5. One thing that I needed was the local flavor add-on so I could get a list of US states. This functionality used to be rolled into the main codebase, but it was rightfully removed in Django 1.5. To install the US local flavor package, just use PIP.
pip install https://github.com/django/django-localflavor-us/zipball/master
Now you should be able to import anything you need from the package in the usual manner, except from the new package instead of the old one.
from django_localflavor_us.us_states import STATE_CHOICES |
For more information, check out the How To Migrate section of the local flavor docs on the Django documentation site.
I’m currently working on a project where I have a model named ‘Instructor’ with a few fields:
- first_name – CharField
- last_name – CharField
- departments – Many-toMany
I found out at some point that I’d really like a field called “full_name”, which is “first_name” and “last_name” concatenated together. I didn’t want to have to fill the field in though, I wanted it to happen automatically. To accomplish this, I extended Django’s Model.save() method after I added the ‘full_name’ column to my model.
class Instructor(models.Model): first_name = models.CharField(max_length=150) last_name = models.CharField(max_length=150) departments = models.ManyToManyField(Department) full_name = models.CharField(max_length=180, blank=True) def save( self, *args, **kw ): self.full_name = '{0} {1}'.format( self.first_name, self.last_name ) super( Instructor, self ).save( *args, **kw ) |
And that’s it! Now every time I create a new instructor with ‘first_name’ and ‘last_name’, it automatically populates the ‘full_name’ field for me.