Django 3, MySQL REST API Angular 10 CRUD Example

Here in this tutorial I am going to explain how to integrate Django REST API with Angular framework. CRUD stands for Create, Read, Update and Delete operations which will be performed from UI (User Interface) using Angular framework and on server side Django framework and MySQL server are used.

The Angular framework will be used in this example for representing the UI (User Interface) where end users will perform CRUD operations.

Prerequisites

Angular 10, DJango 3, npm 6.14.6, node v12.18.3, MySQL 8.0.17, Django 3 REST API, MySQL CRUD Example, Create new Angular Project

Project Setup

Create a new project in Angular using the command ng new <project name>. The name of the project for this example is angular-django-rest-api-crud.

I am also creating four different components for performing CRUD operations using the following commands.

Having separate components for each operation will give you more control over managing the source code and project structure. The respective directories and files will be created accordingly under src/app folder.

ng g c user-list
ng g c user-add
ng g c user-edit
ng g c user-detail

If you open src/app/app.module.ts file, you will see entries for all new components are also added to this file.

Routing

Angular routing determines the navigation for your application and it is recommended to have in your application for a user friendly page navigation.

For example, you want to create new user, so you will click on a link – Add New User. You may update existing user information, so you may click on Edit link and so on.

Edit file src/app/app-routing.module.ts to have below source code.

I am importing the required modules and components and at the end I exported the class for using into different components.

I have defined paths for routing, such as, when you hit the root URL in the browser, it will redirect to the /users path, or when you want to perform other operations – create, update, delete or fetch detail for a particular user information.

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';

import { UserListComponent } from './user-list/user-list.component';
import { UserAddComponent } from './user-add/user-add.component';
import { UserEditComponent } from './user-edit/user-edit.component';
import { UserDetailComponent } from './user-detail/user-detail.component';

const routes: Routes = [
  { path: '', redirectTo: '/users', pathMatch: 'full' },
  { path: 'users', component: UserListComponent },
  { path: 'user/:id/detail', component: UserDetailComponent },
  { path: 'user/:id/edit', component: UserEditComponent },
  { path: 'user/add', component: UserAddComponent }
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }

Additional Modules

Open your src/app/app.module.ts and add few required modules for the application, such as, FormsModuleHttpClientModule and AppRoutingModule. Other components and modules are added automatically into this file.

FormsModule is required to define your HTML form, HttpClientModule is required for preforming data exchange over HTTP protocol and AppRoutingModule is required for defining routes used for navigation in the application.

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { FormsModule }    from '@angular/forms';
import { HttpClientModule }    from '@angular/common/http';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { UserListComponent } from './user-list/user-list.component';
import { UserAddComponent } from './user-add/user-add.component';
import { UserEditComponent } from './user-edit/user-edit.component';
import { UserDetailComponent } from './user-detail/user-detail.component';

