django适当进阶篇
Django Form表单
django中的Form一般有两种功能:
输入html
验证用户输入
在项目中创建一个form文件

先写一个简单的forn:
1 2 3 4 5 6 7 | from django import formsfrom app01 import modelsclass 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 refrom django import formsfrom django.core.exceptions import ValidationErrordef 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 formsfrom app01 import modelsclass 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 renderfrom app01 import formsfrom app01 import modelsdef 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 modelsdef 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.pyclass 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 modelsdef 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_htmlclass 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.captionclass 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,HttpResponsefrom 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.hostnameclass 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.hostnameclass 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.usernameclass 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 Fmodels.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) |
浙公网安备 33010602011771号