更新了Django第4天代码
This commit is contained in:
parent
a8428301e1
commit
39f70bd33d
|
|
@ -0,0 +1,3 @@
|
|||
import pymysql
|
||||
|
||||
pymysql.install_as_MySQLdb()
|
||||
|
|
@ -0,0 +1,127 @@
|
|||
"""
|
||||
Django settings for car project.
|
||||
|
||||
Generated by 'django-admin startproject' using Django 2.0.5.
|
||||
|
||||
For more information on this file, see
|
||||
https://docs.djangoproject.com/en/2.0/topics/settings/
|
||||
|
||||
For the full list of settings and their values, see
|
||||
https://docs.djangoproject.com/en/2.0/ref/settings/
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
|
||||
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
|
||||
# Quick-start development settings - unsuitable for production
|
||||
# See https://docs.djangoproject.com/en/2.0/howto/deployment/checklist/
|
||||
|
||||
# SECURITY WARNING: keep the secret key used in production secret!
|
||||
SECRET_KEY = 'ol6dmf6im(w!l*z4w+_whm&)8@(c7%4&tlhd%uh6$lfx=pi*5e'
|
||||
|
||||
# SECURITY WARNING: don't run with debug turned on in production!
|
||||
DEBUG = True
|
||||
|
||||
ALLOWED_HOSTS = []
|
||||
|
||||
|
||||
# Application definition
|
||||
|
||||
INSTALLED_APPS = [
|
||||
'django.contrib.admin',
|
||||
'django.contrib.auth',
|
||||
'django.contrib.contenttypes',
|
||||
'django.contrib.sessions',
|
||||
'django.contrib.messages',
|
||||
'django.contrib.staticfiles',
|
||||
'search',
|
||||
]
|
||||
|
||||
MIDDLEWARE = [
|
||||
'django.middleware.security.SecurityMiddleware',
|
||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||
'django.middleware.common.CommonMiddleware',
|
||||
'django.middleware.csrf.CsrfViewMiddleware',
|
||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||
'django.contrib.messages.middleware.MessageMiddleware',
|
||||
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
||||
]
|
||||
|
||||
ROOT_URLCONF = 'car.urls'
|
||||
|
||||
TEMPLATES = [
|
||||
{
|
||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
||||
'DIRS': [os.path.join(BASE_DIR, 'templates')]
|
||||
,
|
||||
'APP_DIRS': True,
|
||||
'OPTIONS': {
|
||||
'context_processors': [
|
||||
'django.template.context_processors.debug',
|
||||
'django.template.context_processors.request',
|
||||
'django.contrib.auth.context_processors.auth',
|
||||
'django.contrib.messages.context_processors.messages',
|
||||
],
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
WSGI_APPLICATION = 'car.wsgi.application'
|
||||
|
||||
|
||||
# Database
|
||||
# https://docs.djangoproject.com/en/2.0/ref/settings/#databases
|
||||
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.mysql',
|
||||
'NAME': 'car',
|
||||
'HOST': 'localhost',
|
||||
'PORT': 3306,
|
||||
'USER': 'root',
|
||||
'PASSWORD': '123456',
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# Password validation
|
||||
# https://docs.djangoproject.com/en/2.0/ref/settings/#auth-password-validators
|
||||
|
||||
AUTH_PASSWORD_VALIDATORS = [
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
# Internationalization
|
||||
# https://docs.djangoproject.com/en/2.0/topics/i18n/
|
||||
|
||||
LANGUAGE_CODE = 'en-us'
|
||||
|
||||
TIME_ZONE = 'UTC'
|
||||
|
||||
USE_I18N = True
|
||||
|
||||
USE_L10N = True
|
||||
|
||||
USE_TZ = True
|
||||
|
||||
|
||||
# Static files (CSS, JavaScript, Images)
|
||||
# https://docs.djangoproject.com/en/2.0/howto/static-files/
|
||||
STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static')]
|
||||
|
||||
STATIC_URL = '/static/'
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
"""car URL Configuration
|
||||
|
||||
The `urlpatterns` list routes URLs to views. For more information please see:
|
||||
https://docs.djangoproject.com/en/2.0/topics/http/urls/
|
||||
Examples:
|
||||
Function views
|
||||
1. Add an import: from my_app import views
|
||||
2. Add a URL to urlpatterns: path('', views.home, name='home')
|
||||
Class-based views
|
||||
1. Add an import: from other_app.views import Home
|
||||
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
|
||||
Including another URLconf
|
||||
1. Import the include() function: from django.urls import include, path
|
||||
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
|
||||
"""
|
||||
from django.contrib import admin
|
||||
from django.conf.urls import url
|
||||
|
||||
from search import views
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^search$', views.search),
|
||||
url(r'^search2$', views.ajax_search),
|
||||
url(r'^add', views.add),
|
||||
url(r'^admin/', admin.site.urls),
|
||||
]
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
"""
|
||||
WSGI config for car project.
|
||||
|
||||
It exposes the WSGI callable as a module-level variable named ``application``.
|
||||
|
||||
For more information on this file, see
|
||||
https://docs.djangoproject.com/en/2.0/howto/deployment/wsgi/
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
from django.core.wsgi import get_wsgi_application
|
||||
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "car.settings")
|
||||
|
||||
application = get_wsgi_application()
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
#!/usr/bin/env python
|
||||
import os
|
||||
import sys
|
||||
|
||||
if __name__ == "__main__":
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "car.settings")
|
||||
try:
|
||||
from django.core.management import execute_from_command_line
|
||||
except ImportError as exc:
|
||||
raise ImportError(
|
||||
"Couldn't import Django. Are you sure it's installed and "
|
||||
"available on your PYTHONPATH environment variable? Did you "
|
||||
"forget to activate a virtual environment?"
|
||||
) from exc
|
||||
execute_from_command_line(sys.argv)
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
from django.contrib import admin
|
||||
|
||||
from search.models import CarRecord
|
||||
|
||||
|
||||
class CarRecordAdmin(admin.ModelAdmin):
|
||||
|
||||
list_display = ('carno', 'reason', 'date', 'punish', 'isdone')
|
||||
search_fields = ('carno', )
|
||||
|
||||
|
||||
admin.site.register(CarRecord, CarRecordAdmin)
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class SearchConfig(AppConfig):
|
||||
name = 'search'
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11 on 2018-05-24 01:16
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='CarRecord',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('carno', models.CharField(max_length=7)),
|
||||
('reason', models.CharField(max_length=50)),
|
||||
('date', models.DateTimeField(db_column='happen_date')),
|
||||
('punlish', models.CharField(max_length=50)),
|
||||
('isdone', models.BooleanField(default=False)),
|
||||
],
|
||||
options={
|
||||
'db_table': 'tb_car_record',
|
||||
},
|
||||
),
|
||||
]
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11 on 2018-05-24 06:20
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('search', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name='carrecord',
|
||||
options={'ordering': ('-date',)},
|
||||
),
|
||||
migrations.RenameField(
|
||||
model_name='carrecord',
|
||||
old_name='punlish',
|
||||
new_name='punish',
|
||||
),
|
||||
]
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
from django.db import models
|
||||
|
||||
|
||||
class CarRecord(models.Model):
|
||||
carno = models.CharField(max_length=7)
|
||||
reason = models.CharField(max_length=50)
|
||||
date = models.DateTimeField(db_column='happen_date', auto_now_add=True)
|
||||
punish = models.CharField(max_length=50)
|
||||
isdone = models.BooleanField(default=False)
|
||||
|
||||
@property
|
||||
def happen_date(self):
|
||||
return self.date.strftime('%Y-%m-%d %H:%M:%S')
|
||||
"""
|
||||
return '%d年%02d月%02d日 %02d:%02d:%02d' % \
|
||||
(self.date.year, self.date.month, self.date.day,
|
||||
self.date.hour, self.date.minute, self.date.second)
|
||||
"""
|
||||
|
||||
class Meta:
|
||||
db_table = 'tb_car_record'
|
||||
ordering = ('-date', )
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
from json import JSONEncoder
|
||||
|
||||
from django import forms
|
||||
from django.http import JsonResponse
|
||||
from django.shortcuts import render
|
||||
|
||||
from search.models import CarRecord
|
||||
|
||||
# 序列化/串行化/腌咸菜 - 把对象按照某种方式处理成字节或者字符的序列
|
||||
# 反序列化/反串行化 - 把字符或者字节的序列重新还原成对象
|
||||
# Python实现序列化和反序列化的工具模块 - json / pickle / shelve
|
||||
# return HttpResponse(json.dumps(obj), content_type='application/json')
|
||||
# return JsonResponse(obj, encoder=, safe=False)
|
||||
# from django.core.serializers import serialize
|
||||
# return HttpResponse(serialize('json', obj), content_type='application/json; charset=utf-8')
|
||||
|
||||
|
||||
class CarRecordEncoder(JSONEncoder):
|
||||
|
||||
def default(self, o):
|
||||
del o.__dict__['_state']
|
||||
o.__dict__['date'] = o.happen_date
|
||||
return o.__dict__
|
||||
|
||||
|
||||
def ajax_search(request):
|
||||
if request.method == 'GET':
|
||||
return render(request, 'search2.html')
|
||||
else:
|
||||
carno = request.POST['carno']
|
||||
record_list = list(CarRecord.objects.filter(carno__icontains=carno))
|
||||
# 第一个参数是要转换成JSON格式(序列化)的对象
|
||||
# encoder参数要指定完成自定义对象序列化的编码器(JSONEncoder的子类型)
|
||||
# safe参数的值如果为True那么传入的第一个参数只能是字典
|
||||
# return HttpResponse(json.dumps(record_list), content_type='application/json; charset=utf-8')
|
||||
return JsonResponse(record_list, encoder=CarRecordEncoder,
|
||||
safe=False)
|
||||
|
||||
|
||||
def search(request):
|
||||
# 请求行中的请求命令
|
||||
# print(request.method)
|
||||
# 请求行中的路径
|
||||
# print(request.path)
|
||||
# 请求头(以HTTP_打头的键是HTTP请求的请求头)
|
||||
# print(request.META)
|
||||
# 查询参数: http://host/path/resource?a=b&c=d
|
||||
# print(request.GET)
|
||||
# 表单参数
|
||||
# print(request.POST)
|
||||
if request.method == 'GET':
|
||||
ctx = {'show_result': False}
|
||||
else:
|
||||
carno = request.POST['carno']
|
||||
ctx = {
|
||||
'show_result': True,
|
||||
'record_list': list(CarRecord.objects.filter(carno__contains=carno))}
|
||||
return render(request, 'search.html', ctx)
|
||||
|
||||
|
||||
class CarRecordForm(forms.Form):
|
||||
carno = forms.CharField(min_length=7, max_length=7, label='车牌号', error_messages={'carno': '请输入有效的车牌号'})
|
||||
reason = forms.CharField(max_length=50, label='违章原因')
|
||||
punish = forms.CharField(max_length=50, required=False, label='处罚方式')
|
||||
|
||||
|
||||
def add(request):
|
||||
errors = []
|
||||
if request.method == 'GET':
|
||||
f = CarRecordForm()
|
||||
else:
|
||||
f = CarRecordForm(request.POST)
|
||||
if f.is_valid():
|
||||
CarRecord(**f.cleaned_data).save()
|
||||
f = CarRecordForm()
|
||||
else:
|
||||
errors = f.errors.values()
|
||||
return render(request, 'add.html', {'f': f, 'errors': errors})
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
<svg width="13" height="13" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill="#dd4646" d="M1277 1122q0-26-19-45l-181-181 181-181q19-19 19-45 0-27-19-46l-90-90q-19-19-46-19-26 0-45 19l-181 181-181-181q-19-19-45-19-27 0-46 19l-90 90q-19 19-19 46 0 26 19 45l181 181-181 181q-19 19-19 45 0 27 19 46l90 90q19 19 46 19 26 0 45-19l181-181 181 181q19 19 45 19 27 0 46-19l90-90q19-19 19-46zm387-226q0 209-103 385.5t-279.5 279.5-385.5 103-385.5-103-279.5-279.5-103-385.5 103-385.5 279.5-279.5 385.5-103 385.5 103 279.5 279.5 103 385.5z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 560 B |
|
|
@ -0,0 +1,3 @@
|
|||
<svg width="13" height="13" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill="#70bf2b" d="M1412 734q0-28-18-46l-91-90q-19-19-45-19t-45 19l-408 407-226-226q-19-19-45-19t-45 19l-91 90q-18 18-18 46 0 27 18 45l362 362q19 19 45 19 27 0 46-19l543-543q18-18 18-45zm252 162q0 209-103 385.5t-279.5 279.5-385.5 103-385.5-103-279.5-279.5-103-385.5 103-385.5 279.5-279.5 385.5-103 385.5 103 279.5 279.5 103 385.5z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 436 B |
|
|
@ -0,0 +1,23 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>添加</title>
|
||||
</head>
|
||||
<body>
|
||||
<h2>添加违章记录</h2>
|
||||
<hr>
|
||||
<p>
|
||||
{% for err in errors %}
|
||||
<div style="color: red; font-size: 12px;">{{ err }}</div>
|
||||
{% endfor %}
|
||||
</p>
|
||||
<form action="/add" method="post">
|
||||
<table>
|
||||
{{ f.as_table }}
|
||||
</table>
|
||||
{% csrf_token %}
|
||||
<input type="submit" value="添加">
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
<!DOCTYPE html>
|
||||
{% load staticfiles %}
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>车辆违章查询</title>
|
||||
<style>
|
||||
* {
|
||||
font: 18px/30px Arial;
|
||||
}
|
||||
#container {
|
||||
width: 960px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
#container form {
|
||||
width: 620px;
|
||||
margin: 10px auto;
|
||||
padding-top: 100px;
|
||||
}
|
||||
#container form input[type=search] {
|
||||
display: inline-block;
|
||||
width: 480px;
|
||||
height: 30px;
|
||||
}
|
||||
#container form input[type=submit] {
|
||||
display: inline-block;
|
||||
width: 80px;
|
||||
height: 40px;
|
||||
border: None;
|
||||
background-color: red;
|
||||
color: white;
|
||||
margin-left: 20px;
|
||||
}
|
||||
#container table {
|
||||
width: 920px;
|
||||
margin: 20px auto;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
#container table th {
|
||||
font-weight: bolder;
|
||||
border-bottom: 1px solid darkgray;
|
||||
}
|
||||
#container table td {
|
||||
text-align: center;
|
||||
height: 50px;
|
||||
width: 180px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="container">
|
||||
<form action="/search" method="post">
|
||||
<!-- 跨站身份伪造: 利用浏览器存储的cookie中的用户身份标识冒充用户执行操作 -->
|
||||
<!-- 防范跨站身份伪造最佳的做法就是在表单中放置随机令牌 -->
|
||||
<!-- 除此之外通过设置令牌还可以防范表单重复提交以及重放攻击 -->
|
||||
<!-- 隐藏域 / 隐式表单域: 页面上是无法看到该内容-->
|
||||
{% csrf_token %}
|
||||
<input type="search" name="carno" placeholder="请输入你的车牌号" required>
|
||||
<input type="submit" value="搜索">
|
||||
</form>
|
||||
<hr>
|
||||
{% if show_result %}
|
||||
<table>
|
||||
<tr>
|
||||
<th>车牌号</th>
|
||||
<th>违章原因</th>
|
||||
<th>违章时间</th>
|
||||
<th>处罚方式</th>
|
||||
<th>是否受理</th>
|
||||
</tr>
|
||||
{% for record in record_list %}
|
||||
<tr>
|
||||
<td>{{ record.carno }}</td>
|
||||
<td>{{ record.reason }}</td>
|
||||
<td>{{ record.happen_date }}</td>
|
||||
<td>{{ record.punish }}</td>
|
||||
<td>
|
||||
{% if record.isdone %}
|
||||
<img src="{% static '/images/icon-yes.svg' %}">
|
||||
{% else %}
|
||||
<img src="{% static '/images/icon-no.svg' %}">
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
{% endif %}
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>车辆违章查询</title>
|
||||
<style>
|
||||
* {
|
||||
font: 18px/30px Arial;
|
||||
}
|
||||
#container {
|
||||
width: 960px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
#search {
|
||||
width: 720px;
|
||||
margin: 10px auto;
|
||||
padding-top: 100px;
|
||||
}
|
||||
#search input[type=search] {
|
||||
display: inline-block;
|
||||
width: 480px;
|
||||
height: 30px;
|
||||
}
|
||||
#search input[type=submit] {
|
||||
display: inline-block;
|
||||
width: 80px;
|
||||
height: 40px;
|
||||
border: None;
|
||||
background-color: red;
|
||||
color: white;
|
||||
margin-left: 20px;
|
||||
}
|
||||
#result {
|
||||
width: 920px;
|
||||
margin: 20px auto;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
#result th {
|
||||
font-weight: bolder;
|
||||
border-bottom: 1px solid darkgray;
|
||||
}
|
||||
#result td, #result th {
|
||||
text-align: center;
|
||||
height: 50px;
|
||||
width: 180px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="container">
|
||||
<form id="search" action="/search" method="post">
|
||||
<!-- 跨站身份伪造: 利用浏览器存储的cookie中的用户身份标识冒充用户执行操作 -->
|
||||
<!-- 防范跨站身份伪造最佳的做法就是在表单中放置随机令牌 -->
|
||||
<!-- 除此之外通过设置令牌还可以防范表单重复提交以及重放攻击 -->
|
||||
<!-- 隐藏域 / 隐式表单域: 页面上是无法看到该内容-->
|
||||
{% csrf_token %}
|
||||
<input type="search" id="carno" name="carno" placeholder="请输入你的车牌号" required>
|
||||
<input type="submit" value="搜索">
|
||||
<a href="/add">添加新记录</a>
|
||||
</form>
|
||||
<hr>
|
||||
<table id="result">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>车牌号</th>
|
||||
<th>违章原因</th>
|
||||
<th>违章时间</th>
|
||||
<th>处罚方式</th>
|
||||
<th>是否受理</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
|
||||
<script>
|
||||
$(function() {
|
||||
$('#search').on('submit', function(evt) {
|
||||
evt.preventDefault();
|
||||
var carno = $('#carno').val();
|
||||
var token = $('#search input[type=hidden]').val()
|
||||
$.ajax({
|
||||
url: '/search2',
|
||||
type: 'post',
|
||||
data: {
|
||||
'carno': carno,
|
||||
'csrfmiddlewaretoken': token
|
||||
},
|
||||
dataType: 'json',
|
||||
success: function(json) {
|
||||
$('#result tbody').children().remove();
|
||||
for (var i = 0; i < json.length; i += 1) {
|
||||
var record = json[i];
|
||||
var tr = $('<tr>').append($('<td>').text(record.carno))
|
||||
.append($('<td>').text(record.reason))
|
||||
.append($('<td>').text(record.date))
|
||||
.append($('<td>').text(record.punish));
|
||||
var imgName = record.isdone ? 'icon-yes.svg' : 'icon-no.svg';
|
||||
tr.append($('<td>').append($('<img>').attr('src', '/static/images/' + imgName)));
|
||||
$('#result tbody').append(tr);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
# Generated by Django 2.0.5 on 2018-05-22 03:07
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Dept',
|
||||
fields=[
|
||||
('no', models.IntegerField(primary_key=True, serialize=False)),
|
||||
('name', models.CharField(max_length=20)),
|
||||
('location', models.CharField(max_length=10)),
|
||||
],
|
||||
options={
|
||||
'db_table': 'tb_dept',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Emp',
|
||||
fields=[
|
||||
('no', models.IntegerField(primary_key=True, serialize=False)),
|
||||
('name', models.CharField(max_length=20)),
|
||||
('job', models.CharField(max_length=10)),
|
||||
('mgr', models.IntegerField(null=True)),
|
||||
('sal', models.DecimalField(decimal_places=2, max_digits=7)),
|
||||
('comm', models.DecimalField(decimal_places=2, max_digits=7, null=True)),
|
||||
('dept', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='hrs.Dept')),
|
||||
],
|
||||
options={
|
||||
'db_table': 'tb_emp',
|
||||
},
|
||||
),
|
||||
]
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
# Generated by Django 2.0.5 on 2018-05-23 01:23
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('hrs', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='dept',
|
||||
name='excellent',
|
||||
field=models.BooleanField(default=0, verbose_name='是否优秀'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='dept',
|
||||
name='location',
|
||||
field=models.CharField(max_length=10, verbose_name='部门所在地'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='dept',
|
||||
name='name',
|
||||
field=models.CharField(max_length=20, verbose_name='部门名称'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='dept',
|
||||
name='no',
|
||||
field=models.IntegerField(primary_key=True, serialize=False, verbose_name='部门编号'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='emp',
|
||||
name='comm',
|
||||
field=models.DecimalField(blank=True, decimal_places=2, max_digits=7, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='emp',
|
||||
name='mgr',
|
||||
field=models.IntegerField(blank=True, null=True),
|
||||
),
|
||||
]
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
# Generated by Django 2.0.5 on 2018-05-24 08:46
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('hrs', '0002_auto_20180523_0923'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='emp',
|
||||
name='mgr',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='hrs.Emp'),
|
||||
),
|
||||
]
|
||||
|
|
@ -24,7 +24,8 @@ class Emp(models.Model):
|
|||
no = models.IntegerField(primary_key=True)
|
||||
name = models.CharField(max_length=20)
|
||||
job = models.CharField(max_length=10)
|
||||
mgr = models.IntegerField(null=True, blank=True)
|
||||
mgr = models.ForeignKey('self', null=True, blank=True, on_delete=models.SET_NULL)
|
||||
# mgr = models.IntegerField(null=True, blank=True)
|
||||
sal = models.DecimalField(max_digits=7, decimal_places=2)
|
||||
comm = models.DecimalField(max_digits=7, decimal_places=2, null=True, blank=True)
|
||||
dept = models.ForeignKey(Dept, on_delete=models.PROTECT)
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ from hrs import views
|
|||
|
||||
urlpatterns = [
|
||||
path('depts', views.depts, name='depts'),
|
||||
path('depts/emps', views.emps, name='empsindept'),
|
||||
path('deldepts', views.del_dept, name='ddel')
|
||||
# url('depts/emps/(?P<no>[0-9]+)', views.emps, name='empsindept'),
|
||||
path('depts/emps/<int:no>', views.emps, name='empsindept'),
|
||||
path('deldept/<int:no>', views.del_dept, name='ddel')
|
||||
]
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
from django.http import HttpResponse
|
||||
from django.shortcuts import render, redirect
|
||||
from django.urls import reverse
|
||||
from django.db.models import ObjectDoesNotExist
|
||||
|
||||
from json import dumps
|
||||
|
||||
from hrs.models import Dept, Emp
|
||||
|
||||
|
|
@ -11,13 +14,21 @@ def index(request):
|
|||
return render(request, 'index.html', context=ctx)
|
||||
|
||||
|
||||
def del_dept(request):
|
||||
# 重定向 - 重新请求一个指定的页面
|
||||
return redirect(reverse('depts'))
|
||||
def del_dept(request, no='0'):
|
||||
try:
|
||||
Dept.objects.get(pk=no).delete()
|
||||
ctx = {'code': 200}
|
||||
except (ObjectDoesNotExist, ValueError):
|
||||
ctx = {'code': 404}
|
||||
return HttpResponse(
|
||||
dumps(ctx), content_type='application/json; charset=utf-8')
|
||||
# 重定向 - 给浏览器一个URL, 让浏览器重新请求指定的页面
|
||||
# return redirect(reverse('depts'))
|
||||
# return depts(request)
|
||||
|
||||
|
||||
def emps(request):
|
||||
no = request.GET['no']
|
||||
def emps(request, no='0'):
|
||||
# no = request.GET['no']
|
||||
# dept = Dept.objects.get(no=no)
|
||||
# ForeignKey(Dept, on_delete=models.PROTECT, related_name='emps')
|
||||
# dept.emps.all()
|
||||
|
|
|
|||
|
|
@ -5,6 +5,11 @@
|
|||
<meta charset="UTF-8">
|
||||
<title>部门</title>
|
||||
<link href="{% static 'css/bootstrap.min.css' %}" rel="stylesheet">
|
||||
<style>
|
||||
#dept td, #dept th {
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
|
|
@ -14,6 +19,7 @@
|
|||
<hr>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row clearfix">
|
||||
<div class="col-md-8 column">
|
||||
<table id="dept" class="table table-striped table-hover">
|
||||
|
|
@ -32,7 +38,7 @@
|
|||
<td>{{ dept.no }}</td>
|
||||
<td>
|
||||
<!-- 写代码时要尽量避免使用硬编码(hard code) -->
|
||||
<a href="{% url 'empsindept' %}?no={{ dept.no }}">{{ dept.name }}</a>
|
||||
<a href="{% url 'empsindept' dept.no %}">{{ dept.name }}</a>
|
||||
</td>
|
||||
<td>{{ dept.location }}</td>
|
||||
<td>
|
||||
|
|
@ -43,7 +49,7 @@
|
|||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
<a href="{% url 'ddel' %}?dno={{ dept.no }}" class="btn btn-xs btn-warning">删除</a>
|
||||
<a id="{{ dept.no }}" href="javascript:void(0);" class="btn btn-xs btn-warning">删除</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
|
@ -60,6 +66,18 @@
|
|||
$(function() {
|
||||
$('#dept tbody tr:even').addClass('info');
|
||||
$('#dept tbody tr:odd').addClass('warning');
|
||||
$('#dept a[id]').on('click', function(evt) {
|
||||
var a = $(evt.target);
|
||||
if (confirm('确定要删除吗?')) {
|
||||
$.getJSON('/hrs/deldept/' + a.attr('id'), function(json) {
|
||||
if (json.code == 200) {
|
||||
a.parent().parent().remove();
|
||||
$('#dept tbody tr:even').addClass('info');
|
||||
$('#dept tbody tr:odd').addClass('warning');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
|
|
|||
Loading…
Reference in New Issue