In traditional Web application development, most programmers treat the browser as the dividing line between frontend and backend. The part in the browser that shows pages to users is called the frontend, and all the code running on the server that provides business logic and prepares data for the frontend is called the backend. Frontend-backend separation means frontend engineers and backend engineers agree on the data interaction APIs, then do development and testing in parallel. The backend only provides data and does not render the data to pages. The frontend gets data through HTTP requests and is responsible for rendering the data to pages. This work is done by JavaScript code in the browser.
Using frontend-backend separation has many benefits. Let us briefly talk about these benefits below:
- Improve development efficiency. After the frontend and backend are separated, frontend and backend code can be decoupled. As long as the frontend and backend agree on the interfaces and the interface parameters needed by the application, they can start parallel development without waiting for the other side to finish. In this case, frontend and backend engineers can each focus only on their own development work, which helps build a better team. Also, in the frontend-backend separation development model, even if requirements change, as long as the interface and data format do not change, backend developers do not need to change the code, and only the frontend needs to change.
- Improve code maintainability. After frontend-backend separation, the code of the application is no longer mixed frontend and backend code. There is only a calling dependency during runtime. In this way, maintaining the code becomes much easier and much more pleasant, and changing one part will not affect the whole body anymore. When your code becomes clear and clean, the readability and maintainability of the code both improve greatly.
- Support multiple terminals and service architecture. After frontend-backend separation, the same set of data interfaces can serve different terminals, which is more helpful for building multi-terminal applications. Also, because the interfaces provided by the backend can call each other through HTTP(S), it helps build service architecture, including microservices.
Next, let us rewrite the previous voting application in the frontend-backend separation way.
As we just said, in the frontend-backend separation development model, the backend needs to provide data APIs for the frontend. These APIs usually return data in JSON format. In a Django project, we can first turn objects into dictionaries, and then use Django's wrapped JsonResponse to return JSON format data to the browser. The specific way is shown below.
def show_subjects(request):
queryset = Subject.objects.all()
subjects = []
for subject in queryset:
subjects.append({
'no': subject.no,
'name': subject.name,
'intro': subject.intro,
'isHot': subject.is_hot
})
return JsonResponse(subjects, safe=False)In the code above, we loop through the QuerySet object returned by querying subjects, turn each subject's data into a dictionary, save the dictionaries in a list container named subjects, and finally use JsonResponse to serialize the list and return JSON format data to the browser. Because JsonResponse is serializing a list instead of a dictionary, we need to set the value of the safe parameter to False so it can serialize subjects; otherwise, a TypeError exception will happen.
You may already have found that writing your own code to turn an object into a dictionary is troublesome. If the object has many attributes, and some attributes are related to a more complex object, the situation becomes even worse. For this reason, we can use a third-party library named bpmappers to simplify turning objects into dictionaries. This third-party library also provides support for the Django framework.
Install the third-party library bpmappers.
pip install bpmappersWrite a mapper to implement object-to-dictionary conversion.
from bpmappers.djangomodel import ModelMapper
from poll2.models import Subject
class SubjectMapper(ModelMapper):
class Meta:
model = SubjectChange the view function.
def show_subjects(request):
queryset = Subject.objects.all()
subjects = []
for subject in queryset:
subjects.append(SubjectMapper(subject).as_dict())
return JsonResponse(subjects, safe=False)Configure URL mapping.
urlpatterns = [
path('api/subjects/', show_subjects),
]Then access this API, and you can get JSON format data like the following.
[
{
"no": 1,
"name": "Python Full Stack + Artificial Intelligence",
"intro": "Python is a computer programming language. It is an object-oriented dynamic typed language. At first it was designed for writing automation scripts (shell). As versions kept being updated and new language features were added, it has been used more and more in independent and large-scale project development.",
"is_hot": true
},
// content below is omitted here
]If we do not want to show the subject's creation time in the JSON data, we can exclude the create_date attribute in the mapper. If we want the key for whether it is a hot subject to be named isHot, and the default name is is_hot, we can also do that by changing the mapper. The specific way is shown below.
from bpmappers import RawField
from bpmappers.djangomodel import ModelMapper
from poll2.models import Subject
class SubjectMapper(ModelMapper):
isHot = RawField('is_hot')
class Meta:
model = Subject
exclude = ('is_hot', )Check the JSON data returned by the subject API again.
[
{
"no": 101,
"name": "Python Full Stack + Artificial Intelligence",
"intro": "Python is a computer programming language. It is an object-oriented dynamic typed language. At first it was designed for writing automation scripts (shell). As versions kept being updated and new language features were added, it has been used more and more in independent and large-scale project development.",
"isHot": true
},
// content below is omitted here
]For the detailed usage guide of bpmappers, please refer to its official documentation. This official documentation is written in Japanese, and you can use the browser's translation function to translate it into a language you know well.
Next, we use the frontend framework Vue.js to render the page. If you want to fully understand and learn Vue.js, it is recommended to read its official tutorial or search for a beginner tutorial for Vue.js, such as Vue.js Crash Course, on YouTube.
Rewrite the subjects.html page and use Vue.js to render the page.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Subject Information</title>
<style>
/* Cascading style sheet content is omitted here */
</style>
</head>
<body>
<div id="container">
<h1>All Subjects at Coding School</h1>
<hr>
<div id="main">
<dl v-for="subject in subjects">
<dt>
<a :href="'/static/html/teachers.html?sno=' + subject.no">
{{ subject.name }}
</a>
<img v-if="subject.is_hot" src="/static/images/hot-icon-small.png">
</dt>
<dd>{{ subject.intro }}</dd>
</dl>
</div>
</div>
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.11/vue.min.js"></script>
<script>
let app = new Vue({
el: '#main',
data: {
subjects: []
},
created() {
fetch('/api/subjects/')
.then(resp => resp.json())
.then(json => {
this.subjects = json
})
}
})
</script>
</body>
</html>Frontend-backend separation development needs to deploy frontend pages as static resources. When the project really goes online, we will separate static and dynamic parts for the whole Web application. Static resources are deployed through an Nginx or Apache server. The Python program that generates dynamic content is deployed on a uWSGI or Gunicorn server. Requests for dynamic content are routed by Nginx or Apache to the uWSGI or Gunicorn server.
During the development stage, we usually use Django's built-in test server. If you want to try frontend-backend separation, you can first put the static pages in the static resource directory created before. For the specific way, you can refer to the complete project code.