endpoint, frontend

This commit is contained in:
Bartosz Karwacki 2022-01-15 17:40:16 +01:00
parent 6a35148188
commit 8e29a715a5
12 changed files with 168 additions and 87 deletions

View File

@ -50,6 +50,7 @@ INSTALLED_APPS = [
"corsheaders",
"django_filters",
# apps
'cars'
]
MIDDLEWARE = [
@ -154,7 +155,4 @@ DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
# CORS
CORS_ALLOWED_ORIGINS = env(
"ALLOWED_ORIGINS",
default="http://localhost:3000",
).split()
CORS_ALLOW_ALL_ORIGINS = True

View File

@ -0,0 +1,27 @@
# Generated by Django 3.2.9 on 2022-01-15 15:58
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='Car',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('mark', models.CharField(max_length=150)),
('model', models.CharField(max_length=150)),
('mileage', models.PositiveIntegerField()),
('production_year', models.PositiveSmallIntegerField()),
('engine_capacity', models.DecimalField(decimal_places=2, max_digits=16)),
('combustion', models.DecimalField(decimal_places=2, max_digits=16)),
('price', models.DecimalField(decimal_places=2, max_digits=16)),
],
),
]

View File

@ -5,9 +5,9 @@ class Car(models.Model):
model = models.CharField(max_length=150)
mileage = models.PositiveIntegerField()
production_year = models.PositiveSmallIntegerField()
engine_capacity = models.DecimalField()
combustion = models.DecimalField()
price = models.DecimalField()
engine_capacity = models.DecimalField(decimal_places=2, max_digits=16)
combustion = models.DecimalField(decimal_places=2, max_digits=16)
price = models.DecimalField(decimal_places=2, max_digits=16)
def __str__(self) -> str:
return "Car"

View File

@ -1,12 +1,7 @@
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from .views import CarViews
# Create a router and register our viewsets with it.
router = DefaultRouter()
router.register(r'cars', CarViews.as_view(), name="cars")
from .views import CarList
# The API URLs are now determined automatically by the router.
urlpatterns = [
path('', include(router.urls)),
path('cars', CarList.as_view()),
]

25
backend/cars/utils.py Normal file
View File

@ -0,0 +1,25 @@
VALUES = ['low', 'mid', 'high']
def production_year_to_value(production_year):
return VALUES[["Dawno", "Średnio", "Niedawno"].index(production_year)]
def mileage_to_value(mileage):
return VALUES[["Niski", "Średni", "Duży"].index(mileage)]
def engine_capacity_to_value(engine_capacity):
return VALUES[["Mała", "Średnia", "Ogromna"].index(engine_capacity)]
def combustion_to_value(combustion):
return VALUES[["Niskie", "Średnie", "Wysokie"].index(combustion)]
def map_query_params(query_params):
values = {}
params = ['production_year', 'mileage', 'engine_capacity', 'combustion']
funcs = [production_year_to_value, mileage_to_value, engine_capacity_to_value, combustion_to_value]
for param, func in zip(params, funcs):
if (query_param := query_params.get(param)):
values[param] = func(query_param)
return values

View File

@ -1,19 +1,15 @@
from rest_framework.views import APIView
from .models import Car
from rest_framework import generics
from rest_framework.response import Response
class CarViews(APIView):
def get(self, request, format=None):
"""
Returns car list based on fuzzy_logic filters.
"""
combustion = request.query_params.get('combustion')
mileage = request.query_params.get('mileage')
production_year = request.query_params.get('production_year')
engine_capacity = request.query_params.get('engine_capacity')
print(combustion, mileage, production_year, engine_capacity)
cars = list(Car.objects.all())
return Response(cars)
from .models import Car
from .serializers import CarSerializer
from .utils import map_query_params
class CarList(generics.ListAPIView):
queryset = Car.objects.all()
serializer_class = CarSerializer
def list(self, request):
values = map_query_params(request.query_params)
queryset = self.get_queryset()
serializer = CarSerializer(queryset, many=True)
return Response(serializer.data)

View File

@ -1,3 +1,4 @@
SECRET_KEY=SECRET_KEY
DEBUG=1
ALLOWED_HOSTS=localhost 127.0.0.1
ALLOWED_ORIGINS=http://localhost:8080 http://127.0.01:8080

View File

