django适当进阶篇
Django Form表单
django中的Form一般有两种功能:
输入html
验证用户输入
在项目中创建一个form文件
先写一个简单的forn:
1 2 3 4 5 6 7 | from django import forms from app01 import models class BookForm(forms.Form): #数据库中要有对应的字段,如title title = forms.CharField(max_length = 15 ) publication_date = forms.DateField() |
再写一个对应的视图:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | def book_form(request): form = forms.BookForm() if request.method = = 'POST' : form = forms.BookForm(request.POST) if form.is_valid(): form_data = form.cleaned_data #提取前端的数据 form_data[ 'publishers_id' ] = request.POST.get( 'publisher_id' ) #保存数据 book_obj = models.Book( * * form_data) book_obj.save() else : #form的错误信息 print (form.errors) publisher_list = models.Publisher.objects. all () return render(request, 'book_form.html' ,{ 'book_form' :form, 'publishers' :publisher_list}) |
最后写一个简单的模板:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | <!DOCTYPE html> <html lang = "en" > <head> <meta charset = "UTF-8" > <title>Title< / title> < / head> <body> <form action = " " method=" post">{ % csrf_token % } {{ book_form }} <select name = "publisher_id" > { % for publisher in publishers % } <option value = "{{ publisher.id }}" >{{ publisher.name }}< / option> { % endfor % } < / select> < input type = "submit" value = "创建图书" > < / form> < / body> < / html> |
一个更复杂的实例:
form:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | #!/usr/bin/env python # -*- coding:utf-8 -*- import re from django import forms from django.core.exceptions import ValidationError def mobile_validate(value): mobile_re = re. compile (r '^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$' ) if not mobile_re.match(value): raise ValidationError( '手机号码格式错误' ) class PublishForm(forms.Form): user_type_choice = ( ( 0 , u '普通用户' ), ( 1 , u '高级用户' ), ) user_type = forms.IntegerField(widget = forms.widgets.Select(choices = user_type_choice, attrs = { 'class' : "form-control" })) title = forms.CharField(max_length = 20 , min_length = 5 , error_messages = { 'required' : u '标题不能为空' , 'min_length' : u '标题最少为5个字符' , 'max_length' : u '标题最多为20个字符' }, widget = forms.TextInput(attrs = { 'class' : "form-control" , 'placeholder' : u '标题5-20个字符' })) memo = forms.CharField(required = False , max_length = 256 , widget = forms.widgets.Textarea(attrs = { 'class' : "form-control no-radius" , 'placeholder' : u '详细描述' , 'rows' : 3 })) phone = forms.CharField(validators = [mobile_validate, ], error_messages = { 'required' : u '手机不能为空' }, widget = forms.TextInput(attrs = { 'class' : "form-control" , 'placeholder' : u '手机号码' })) email = forms.EmailField(required = False , error_messages = { 'required' : u '邮箱不能为空' , 'invalid' : u '邮箱格式错误' }, widget = forms.TextInput(attrs = { 'class' : "form-control" , 'placeholder' : u '邮箱' })) ''' def __init__(self, *args, **kwargs): super(SampleImportForm, self).__init__(*args, **kwargs) self.fields['idc'].widget.choices = models.IDC.objects.all().order_by('id').values_list('id','display') self.fields['business_unit'].widget.choices = models.BusinessUnit.objects.all().order_by('id').values_list('id','name') Forms ''' |
视图:
1 2 3 4 5 6 7 8 9 10 | def test_form_view(request): if request.method = = 'POST' : request_form = PublishForm(request.POST) if request_form.is_valid(): request_dict = request_form.clean() print (request_dict) return render(request, 'test.html' , { 'pub_form' :request_form}) else : pub_form = PublishForm() return render(request, 'test.html' ,{ 'pub_form' :pub_form}) |
模板:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | < div > < form method = "post" action = "{% url 'test_form' %}" >{% csrf_token %} < div >{{ pub_form.user_type }} {{ pub_form.errors.title }}</ div > < div >{{ pub_form.title }}</ div > < div >{{ pub_form.email }}</ div > < div >{{ pub_form.phone }}</ div > < div >{{ pub_form.memo }}</ div > {% if pub_form.errors %} {{ pub_form.errors }} {% endif %} < input type = "submit" value = "提交" > </ form > </ div > |
ModelForm
Form文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | from django import forms from app01 import models class BookModelForm(forms.ModelForm): class Meta: #写一个原类 model = models.Book #关联的表 exclude = () #什么字段都显示 #fields = ('titile') #只显示title字段 #添加样式 widgets = { 'title' : forms.TextInput(attrs = { 'class' : 'form-control' }), } |
对应的视图文件:
1 2 3 4 5 6 7 8 9 10 11 12 | from django.shortcuts import render from app01 import forms from app01 import models def book_modelform(request): form = forms.BookModelForm() if request.method = = 'POST' : form = forms.BookModelForm(request.POST) #表单验证 if form.is_valid(): #最牛逼的保存 form.save() return render(request, 'book_modelform.html' ,{ 'book_form' :form,}) |
最后前端模板文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | <!DOCTYPE html> < html lang = "en" > < head > < meta charset = "UTF-8" > < title >Title</ title > < link href = "/static/css/bootstrap.css" rel = "stylesheet" > </ head > < body > < form action = "" method = "post" class = "form-control" > {% csrf_token %} {# < div >#} 分开写 {# {% for ele in book_form %}#} {# < div >{{ ele.name }}{{ ele }}{{ ele.errors }}</ div >#} {# {% endfor %}#} {# </ div >#} {{ book_form }} < input type = "submit" value = "创建图书" > </ form > < script src = "/static/js/jquery-2.2.3.js" ></ script > </ body > </ html > |
Django Admin
django amdin是django提供的一个后台管理页面,改管理页面提供完善的html和css,使得你在通过Model创建完数据库表之后,就可以对数据进行增删改查,而使用django admin 则需要以下步骤:
创建后台管理员
配置url
注册和配置django admin后台管理页面
1、创建后台管理员
1 | python manage.py createsuperuser |
2、配置后台管理url
1 | url(r '^admin/' , include(admin.site.urls)) |
3、注册和配置django admin 后台管理页面
a、在admin中执行如下配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | from django.contrib import admin # Register your models here. from app01 import models def make_forbidden(modelAdmin,request,queryset): queryset.update(status = 'forbidden' ) make_forbidden.short_description = 'set to forbidden' class BookAdmin(admin.ModelAdmin): #自定制admin list_display = ( 'id' , 'title' , 'publishers' , 'publication_date' , 'colored_status' ) #搜索 search_fields = ( 'title' , 'publishers__name' ) #publishers__name可以关联到另一个表 #过滤 list_filter = ( 'publishers' , 'publication_date' ) #可编辑 list_editable = ( 'title' , 'publishers' , 'publication_date' ) #分页 list_per_page = 10 filter_horizontal = ( 'authors' ,) raw_id_fields = ( 'publishers' ,) #动作 actions = [make_forbidden,] admin.site.register(models.Author) admin.site.register(models.Publisher) admin.site.register(models.Book,BookAdmin) #将上述类添加到这里 |
b、设置数据表名称
1 2 3 4 5 6 7 8 | #models.py class UserType(models.Model): name = models.CharField(max_length = 50 ) class Meta: #修改前端显示名字 verbose_name = '用户类型' verbose_name_plural = '用户类型' |
Admin 定制Action:
1 2 3 4 5 6 7 | from django.contrib import admin # Register your models here. from app01 import models def make_forbidden(modelAdmin,request,queryset): queryset.update(status = 'forbidden' ) make_forbidden.short_description = 'set to forbidden' |
其中queryset就是在前端选中的对象,在这个函数中可以对这个对象做操作。
1 2 3 | class BookAdmin(admin.ModelAdmin): actions = [make_forbidden,] admin.site.register(models.Book,BookAdmin) #将上述类添加到这里 |
在类中添加action动作后就可以在前端找到set to forbidden动作,就可以将状态变成forbidden
将前端显示的状态加一个样式:
models中加入:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | from django.utils.html import format_html class Book(models.Model): title = models.CharField(max_length = 100 ) authors = models.ManyToManyField(Author) publishers = models.ForeignKey(Publisher) publication_date = models.DateField() status_choices = (( 'published' ,u '已出版' ), ( 'producing' ,u '待出版' ), ( 'forbidden' ,u '禁书' ), ) status = models.CharField(choices = status_choices,max_length = 32 ,default = 'producing' ) def __str__( self ): return '<%s>' % ( self .title) #给前端添加样式 def colored_status( self ): if self .status = = "published" : format_td = format_html( '<span style="padding:2px;background-color:yellowgreen;color:white">已出版</span>' ) elif self .status = = "producing" : format_td = format_html( '<span style="padding:2px;background-color:pink;color:white">待出版</span>' ) elif self .status = = "forbidden" : format_td = format_html( '<span style="padding:2px;background-color:orange;color:white">禁书</span>' ) return format_td #将前端显示的名字变成status colored_status.short_description = 'status' |
在admin中添加一个status的字段:
前端显示效果如下:
常用ORM操作
一、一对多操作
models.py文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | from django.db import models # Create your models here. class UserType(models.Model): caption = models.CharField(max_length = 64 ) def __str__( self ): return self .caption class UserInfo(models.Model): user_type = models.ForeignKey(UserType) username = models.CharField(max_length = 64 ) age = models.IntegerField() def __str__( self ): return self .username |
增加操作:
view中对user_type添加三条数据
1 2 3 4 5 6 7 8 9 10 11 12 | from django.shortcuts import render,HttpResponse from app01 import models # Create your views here. def user_type(request): dic = { 'caption' : 'COO' } models.UserType.objects.create( * * dic) return HttpResponse( 'ok' ) def user_info(request): return HttpResponse( 'ok' ) |
数据库中是外键的字段的字段名称是这样的:xxx_id
所以添加user_info的数据方式一如下:
1 2 3 4 | def user_info(request): dic = { 'username' : 'xx' , 'age' : '88' , 'user_type_id' : '1' } models.UserInfo.objects.create( * * dic) return HttpResponse( 'ok' ) |
方式二,通过对象添加:
1 2 3 4 5 | dic = { 'username' : 'hetan' , 'age' : '25' , 'user_type' :models.UserType.objects.get( id = 1 )} models.UserInfo.objects.create( * * dic) result = models.UserInfo.objects. all () for item in result: print (item.username,item.age,item.user_type.caption) |
其中item.user_type就代指了user_type表的对象,在通过.就可以调用caption属性了
其效果为
删除和修改同增加
查询操作:
正向查询:ForeignKey在哪个表中通过这个表查询两个表的关联数据就是正向查询
反向查询:和正向相反,通过没有ForeignKey那个表查询就是反向查询
实例1,需求:UserType为CEO的所有数据
通过UserInfo正向查询:
1 2 3 | result = models.UserInfo.objects. filter (user_type__caption = 'CEO' ) for item in result: print (item.username,item.age) |
django的orm中的跨表查询要用到双下划线,例如上述代码中的user_type__caption,caption是另一张usertype表中的字段,从userinfo中
跨到usertype表中所以要写成user_type__caption。
通过UserType反向查询:
1 2 | line = models.UserType.objects.get( id = 1 ) print (line.userinfo_set. all ()) |
反向查询对象会有一个方法为另一张表名_set,这个方法就可以查询到另一张表的对象
还可以像这样:
1 2 | line = models.UserType.objects.get( id = 1 ) print (line.userinfo_set. filter (username = 'hetan' )) |
可以这样理解:
line.userinfo_set = model.UserInfo.objects.filter(user_type=line)
1 2 | line = models.UserType.objects.get(userinfo__username = 'hetan' ) print (line.userinfo_set. all ().count()) |
二、多对多操作
表结构如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | class Host(models.Model): hostname = models.CharField(max_length = 64 ) port = models.IntegerField() def __str__( self ): return self .hostname class HostAdmin(models.Model): username = models.CharField(max_length = 32 ) email = models.CharField(max_length = 32 ) host = models.ManyToManyField(Host) def __str__( self ): return self .username |
正向添加
1 2 3 4 5 6 7 8 | models.Host.objects.create(hostname = 'c1' ,port = 80 ) models.Host.objects.create(hostname = 'c2' ,port = 80 ) models.Host.objects.create(hostname = 'c3' ,port = 80 ) models.HostAdmin.objects.create(username = 'root' ,email = '1@163.com' ) models.HostAdmin.objects.create(username = 'mysql' ,email = '1@163.com' ) models.HostAdmin.objects.create(username = 'nginx' ,email = '1@163.com' ) models.HostAdmin.objects.create(username = 'ssh' ,email = '1@163.com' ) |
1 2 3 | admin_obj = models.HostAdmin.objects.get(username = 'root' ) host_list = models.Host.objects.filter(id__lt = 3 ) admin_obj.host. add ( * host_list) |
反向添加
1 2 3 | host_obj = models.Host.objects.get( id = 3 ) admin_list = models.HostAdmin.objects. filter (id__gt = 1 ) host_obj.hostadmin_set.add( * admin_list) |
自定义第三张表
表结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | class Host1(models.Model): hostname = models.CharField(max_length = 64 ) port = models.IntegerField() def __str__( self ): return self .hostname class HostAdmin1(models.Model): username = models.CharField(max_length = 32 ) email = models.CharField(max_length = 32 ) host = models.ManyToManyField(Host,through = 'HostRelation' ) def __str__( self ): return self .username class HostRelation(models.Model): c1 = models.ForeignKey(Host1) c2 = models.ForeignKey(HostAdmin1) |
through
=
'HostRelation'表示要自己定义第三张表,并且可以自定义添加字段
1 2 3 4 | models.HostRelation.objects.create( c1_id = 2 , c2_id = 1 ) |
正向查询
1 2 | admin_obj = models.HostAdmin.objects.get( id = 1 ) print (admin_obj.host. all ()) |
反向查询
1 2 | host_obj = models.Host.objects.get( id = 1 ) host_obj.hostadmin_set. all () |
自定义方式查询
1 2 3 4 | realtion_list = models.HostRelation.objects. all () for item in realtion_list: print (item.c1.hostname) print (item.c2.username) |
三、select_related
用于优化查询,一次将Forigkey全部加载到内存
四、F
需求:tb表中的age字段自加1
1 2 3 | from django.db.models import F models.tb.objects. all .update(age = F( 'age' ) + 1 ) sql语句 update tb set age = age + 1 ; |
五、Q
作用:条件查询
from
django.db.models
import
Q
Q是可以嵌套的
其中hostname这个地方可以跨表操作或__gt/__contins等,和filter中的操作是一样的。
这里应该是con
1 | models.Tb1.objects. filter (con) |