Create Your Own Models: A Framework

I get a lot of these questions:

“How do I structure my data models to do this very specific thing….” [Create this Hacker News Clone, Reddit Clone, Twitter clone, my new awesome startup, this thing at work…]

This is not a very good question.

The better question very might be:

“Is there a framework I can use to structure the models for my app? (Or any app I make in the future?)”

That is a better question.

A lot of people want an answer to their questions for the current thing they are working on. It seems like nobody is asking the question that will help them with the next project and the next and the next…

So, is there a framework that you can use for the model structure of every application that you ever create from here on out?

Framework for building model structures

Here are the steps you need to complete:

  1. Plan — yes! there are a little bit of planning, and we go into that here in a bit.
  2. Implement — Use the planning to implement your models. And if that seems like it’s going to be painful for your to do, I will give you some simple heuristics to follow to make this simpler.
  3. Test — I’m not even talking about unittestting, I’m talking about using the Django Shell to try out some queries to see it makes sense to your and what you’re trying to do.

Alright, let’s get started.

Plan — How to make sure you’re on the right path

First thing you should do is build out the Nouns that you need in your application. Your Models are basically the Nouns that you can Create, Update, Delete etc.

Once you have your nouns, write them all down and write boxes around them.

boxes

Now, you should have a piece of paper with a bunch of boxes and inside the boxes, should be a noun that has something to do with your application.

Next, you need to create your model relationships. The way you do this is with lines, 1 and *. So, what does this mean? Let’s look at the models again.

There is a Book, a Author, Review, and Customer. So, take some time to think about the relationships.

What I like to do is first create the lines where each Noun is connected. Let’s see what I was thinking when I did this:

  • A Book has an Author
  • A Book has 0 or more Review’s
  • A Book has 0 or more Customer’s
  • Customer’s can write Review’s

So, the lines I created based on my thinking above looks something like this:

boxes

You might notice that my thinking, is pictured the same way in the picture. You can notice that I wrote a word in the middle of the line that corresponds to my thinking.

For example:

A Book has an Author

The word between the line is “has”. This keeps my thinking straight. I’m basically asking myself, what is the evidence that this is correct? The answer is, “I know a book has an author”. Make sense?

We are not done, we need to create an additional relationship between these models.

The way we do this, is using 1 and *.

  • 1 represents only ONE instance of this object.
  • * represents multiple instances of this object.

Let’s look to see what I mean by this:

boxes (Oops, the Customer to Review is not correct should be 1 - * — Stay with me!)

The relationship between Book and Author has * on both sides.

The relationship between Book and Review has 1 near Book and * near Review.

What does this represent? This might be a bit hard to wrap your head around but you are just asking yourself questions about relationships and putting a 1 or * on the correct Model.


Let’s see what this looks like:

  • 1 Book has Many Authors? YES, that’s true! Now, reverse the question…
  • 1 Author can author Many Books? YES! That’s also true.

If both questions are True, put a * on both ends.


Let’s try another one:

  • 1 Book has many Reviews? YES! Go to Amazon and go to your favorite book, there are multiple Reviews. Let’s try reversing the question…
  • 1 Review has many Books? No… That’s not true. Each book is different, so each book has different reviews (or at least should).

If only 1 question is true, put a 1 on the object where the “1 [object]” has the Truthy answer


In this case, “1 Book” is the true one, so you put the 1 near the book and the Many (*) by the Review.

There could be times, when NEITHER questions are true. What do you do then? You change the question from: “1 Book has many [insert object]” to “1 Book has 1 [insert object]“. (Change the “many” to “1” instead.)


Let’s look at an example with User and Profile (this example is not on my index card)

  • 1 User has Many Profiles? NO, that’s not true… what about reverse?
  • 1 Profile can be shared with Many Users? NO… that’s not true either… Let’s change the question:
  • 1 User has 1 Profile? YES! that’s true!… should we reverse the question? Let’s do it…
  • 1 Profile can be associated with 1 User? YES! That’s true too!

If you change the question to 1 [object] has 1 [object] both sides of the relationship should have a 1


Keep asking the questions for all the boxes where there is a line between them. And if you do the questions, you should get the image below:

boxes (Oops, the Customer to Review is not correct should be 1 - * — Stay with me!)

Implement — Put that plan into action!

The reason why we have an index card or piece of paper and lines and a bunch of * and 1 all over this model diagram is because it makes implementing this data model SO MUCH EASIER!

Here are the steps to Implementation:

  1. Determine what Model is the most important in this diagram
  2. Start Building this Model
  3. Anytime you see a Relationship with a * on both sides, make it a ManyToManyField (put the ManyToManyField on the most important Model)
  4. Anytime you see a Relationship with a * on one side and a 1 on the other side, put a ForeignKey fields on the side where the * is.
  5. Anytime you see a Relationships with 1 on both sides, make it a OneToOneField (put the OneToOneField on the most important Model).
  6. Repeat with all the other Models.

For #1, the most important Model is going to be dependant on your application. The application that my model data is modeling, is a listing of Books like Amazon.

But, your application might be a listing of Authors and therefore, your most important Model will be Author. Got it?

I’m going to follow all the instructions and show you what my models.py might look like. Remember, the first thing you do, is build the relationships. I am not worried about the data that fits into the Models at this point. We are just worrying about Relationships between models.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
from django.db import models

class Customer(models.Model):
  	pass

class Review(models.Model):
  	book = models.ForeignKey('Book', on_delete=models.CASCADE)
    customers = models.ManyToManyField(Customer)
  
class Author(models.Model):
  	pass

class Book(models.Model):
    customers = models.ManyToManyField(Customer)
    authors = models.ManyToManyField(Author)

I could have put the ManyToManyField on Customer instead of Review but at this point it doesn’t matter. You should get a structure finished and go to the Test step to make sure it’s doing what you want it to do. If you find that it would be better to put the ManyToManyField on the Customer instead of Review, you can always change your structure after you test.

Now, anywhere there is a pass like for Author and Customer. Let’s just add a field, like name. Just so that we can create those objects when we test.

(NOTE: Better yet, if this was your application, put in 1 field that you plan on adding to it.)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
from django.db import models

class Customer(models.Model):
  	name = models.CharField(max_length=50)

class Review(models.Model):
  	book = models.ForeignKey('Book', on_delete=models.CASCADE)
    customers = models.ManyToManyField(Customer)
  
class Author(models.Model):
  	name = models.CharField(max_length=50)

class Book(models.Model):
    customers = models.ManyToManyField(Customer)
    authors = models.ManyToManyField(Author)

So, we have a simple model structure. Let’s test it!

Test — Make sure that implement works for you

We get to the testing. If you want to create a throw-away Django project just to play around with this model structure, you can. One idea that I like to do, is create the actual Django Project and start out with the db.sqlite3 database and run some queries with my new model structure.

Once I like it and it works for what I’m trying to do, then, I’ll delete the db.sqlite3 database and plugin a Postgres database or similar.

So, let’s get started, let’s see what this looks like when we use this new structure.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
$ python manage.py shell
>>> from myapp.models import Book, Review, Customer, Author
>>> a = Author(name="John")
>>> a.save()
>>> c = Customer(name="Chris")
>>> c.save()
>>> b = Book()
>>> b.save()
>>> b.customers.add(c)
>>> b.authors.add(a)
>>> b.authors.all()
<QuerySet [<Author: Author object (1)>]>
>>> b.customers.all()
<QuerySet [<Customer: Customer object (1)>]>
>>> r = Review(book=b)
>>> r.save()
>>> r = Review(book=b)
>>> r.save()
>>> b.review_set.all()
<QuerySet [<Review: Review object (1)>, <Review: Review object (2)>]>
>>> 

And you can just keep going. Testing out the models and get a feeling for how to create, delete, and update your data.

You can even take some of those and write them down for later. You might need to use those exact same queries to build up your Views when you’re ready to start coding for real.

Conclusion

I really hope this gives you a really good framework and some heuristics to get started created your own Model Structure now and into the future with all your future projects.

Comment in the comment section below and tell me what you’re working on and if this will help you. I read every comment!!

comments powered by Disqus