@NgModule({
  declarations: [
    AppComponent,
    UserListComponent,
    UserAddComponent,
    UserEditComponent,
    UserDetailComponent
  ],
  imports: [
    FormsModule,
    BrowserModule,
    AppRoutingModule,
	HttpClientModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Redirect to /users

If you now try to open your application by executing command ng serve –open in command line tool you won’t be redirected to the http://localhost:4200/users though you have redirected root path to /users in src/app/app-routing.module.ts file.

You will see the path in browser as http://localhost:4200/users but you will see the output on the browser from src/app/app.component.html file.

Therefore, remove everything from app.component.html file and put only <router-outlet></router-outlet> in this file and now save the file.

Now if you open the application by executing command ng serve --open, then you should see the output as user-list works! on home page.

Model Class

The below model class maps the JSON key/value pairs response from the REST API.

export class User {
  id?: string;
  name: string;
  email: string;
  phone: string;
  address: string;
}

Here in the above class, notice I have put ? after id field to indicate optional value for id field during adding new user information because the id field is auto-generated value.

Service Class

It is a good idea to create a central class that will be used by all modules or components in Angular to interact with server either to fetch the data or send the data to server.

Create below service class – src/app/user.service.ts – that will list down CRUD operation methods. In the below class you have defined methods for CRUD operations for a user.

So you give user options through your UI (User Interface) to add new user, update existing user, fetching exiting users/user and deleting existing user.

Create UserService class using the following command on your project’s root directory. This will create the required file user.service.ts file under src/app folder.

import { Injectable } from '@angular/core';

import { HttpClient, HttpHeaders } from '@angular/common/http';

import { Observable, of } from 'rxjs';
import { catchError, map, tap } from 'rxjs/operators';

import { User } from './user';

@Injectable({
  providedIn: 'root'
})
export class UserService {

  private userUrl = 'http://localhost:8000/users';  // Base URL to REST API
  
  constructor(private http: HttpClient) { }
  
  /** GET users from the server */
  getUsers(): Observable<User[]> {
    return this.http.get<User[]>(this.userUrl);
  }
  
  /** GET user by id. Will 404 if id not found */
  getUser(id: string): Observable<any> {
    const url = `${this.userUrl}/${id}`;
    return this.http.get<User>(url);
  }
  
  /** POST: add a new user to the server */
  addUser(user: User) {
	//console.log(user);
    return this.http.post(this.userUrl, user, {headers: new HttpHeaders({ 'Content-Type': 'application/json' }), responseType: 'text' as 'json'});
  }
  
  /** PUT: update the user on the server */
  updateUser(user: User): Observable<any> {
    return this.http.put(this.userUrl, user, {headers: new HttpHeaders({ 'Content-Type': 'application/json' }), responseType: 'text' as 'json'});
  }
  
  /** DELETE: delete the user from the server */
  deleteUser(user: User) {
	  if (confirm("Are you sure to delete?")) {
		const url = `${this.userUrl}`;
		console.log(user);
		const options = {
		  headers: new HttpHeaders({
			'Content-Type': 'application/json',
		  }),
			body: user,
		  responseType: 'text' as 'json'
		};
		return this.http.delete(url + '/' + user.id, options);
	  }
	  return of({});
  }

}

Retrieve All Users

Here I am going to tell you how to write code for fetching all users from the server side REST API. Modify the file src/app/user-list/user-list.component.ts to write the required code.

ngOnInit() hook initializes the directive/component after Angular first displays the data-bound properties and sets the directive/component’s input properties.

I fetch all products data using getUsers() method and populate the users[] array to display data on the HTML page.

I also define delete() method to delete a particular user from a list of users shown on HTML page.

import { Component, OnInit } from '@angular/core';

import { ActivatedRoute } from '@angular/router';

import { User } from '../user';
import { UserService } from '../user.service';

@Component({
  selector: 'app-user-list',
  templateUrl: './user-list.component.html',
  styleUrls: ['./user-list.component.css']
})
export class UserListComponent implements OnInit {

	users: User[] = [];
	
	constructor(private route: ActivatedRoute, private userService: UserService) { }
	
	ngOnInit() {
		this.getUsers();
	}
	
	getUsers(): void {
		this.userService.getUsers().subscribe(users => this.users = users);
	}
	
	delete(user: User): void {
		this.userService.deleteUser(user).subscribe(success=> {this.getUsers();});
	}

}

Now edit src/app/users-list/users-list.component.html file to show users information on page.

Here I am showing products information on HTML table and I have attached Detail, Edit and Delete operations for each row of the table data.

<h3>List of Users</h3>
<div>
	<a routerLink="/add">
		Add New User
	</a>
</div>
<table>
  <tr>
    <th>ID</th>
    <th>Name</th>
    <th>Email</th>
	<th>Phone</th>
	<th>Address</th>
	<th>Actions</th>
  </tr>
  <tr *ngFor="let user of users">
    <td>{{user.name}}</td>
    <td>{{user.email}}</td>
	<td>{{user.phone}}</td>
	<td>{{user.address}}</td>
	<td>
		<a routerLink="/user/{{user.id}}/detail">Detail</a>
		<a routerLink="/user/{{user.id}}/edit">Edit</a>
		<button title="delete user" (click)="delete(user)">X</button>
	</td>
  </tr>
</table>

I have also applied some basic styles to the HTML table for cell padding and spacing and border around the table and cells. Edit src/app/users-list/users-list.component.css to write the below code.

table, th, td {
  border: 1px solid black;
  border-collapse: collapse;
}
th, td {
  padding: 5px;
}

Single User Detail

Now I will show you how to retrieve single user information when you click on Detail link.

Open src/app/user-detail/user-detail.component.ts file and update the file with below source code.

Here in the below class I have fetched the user detail for a given product id as a path parameter. I have also provided goBack() function to give user option when he/she wants to go to the previous page.

import { Component, OnInit } from '@angular/core';

import { Location } from '@angular/common';

import { ActivatedRoute } from '@angular/router';

import { User } from '../user';
import { UserService } from '../user.service';

@Component({
  selector: 'app-user-detail',
  templateUrl: './user-detail.component.html',
  styleUrls: ['./user-detail.component.css']
})
export class UserDetailComponent implements OnInit {

	user: User;
	
	constructor(private route: ActivatedRoute, private userService: UserService, private location: Location) { }
	
	ngOnInit() {
		this.getUser();
	}
	
	getUser(): void {
		const id = this.route.snapshot.paramMap.get('id');
		this.userService.getUser(id).subscribe(user => this.user = user);
	}
	
	goBack(): void {
		this.location.back();
	}

}

Now open src/app/user-detail/user-detail.component.html file to update with below code. In the below code I am using uppercase to make the user name to be displayed in upper case letters.

<div *ngIf="user">
  <h2>{{user.name | uppercase}} Details</h2>
  <div>
    <p>
		Name: {{user.name}}
    </p>
	<p>
		Email: {{user.email}}
    </p>
	<p>
		Phone: {{user.phone}}
    </p>
	<p>
		Address: {{user.address}}
    </p>
  </div>
  <button (click)="goBack()">Go Back</button>
</div>

Update User Detail

Next functionality is how to update the existing user information into database through REST API from Angular. You need to click on the Edit link given on the list of users page.

Open the file src/app/user-edit/user-edit.component.ts and update as given below code.

I fetch the user details first and these values will be used to populate the input fields on HTML form so that user can understand what was the previous value for a field.

import { Component, OnInit, Input } from '@angular/core';

import { Location } from '@angular/common';
import { ActivatedRoute } from '@angular/router';

import { User } from '../user';
import { UserService } from '../user.service';

@Component({
  selector: 'app-user-edit',
  templateUrl: './user-edit.component.html',
  styleUrls: ['./user-edit.component.css']
})
export class UserEditComponent implements OnInit {

	@Input() user: User;
	
	constructor(private route: ActivatedRoute, private userService: UserService, private location: Location) { }
	
	ngOnInit() {
		this.getUser();
	}
	
	getUser(): void {
		const id = this.route.snapshot.paramMap.get('id');
		this.userService.getUser(id).subscribe(user => this.user = user);
	}
	
	save(): void {
		this.userService.updateUser(this.user).subscribe(success=> {this.goBack();});
	}
	
	goBack(): void {
		this.location.back();
	}

}

Now open src/app/user-edit/user-edit.component.html file to update as below source code.

<div *ngIf="user">
  <h2>{{user.name | uppercase}} Details</h2>
  <div>
    <p>
		Name: <input [(ngModel)]="user.name" placeholder="User Name">
    </p>
	<p>
		Email: <input [(ngModel)]="user.email" placeholder="User Email">
    </p>
	<p>
		Phone: <input [(ngModel)]="user.phone" placeholder="User Phone">
    </p>
	<p>
		Address: <input [(ngModel)]="user.address" placeholder="User Address">
    </p>
  </div>
  <button (click)="goBack()">Go Back</button>
  <button (click)="save()">Save</button>
</div>

Add User

Next I will implement functionality for adding new user information. Open the file src/app/user-add/user-add.component.ts and update with below code.

import { Component, OnInit, Input } from '@angular/core';

import { Location } from '@angular/common';

import { User } from '../user';
import { UserService } from '../user.service';

@Component({
  selector: 'app-user-add',
  templateUrl: './user-add.component.html',
  styleUrls: ['./user-add.component.css']
})
export class UserAddComponent implements OnInit {

	@Input() user: User = { name: '', email: '', phone: '', address: '' };
	
	constructor(private userService: UserService, private location: Location) { }
	
	ngOnInit() {
	}
	
	save(): void {
		this.userService.addUser(this.user).subscribe(() => this.goBack());
	}
	
	goBack(): void {
		this.location.back();
	}

}

Update the file src/app/user-add/user-add.component.html with the following source code.

<div>
  <h2>Add User Detail</h2>
  <div>
    <p>
		<label>Name:
			<input [(ngModel)]="user.name" placeholder="User Name"/>
		</label>
    </p>
	<p>
		<label>Email:
			<input [(ngModel)]="user.email" placeholder="User Email"/>
		</label>
    </p>
	<p>
		<label>Phone:
			<input [(ngModel)]="user.phone" placeholder="User Phone"/>
		</label>
    </p>
	<p>
		<label>Address:
			<input [(ngModel)]="user.address" placeholder="User Address"/>
		</label>
    </p>
  </div>
  <button (click)="goBack()">Go Back</button>
  <button (click)="save()">Save</button>
</div>

Delete User

Now if you click on the X link to delete a user. You will get confirmation alert and you need to click Yes for deletion.

CORS Issue

You will CORS issue while you are making calls from Angular to Django REST API. You need to install django-cors-headers using the command pip install django-cors-headers.

Nest step is to add it to your INSTALLED_APPS section:

INSTALLED_APPS = (
    ...
    'corsheaders',
    ...
)

You also need to add a middleware class to listen in on the response:

MIDDLEWARE_CLASSES = (
    ...
    
    'corsheaders.middleware.CorsMiddleware',
    'django.middleware.common.CommonMiddleware',
    ...
)

Testing the Application

Make sure you start both application from the command line tool. To start Django REST API you need to run the command manage.py server run on your project’s root directory. To start the Angular application you need to execute the command ng serve --open on your project’s root directory.

Now you can navigate through the application to perform the required activities.

Source Code

Download

Leave a Reply

Your email address will not be published. Required fields are marked *