@ -7,6 +7,7 @@
"": {
"version": "0.1.0",
"dependencies": {
"axios": "^0.24.0",
"core-js": "^3.6.5",
"vue": "^2.6.11",
"vue-router": "^3.2.0",
@ -2610,7 +2611,6 @@
"thread-loader": "^2.1.3",
"url-loader": "^2.2.0",
"vue-loader": "^15.9.2",
"vue-loader-v16": "npm:vue-loader@^16.1.0",
"vue-style-loader": "^4.1.2",
"webpack": "^4.0.0",
"webpack-bundle-analyzer": "^3.8.0",
@ -3394,6 +3394,14 @@
"integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==",
"dev": true
},
"node_modules/axios": {
"version": "0.24.0",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.24.0.tgz",
"integrity": "sha512-Q6cWsys88HoPgAaFAVUb0WpPk0O8iTeisR9IMqy9G8AbO4NlpVknrnQS03zzF9PGAWgO3cgletO3VjV/P7VztA==",
"dependencies": {
"follow-redirects": "^1.14.4"
}
},
"node_modules/babel-code-frame": {
"version": "6.26.0",
"resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz",
@ -3711,7 +3719,6 @@
"@types/node": "*",
"anymatch": "^3.0.3",
"fb-watchman": "^2.0.0",
"fsevents": "^2.3.2",
"graceful-fs": "^4.2.4",
"jest-regex-util": "^27.0.6",
"jest-serializer": "^27.0.6",
@ -4862,7 +4869,6 @@
"dependencies": {
"anymatch": "~3.1.2",
"braces": "~3.0.2",
"fsevents": "~2.3.2",
"glob-parent": "~5.1.2",
"is-binary-path": "~2.1.0",
"is-glob": "~4.0.1",
@ -7207,8 +7213,7 @@
"esprima": "^4.0.1",
"estraverse": "^4.2.0",
"esutils": "^2.0.2",
"optionator": "^0.8.1",
"source-map": "~0.6.1"
"optionator": "^0.8.1"
},
"bin": {
"escodegen": "bin/escodegen.js",
@ -8224,7 +8229,6 @@
"version": "1.14.5",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.5.tgz",
"integrity": "sha512-wtphSXy7d4/OR+MvIFbCVBDzZ5520qV8XfPklSN5QtxuMUJZ+b0Wnst1e1lCDocfzuCkHqj8k0FpZqO+UIaKNA==",
"dev": true,
"engines": {
"node": ">=4.0"
}
@ -10509,7 +10513,6 @@
"@jest/types": "^24.9.0",
"anymatch": "^2.0.0",
"fb-watchman": "^2.0.0",
"fsevents": "^1.2.7",
"graceful-fs": "^4.1.15",
"invariant": "^2.2.4",
"jest-serializer": "^24.9.0",
@ -18092,8 +18095,7 @@
"dependencies": {
"chokidar": "^3.4.1",
"graceful-fs": "^4.1.2",
"neo-async": "^2.5.0",
"watchpack-chokidar2": "^2.0.1"
"neo-async": "^2.5.0"
},
"optionalDependencies": {
"watchpack-chokidar2": "^2.0.1"
@ -18467,7 +18469,6 @@
"anymatch": "^2.0.0",
"async-each": "^1.0.1",
"braces": "^2.3.2",
"fsevents": "^1.2.7",
"glob-parent": "^3.1.0",
"inherits": "^2.0.3",
"is-binary-path": "^1.0.0",
@ -22093,6 +22094,14 @@
"integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==",
"dev": true
},
"axios": {
"version": "0.24.0",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.24.0.tgz",
"integrity": "sha512-Q6cWsys88HoPgAaFAVUb0WpPk0O8iTeisR9IMqy9G8AbO4NlpVknrnQS03zzF9PGAWgO3cgletO3VjV/P7VztA==",
"requires": {
"follow-redirects": "^1.14.4"
}
},
"babel-code-frame": {
"version": "6.26.0",
"resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz",
@ -26185,8 +26194,7 @@
"follow-redirects": {
"version": "1.14.5",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.5.tgz",
"integrity": "sha512-wtphSXy7d4/OR+MvIFbCVBDzZ5520qV8XfPklSN5QtxuMUJZ+b0Wnst1e1lCDocfzuCkHqj8k0FpZqO+UIaKNA==",
"dev": true
"integrity": "sha512-wtphSXy7d4/OR+MvIFbCVBDzZ5520qV8XfPklSN5QtxuMUJZ+b0Wnst1e1lCDocfzuCkHqj8k0FpZqO+UIaKNA=="
},
"for-in": {
"version": "1.0.2",

View File

@ -9,6 +9,7 @@
"lint": "vue-cli-service lint"
},
"dependencies": {
"axios": "^0.24.0",
"core-js": "^3.6.5",
"vue": "^2.6.11",
"vue-router": "^3.2.0",

View File

@ -1,48 +1,63 @@
<template>
<v-container>
<h1 class="title font-weight-thin">Wyszukiwarka samochodów</h1>
<v-row>
<v-col md="3" v-for="item in items" :key="item.label">
<v-combobox v-model="item.selected" :items="item.items" :label="item.label"></v-combobox>
</v-col>
</v-row>
<v-row justify="center">
<v-btn rounded color="primary" dark>Szukaj</v-btn>
</v-row>
</v-container>
<v-container>
<h1 class="title font-weight-thin">Wyszukiwarka samochodów</h1>
<v-row>
<v-col md="3" v-for="item in items" :key="item.label">
<v-combobox
v-model="item.selected"
:items="item.items"
:label="item.label"
></v-combobox>
</v-col>
</v-row>
<v-row justify="center">
<v-btn rounded color="primary" dark @click="send">Szukaj</v-btn>
</v-row>
</v-container>
</template>
<script>
import axios from "axios";
import { mapMutations } from 'vuex'
export default {
name: "Search",
name: "Search",
data: () => ({
items: {
age: {
label: "Rok produkcji",
selected: "",
items: ["Dawno", "Średnio", "Niedawno"],
},
mileage: {
label: "Przebieg",
selected: "",
items: ["Niski", "Średni", "Duży"],
},
engine_capacity: {
label: "Pojemność silnika",
selected: "",
items: ["Mała", "Średnia", "Ogromna"],
},
fuel_usage: {
label: "Spalanie paliwa",
selected: "",
items: ["Niskie", "Średnie", "Wysokie"],
},
},
}),
data: () => ({
items: {
production_year: {
label: "Rok produkcji",
selected: "",
items: ["Dawno", "Średnio", "Niedawno"],
},
mileage: {
label: "Przebieg",
selected: "",
items: ["Niski", "Średni", "Duży"],
},
engine_capacity: {
label: "Pojemność silnika",
selected: "",
items: ["Mała", "Średnia", "Ogromna"],
},
combustion: {
label: "Spalanie paliwa",
selected: "",
items: ["Niskie", "Średnie", "Wysokie"],
},
},
}),
methods: {
...mapMutations(['setCars']),
send() {
let query = {}
Object.entries(this.items).forEach(([key, value]) =>
query[key] = value.selected
);
axios.get('http://localhost:8000/cars', { params: query}).then((res) => { this.setCars(res.data) })
},
},
};
</script>
<style scoped>
</style>

View File

@ -2,13 +2,14 @@
<v-container>
<v-row>
<v-col md="12">
<v-data-table :headers="headers" :items="items" class="elevation-1"></v-data-table>
<v-data-table :headers="headers" :items="getCars" class="elevation-1"></v-data-table>
</v-col>
</v-row>
</v-container>
</template>
<script>
import { mapGetters } from 'vuex'
export default {
name: "Table",
@ -19,7 +20,7 @@ export default {
{ text: "Przebieg (km)", value: "mileage" },
{ text: "Rok produkcji", value: "production_year" },
{ text: "Pojemnośc silnika (cm^3)", value: "engine_capacity" },
{ text: "Spalanie (L/100km)", value: "fuel_usage" },
{ text: "Spalanie (L/100km)", value: "combustion" },
{ text: "Cena (zł)", value: "price" },
],
items: [{
@ -28,7 +29,7 @@ export default {
mileage: 230000,
production_year: 2008,
engine_capacity: 2.0,
fuel_usage: 7.6,
combustion: 7.6,
price: 12200,
},
{
@ -37,11 +38,14 @@ export default {
mileage: 430000,
production_year: 2003,
engine_capacity: 1.3,
fuel_usage: 5.5,
combustion: 5.5,
price: 3500,
},
],
}),
computed: {
...mapGetters(['getCars'])
}
};
</script>

View File

@ -4,8 +4,19 @@ import Vuex from "vuex";
Vue.use(Vuex);
export default new Vuex.Store({
state: {},
mutations: {},
state: {
cars: []
},
mutations: {
setCars(state, cars) {
state.cars = cars
}
},
getters: {
getCars: state => {
return state.cars
}
},
actions: {},
modules: {},
});