ORM版學員管理系統
班級表
表結構html
class Class(models.Model): id = models.AutoField(primary_key=True) # 主鍵 cname = models.CharField(max_length=32) # 班級名稱 first_day = models.DateField() # 開班時間
查詢班級
URL部分:前端
url(r'^class_list/$', views.class_list, name="class_list"),
視圖部分:數據庫
def class_list(request): class_list = models.Class.objects.all() return render(request, "class_list.html", {"class_list": class_list})
HTML部分:django
<table border="1"> {% for class in class_list %} <tr> <td>{{ forloop.counter }}</td> <td>{{ class.id }}</td> <td>{{ class.cname }}</td> <td>{{ class.first_day|date:'Y-m-d' }}</td> </tr> {% endfor %} </table>
新增班級
URL部分:ide
url(r'^add_class/$', views.add_class, name="add_class"),
視圖部分:函數
def add_class(request): # 前端POST填好的新班級信息 if request.method == "POST": cname = request.POST.get("cname") first_day = request.POST.get("first_day") # 還能夠這麼獲取提交的數據,但不推薦這麼寫 # data = request.POST.dict() # del data["csrfmiddlewaretoken"] # 建立新數據的兩種方式 # new_class = models.Class(cname=cname, first_day=first_day) # new_class.save() models.Class.objects.create(cname=cname, first_day=first_day) # 跳轉到class_list return redirect(reverse('class_list')) # 返回添加班級的頁面 return render(request, "add_class.html")
HTML部分:oop
在班級列表頁面添加一個a標籤:post
<a href="{% url 'add_class' %}">新頁面添加</a>
新添加頁面:ui
注意 {% csrf_token %} 和 date類型的input標籤。this
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="x-ua-compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>添加班級</title> </head> <body> <form action="{% url 'add_class' %}" method="post"> {% csrf_token %} <p>班級名稱:<input type="text" name="cname"></p> <p>開班日期:<input type="date" name="first_day"></p> <p>提交<input type="submit"></p> </form> </body> </html>
刪除班級
URL部分:
url(r'^delete_class/$', views.delete_class, name="delete_class"),
視圖部分:
def delete_class(request): class_id = request.GET.get("class_id") models.Class.objects.filter(id=class_id).delete() return redirect(reverse("class_list"))
HTML部分:
在班級列表頁面的表格中添加刪除。
<a href="{% url 'delete_class' %}?class_id={{ class.id }}">刪除</a>
編輯班級
URL部分:
url(r'^edit_class/$', views.edit_class, name="edit_class"),
視圖部分:
def edit_class(request): if request.method == "POST": class_id = request.POST.get("id") cname = request.POST.get("cname") first_day = request.POST.get("first_day") models.Class.objects.create(id=class_id, cname=cname, first_day=first_day) return redirect(reverse("class_list")) class_id = request.GET.get("class_id") class_obj = models.Class.objects.filter(id=class_id) if class_obj: class_obj = class_obj[0] return render(request, "edit_class.html", {"class": class_obj}) # 找不到該條記錄 else: return redirect(reverse("class_list"))
HTML部分:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="x-ua-compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>編輯班級</title> </head> <body> <form action="{% url 'edit_class' %}" method="post"> {% csrf_token %} <input type="text" value="{{ class.id }}" style="display: none"> <p>班級名稱:<input type="text" name="cname" value="{{ class.cname }}"></p> <p>開班日期:<input type="date" name="first_day" value="{{ class.first_day|date:'Y-m-d' }}"></p> <p>提交<input type="submit"></p> </form> </body> </html>
補充
若是將以前的URL由 /edit_class/?class_id=n修改成 /edit_class/n/ ,視圖函數和HTML部分分別應該如何修改?
URL部分:
url(r'^edit_class/(\d+)$', views.edit_class, name="edit_class"),
視圖部分:
def edit_class(request, class_id): if request.method == "POST": cname = request.POST.get("cname") first_day = request.POST.get("first_day") models.Class.objects.create(id=class_id, cname=cname, first_day=first_day) return redirect(reverse("class_list")) class_obj = models.Class.objects.filter(id=class_id) if class_obj: class_obj = class_obj[0] return render(request, "edit_class.html", {"class": class_obj}) # 找不到該條記錄 else: print("沒有該班級") return redirect(reverse("class_list"))
HTML部分:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="x-ua-compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>編輯班級</title> </head> <body> <form action="{% url 'edit_class' class.id %}" method="post"> {% csrf_token %} <input type="text" value="{{ class.id }}" style="display: none"> <p>班級名稱:<input type="text" name="cname" value="{{ class.cname }}"></p> <p>開班日期:<input type="date" name="first_day" value="{{ class.first_day|date:'Y-m-d' }}"></p> <p>提交<input type="submit"></p> </form> </body> </html>
單表查詢API彙總
<1> all(): 查詢全部結果 <2> filter(**kwargs): 它包含了與所給篩選條件相匹配的對象 <3> get(**kwargs): 返回與所給篩選條件相匹配的對象,返回結果有且只有一個,若是符合篩選條件的對象超過一個或者沒有都會拋出錯誤。 <4> exclude(**kwargs): 它包含了與所給篩選條件不匹配的對象 <5> values(*field): 返回一個ValueQuerySet——一個特殊的QuerySet,運行後獲得的並非一系列model的實例化對象,而是一個可迭代的字典序列 <6> values_list(*field): 它與values()很是類似,它返回的是一個元組序列,values返回的是一個字典序列 <7> order_by(*field): 對查詢結果排序 <8> reverse(): 對查詢結果反向排序 <9> distinct(): 從返回結果中剔除重複紀錄 <10> count(): 返回數據庫中匹配查詢(QuerySet)的對象數量。 <11> first(): 返回第一條記錄 <12> last(): 返回最後一條記錄 <13> exists(): 若是QuerySet包含數據,就返回True,不然返回False
注意:必定區分Object與QuerySet的區別 !!!
QuerySet有update方法而Object默認沒有。
單表查詢之神奇的雙下劃線
models.Tb1.objects.filter(id__lt=10, id__gt=1) # 獲取id大於1 且 小於10的值 models.Tb1.objects.filter(id__in=[11, 22, 33]) # 獲取id等於十一、22、33的數據 models.Tb1.objects.exclude(id__in=[11, 22, 33]) # not in models.Tb1.objects.filter(name__contains="ven") # 獲取name字段包含"ven"的 models.Tb1.objects.filter(name__icontains="ven") # icontains大小寫不敏感 models.Tb1.objects.filter(id__range=[1, 3]) # id範圍是1到3的,等價於SQL的bettwen and 相似的還有:startswith,istartswith, endswith, iendswith date字段還能夠: models.Class.objects.filter(first_day__year=2017)
備註:
在Django的日誌設置中,配置上一個名爲django.db.backends的logger實例便可查看翻譯後的SQL語句。
LOGGING = { 'version': 1, 'disable_existing_loggers': False, 'handlers': { 'console':{ 'level':'DEBUG', 'class':'logging.StreamHandler', }, }, 'loggers': { 'django.db.backends': { 'handlers': ['console'], 'propagate': True, 'level':'DEBUG', }, } }
Django項目完整版LOGGING配置:
LOGGING = { 'version': 1, 'disable_existing_loggers': False, 'formatters': { 'standard': { 'format': '[%(asctime)s][%(threadName)s:%(thread)d][task_id:%(name)s][%(filename)s:%(lineno)d]' '[%(levelname)s][%(message)s]' }, 'simple': { 'format': '[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s' }, 'collect': { 'format': '%(message)s' } }, 'filters': { 'require_debug_true': { '()': 'django.utils.log.RequireDebugTrue', }, }, 'handlers': { 'console': { 'level': 'DEBUG', 'filters': ['require_debug_true'], # 只有在Django debug爲True時纔在屏幕打印日誌 'class': 'logging.StreamHandler', 'formatter': 'simple' }, 'default': { 'level': 'INFO', 'class': 'logging.handlers.RotatingFileHandler', # 保存到文件,自動切 'filename': os.path.join(BASE_LOG_DIR, "xxx_info.log"), # 日誌文件 'maxBytes': 1024 * 1024 * 50, # 日誌大小 50M 'backupCount': 3, 'formatter': 'standard', 'encoding': 'utf-8', }, 'error': { 'level': 'ERROR', 'class': 'logging.handlers.RotatingFileHandler', # 保存到文件,自動切 'filename': os.path.join(BASE_LOG_DIR, "xxx_err.log"), # 日誌文件 'maxBytes': 1024 * 1024 * 50, # 日誌大小 50M 'backupCount': 5, 'formatter': 'standard', 'encoding': 'utf-8', }, 'collect': { 'level': 'INFO', 'class': 'logging.handlers.RotatingFileHandler', # 保存到文件,自動切 'filename': os.path.join(BASE_LOG_DIR, "xxx_collect.log"), 'maxBytes': 1024 * 1024 * 50, # 日誌大小 50M 'backupCount': 5, 'formatter': 'collect', 'encoding': "utf-8" } }, 'loggers': { # 默認的logger應用以下配置 '': { 'handlers': ['default', 'console', 'error'], # 上線以後能夠把'console'移除 'level': 'DEBUG', 'propagate': True, }, # 名爲 'collect'的logger還單獨處理 'collect': { 'handlers': ['console', 'collect'], 'level': 'INFO', } }, }