Giter VIP home page Giter VIP logo

django-relationships's Introduction

General Assembly Logo

Django Relationships

Prerequisites

Objectives

By the end of this, developers should be able to:

  • Create one-to-many relationships with Django
  • Create many-to-many relationships with Django
  • Diagram relationships with ERDs

Preparation

  1. Fork and clone this repository into the django-env folder. FAQ
  2. Run pipenv shell inside the django-env folder to start up your virtual environment.
  3. Change into this repository's directory
  4. Create a new branch, training, for your work.
  5. Checkout to the training branch.
  6. Create a psql database with createdb "django-relationships"
  7. Generate and run migrations with python manage.py makemigrations and python manage.py migrate
  8. Run the server with python manage.py runserver

Building an API with Relationships

So far we have built some pretty basic applications with Django and Python, but now we are going to step it up and add in relationships to our models. To guide us, we have plenty of documentation about the API we are building, including user stories and ERDs (Entity Relationship Diagrams).

This repository has our V1 for a library and hospital app. Our docs show us that for V2 and V3, we are adding relationships to the different models.

Library V2

For V2 of our library app we need to add a new resource called Author and connect it to our Book resource. We will be building a one-to-many relationship where a Book has one Author and an Author can be referenced on many Book resources.

We can also think of this as an Author having multiple Books, which is how we diagram our ERD:

Author -|---< Book

Code-Along: One-to-Many Relationships

In order to get started we should work methodically and build out Author and make sure that resource works on it's own before connecting it to Book.

This repo has starter code for our Author resource, so right now we can CRUD on that resource successfully on it's own. This is good - going methodically and making sure Author works properly before adding a relationship will ultimately help us write better code.

Now, to connect Book and Author we have to look to the model first. This step will involve us adding a field to Book that references the Author resource.

author = models.ForeignKey('Author', related_name='books', on_delete=models.CASCADE)

Let's break this down:

  • models.ForeignKey: creates a foreign key reference to the 'Author' model. This will allow the author field on Book to point to a specific Author in our database.

    • Note: Foreign keys are used in databases to connect resources.
  • related_name: this is what we will be able to access on the other side of our relationship to see what books an author wrote.

  • on_delete=models.CASCADE: this will cause the books our author wrote to be deleted if the author is as well.

That's all we need to do to actually connect these resources!

We can ping our endpoint to create or update a book and send along an ID value for the author field. This will be that "foreign key" that points to the author who wrote the book.

However, we can't see the books that our authors wrote on the other side yet! The AuthorSerializer can be updated to reference the BookSerializer and then return the 'books' field. This should match the name on the Book model for the related_name.

class AuthorSerializer(serializers.ModelSerializer):
    books = BookSerializer(many=True)
    class Meta:
        model = Author
        fields = ('first_name', 'last_name', 'books')

Now, when an Author is returned from the database it will include a reference to that author's books.

Hospital V2

Lab: Doctor -|---< Patient

Time to work on our next app's V2: hospital.

The hospital docs lay out the details for two resources, Doctor and Patient. This repository has some starter code for an app hospital. Just like with the library's starter code, right now both Doctor and Patient support successful CRUD on their own.

Let's connect these two resources:

  1. Add ForeignKey field to Patient (see below section for how to migrate)
  2. Update DoctorSerializer to return patients

Providing Migration Defaults

When you add a new ForeignKey to Patient and then go to make the migration files, you'll find that Django will stop you with a prompt something like this:

$ python manage.py makemigrations
You are trying to add a non-nullable field 'primary_care_physician' to patient without a default; we can't do that (the database needs something to populate existing rows).
Please select a fix:
 1) Provide a one-off default now (will be set on all existing rows with a null value for this column)
 2) Quit, and let me add a default in models.py
Select an option:

As Django is explaining, the migration files won't generate without being provided some reasonable default for this new field that isn't allowed to be empty. This is because the migration files don't know the state of our database, so even if it's empty we still need to provide some value for any "existing rows" that don't already have this field.

We have two options - give Django a value to use for the existing rows in the database, or go back and modify the field in the models file. We'll choose the first one for right now.

Go ahead and type 1 to select this option and hit enter to continue.

Once you do this, you'll be moved on to a message like this:

Please enter the default value now, as valid Python
The datetime and django.utils.timezone modules are available, so you can do e.g. timezone.now
Type 'exit' to exit this prompt
>>>

You might recognize this - it's the Python REPL! The >>> prompt is telling us we can provide Python code to be interpreted. In this case, we want to provide a valid ID of some other row in the database. Assuming our database is empty, the safest value to provide would be 1, since that's the first ID that will ever exist.

Go ahead and type 1 to provide this value and hit enter to continue.

Django should spit you back out to the $ filesystem where you can run your migrations.

Note: Use your judgement when providing defaults. If your database isn't empty, there may be more to consider when picking a good default value.

Library V3

Code-Along: Many-to-Many Relationships

Time to see how we can add a many-to-many relationship to Book. Following the library documentation, Book should have a field that references who has or is borrowing that books from the library.

Book >---< Borrower

Borrowers can borrow many Books, and Books can be borrowed by many Borrowers!

As before, there is already a Borrower resource that supports full CRUD.

In the Book model we will add a new field to reference the Borrower model.

The borrowers field will be a ManyToManyField that will allow Book to store multiple borrowers.

This field might be empty at some point, and that's okay, so the blank=True option sets borrowers to be optional.

On the Borrower resource, the books borrowed will be referenced with the related_name which is loans.

In the BorrowerSerializer we can reference the BookSerializer to be able to see the books a borrower has borrowed.

SQL Join

Sometimes, we want a table to keep track of the connections between resources. For example, a resource called Loan could keep track of the ID of the Borrower and the Book in our many-to-many relationship. In relational databases, this kind of resource/table that "joins" the relationship between two other resources is known as a join table. This table could also hold information about the loan, like due date and checkout date.

We often talk about building a relationship that goes "through" this join table, which is why you'll often see the keyword through when building out join tables in different frameworks.

In Django we can accomplish a join table for our Book >---< Borrower relationship using the current Loan model. We will need to modify our models so that Loan can be used to represent this relationship.

  1. Add two ForeignKeys to Loan (join table)
    • This will keep track of the relationship to the Book and Borrower
    • Note: We can also give it any other fields we want, like a due date!
  2. Update the borrower field on Book to go "through" the Loan table
    • Use through to reference the Loan model
    • Use through_fields to reference the fields on Loan that should refer to the Borrower and Book IDs
  3. Add a LoanReadSerializer to display the book and borrower objects

Book -|--< Loan >--|- Borrower

We should be able to create a Loan and have that translate over to both Book and Borrower, based on the data in the Loan we created. We actually don't end up interacting with the Book or Borrower, but instead just CRUD on Loans.

Hospital V3

Time to plug in a many-to-many relationship between Doctor and their Patients. The hospital documentation shows us that we should have a resource called Appointment to join Doctor and Patient.

Lab: Join Patients and Doctors through Appointment

We need our Appointment before we can use it to "join" Doctor and Patient.

Use the current files for doctors and patients to help guide you.

  1. Create an Appointment model
  2. Add a new serializer class for Appointments
  3. Add CRUD views for Appointments
  4. Test CRUD on Appointment
  5. Connect Patient and Doctor using the Appointment table

Additional Resources

django-relationships's People

Contributors

timmshinbone avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.