I was curious about ** Django REST framework ** and ** Vue.js **, so I tried to combine them.
Instead of using Django's html template function, return the HTML data as a static file and display a list of information obtained from the browser via Rest API with Vue.js. (DB used SQLite3, sample data used the number of stocks of my article.)
Python is ** Python 3.5.1 ** The package is below
# pip3 freeze
Django==1.10.5
django-filter==1.0.1
djangorestframework==3.5.3
Vue.js and axios are fetched by CDN, and the version at the time of posting (2017/1/30) is as follows.
The usual.
# django-admin startproject qiitalist
# cd qiitalist/
# python manage.py startapp stocks
The composition looks like this. (1)-(6) We will look at the implementation individually. (▲ = File not used this time)
qiitalist
│ fixture.json # ② Model added │ manage.py │ ├─qiitalist │ │ settings.py # ① Add settings │ │ urls.py # ⑤ URL setting added │ │ wsgi.py # ▲ │ │ init.py │ │ │ └─ static # ⑥ Static file creation │ vue_grid.css │ vue_grid.html │ vue_grid.js │ └─stocks │ admin.py # ▲ │ apps.py # ▲ │ models.py # ② Add model │ tests.py # ▲ │ serializer.py ③ Add serializer │ urls.py # ⑤ URL setting added │ views.py # ④ View added │ init.py │ └─migrations
Added the application to be implemented and the setting of REST Framework.
settings.py
#Excerpt only for the addition
#Add app
INSTALLED_APPS += [
'stocks',
'rest_framework',
]
#REST API settings (filters, paging)
REST_FRAMEWORK = {
'DEFAULT_FILTER_BACKENDS': ('rest_framework.filters.DjangoFilterBackend',),
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination',
'PAGE_SIZE': 5
}
# views.Define the path used by py
PACKAGE_ROOT = os.path.abspath(os.path.dirname(__file__))
STATICFILES_DIRS = (os.path.join(PACKAGE_ROOT, 'static'),)
Prepare the data model to be published by REST API and the initial data (fixture).
models.py
from django.db import models
class Stock(models.Model):
class Meta:
db_table = "stock"
id = models.AutoField(primary_key=True)
title = models.TextField()
stock_count = models.IntegerField()
fixture.json
[
{
"model": "stocks.stock",
"pk": 1,
"fields": {
"title": "I started machine learning with Python(I also started posting to Qiita)Data preparation",
"stock_count": 29
}
},
{
"model": "stocks.stock",
"pk": 2,
"fields": {
"title": "Ramen map creation with Scrapy and Django",
"stock_count": 23
}
},
{
"model": "stocks.stock",
"pk": 3,
"fields": {
"title": "I started machine learning with Python Data preprocessing",
"stock_count": 22
}
},
{
"model": "stocks.stock",
"pk": 4,
"fields": {
"title": "RabbitMQ message notification app in Python with Growl ~ with Raspberry Pi and Julius ~",
"stock_count": 3
}
}
]
Added the definition of Serialzier to serialize the model.
serializers.py
from rest_framework import serializers
from stocks.models import Stock
class StockSerializer(serializers.ModelSerializer):
class Meta:
model = Stock
fields = ("id", "title", 'stock_count')
Added View definition.
views.py
import os
from django.conf import settings
from django.http.response import HttpResponse
from rest_framework import viewsets
from stocks.models import Stock
from stocks.serializer import StockSerializer
#View that returns a static file
def index(_):
#If you process it as a Django template with render etc., "{{}}Is Vue.It disappears before passing to js.
#I couldn't find a good solution, so I avoided it by opening and throwing the file under static.
html = open(
os.path.join(settings.STATICFILES_DIRS[0], "vue_grid.html")).read()
return HttpResponse(html)
#Rest API viewssets
class StockViewSet(viewsets.ModelViewSet):
queryset = Stock.objects.all()
serializer_class = StockSerializer
#Specify fields that can be used in API filters
filter_fields = ("id", "title", 'stock_count')
Divided by parent (qiitalist) and child (stocks).
urls.py(qiitalist)
from django.conf.urls import include, url
from stocks.urls import urlpatterns as qiitalist_url
urlpatterns = [
url(r'^qiita/', include(qiitalist_url)),
]
urls.py(stocks)
from django.conf.urls import include, url
from rest_framework import routers
from stocks.views import StockViewSet, index
router = routers.DefaultRouter()
router.register(r'stock', StockViewSet)
urlpatterns = [
# qiita/api/stock/
url(r'api/', include(router.urls)),
# qiita/
url(r'', index, name='index'),
]
Imitate the grid component example of https://jp.vuejs.org/v2/examples/grid-component.html </ font>.
vue_grid.css
/*Omitted because it is a copy*/
vue_grid.js
//The upper component mounting part is a copy, so it is omitted.
//Modified to get the specified data from Rest API only for the new Vue part
var demo = new Vue({
el: '#demo',
data: {
searchQuery: '',
gridColumns: ["id", "title", 'stock_count'], //Change
gridData: [] //Data is fetched by API, so delete it
},
created: function(){ //Take it from the Rest API and add it to gridData.
var self = this //It seems to be necessary in terms of scope (this.gridData.An error will occur with push. )
axios.get('/qiita/api/stock/')
.then(function(response){
for(var i = 0; i < response.data.results.length; i++){
self.gridData.push(response.data.results[i]);
}
});
}
})
vue_grid.html
<!-- vue_grid.The html is slightly modified according to the display items.-->
<!DOCTYPE html>
<html>
<head>
<title>Welcome to Vue</title>
<!--CSS loading-->
<link rel="stylesheet" type="text/css" href="/static/vue_grid.css">
<!-- JS(CDN)Read-->
<!-- Vue.js -->
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<!-- Axios(vue-Instead of resource)-->
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
<script type="text/x-template" id="grid-template">
<table>
<thead>
<tr>
<th v-for="key in columns"
@click="sortBy(key)"
:class="{ active: sortKey == key }">
{{ key | capitalize }}
<span class="arrow" :class="sortOrders[key] > 0 ? 'asc' : 'dsc'">
</span>
</th>
</tr>
</thead>
<tbody>
<tr v-for="entry in filteredData">
<td v-for="key in columns">
{{entry[key]}}
</td>
</tr>
</tbody>
</table>
</script>
<div id="demo">
<form id="search">
Search <input name="query" v-model="searchQuery">
</form>
<demo-grid
:data="gridData"
:columns="gridColumns"
:filter-key="searchQuery">
</demo-grid>
</div>
</body>
<!--JS read-->
<script src="/static/vue_grid.js"></script>
</html>
Create a DB.
# python manage.py makemigrations
# python manage.py migrate
Input initial data.
# python manage.py loaddata fixture.json
Start the server.
# python manage.py runserver
Access the API console http: // localhost: 8000 / qiita / api /
from your browser.
Get a list of stocks at http: // localhost: 8000 / qiita / api / stock /
.
(Up to 5 items can be acquired and displayed in the paging setting of ①. * Note: There is no particular meaning because the registered stock is 4 items.)
Access http: // localhost: 8000 / qiita /
and try to display it.
For the time being, I was able to make a place where I could move, so I started to get motivated to study. Vue.js is almost a sutra copy, but I felt it was easier to use (intuitive) than AngularJS and React.js. It is fatal that the number of data handled is small. It's not interesting, so let's increase the number of articles ...
-Implement API at explosive speed using Django REST Framework -Examples of grid components -Generate data using Django's Fixture -Axios is recommended when doing Ajax with Vue. -A JavaScript framework that makes it easy to start with Vue.js
Recommended Posts