静态文件路径的设置
在开始的时候我们写静态文件的路径的时候,写的路径都是固定的路径
如果这样的话,如果静态文件的路径发生变化的时候,我们就需要修改很多文件的静态文件的路径
最开始的代码如下
<script src="/static/js/jquery-2.1.4.min.js"></script>
第一种方式:
将static 修改为变量
<script src="{{ STATIC_URL }}js/jquery-2.1.4.min.js"></script>
在django1.9中我们需要修改setting.py,添加一条语句
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',
'django.core.context_processors.static', #需要添加
],
},
},
]
注意:
{{ STATIC_URL }}的 值 为setting.py中的
STATIC_URL = '/static/'
第二种方式:
在html文件中设置
在html文件头
{% load staticfiles %}
......
<script src="{% static 'js/jquery-2.1.4.min.js'%}"></script>
第二种方式 不需要再setting.py中设置'django.core.context_processors.static',
############################################
小技巧
在写form表单的时候
如果没有写action ,默认会提交到本地
如果写action 值两边需要有/ ,
<form action="/login/" method="post"></form>
#########################
在提交表单的时候,比如,如果用户需要登录,当用户输入密码错误的时候,我们是不是需要用户再次输入一下用户名,不需要用户重复输入用户名 的体验显然更好一些。
我们先看代码
views/account.py
from django.shortcuts import render from app01.forms import account as accountForm def login(request): obj = accountForm.loginForm(request.POST) #关键01 if request.method=="POST": return render(request,"account/login.html",{"obj":obj}) return render(request,"account/login.html",{"obj":obj})
forms/account.py
from django import forms class loginForm(forms.Form): username = forms.CharField() password = forms.CharField(widget=forms.PasswordInput())
templates/account/login.html
<form action="/login/" method="post"> <p>{{ obj.username }}</p> <p>{{ obj.password }}</p> <input type="submit"> </form>
关键01
obj = accountForm.loginForm(request.POST)
这里将请求来的数据,封装到了obj对象中。此时。obj对象不仅可以用于验证,也可以将提交的数据再次显示在页面中。
##########################################################################
form 验证和错误信息
form表单提交时 的错误提示
部分代码如下:
views/account.py
def login(request): obj = accountForm.loginForm(request.POST) if request.method=="POST": if obj.is_valid(): all_data = obj.clean() else: error = obj.errors # 原始数据 需要记住 ,用于form的提交 # 这里的error 是一个Errorlist #参考上面的代码:error中也包含username,password # print type(error) # print error["username][0] # print error["password][0] # error = obj.errors.as_json() # json数据 需要记住 用户ajax # error = obj.errors.as_ul() #生成一个 <ul><li></li>...</ul> ,几乎不用 # error = obj.errors.as_data() # error = obj.errors 两种一样 ,原生数据 return render(request,"account/login.html",{"obj":obj,"error":error}) return render(request,"account/login.html",{"obj":obj})
app01/templatetags/custag.py #这里定了custom tag
from django import template register = template.Library() @register.simple_tag def err_msg(error_list): if error_list: return error_list[0] return ""
template/account/login.html
<form action="/login/" method="post"> <p>{{ obj.username }} <span>{% err_msg error.username %}</span> </p> <p>{{ obj.password }} <span>{{ error.password }}</span></p> <input type="submit"> </form>
注意:
对于ajax
error = obj.errors.as_json()
这里的error返回的是一个序列化的字典:
views/account.py
if request.method=="POST": if obj.is_valid(): all_data = obj.clean() else: error = obj.errors # 原始数据 需要记住 ,用于form的提交 return HttpResponse(error)
template/account/login.html
<form action="/login/" method="post"> <p>{{ obj.username }} <span>{% err_msg error.username %}</span> </p> <p>{{ obj.password }} <span>{{ error.password }}</span></p> <input type="submit" value="submit"> <input type="button" value="ajax" onclick="ajaxSubmit();"> </form> <script> function ajaxSubmit(){ $.ajax({ url:"/login/" type:"POST" data:{"username":"","password":""} }); } </script>
############################
生成select标签
有的时候我们需要用户 录入数据的时候使用固定的集中类型,比如地区,用户类型等,
这个时候就要用到select标签
实现代码如下:(记得配置url)
forms/home.py
from django import forms class importForm(forms.Form): HOST_TYPE= ( (1,"AAA"), (2,"BBB"), (3,"CCC"), ) host = forms.CharField() host_type = forms.IntegerField( widget=forms.Select(choices=HOST_TYPE) )
views/home.py
from django.shortcuts import render from app01.forms import home as HomeForm def index(request): obj = HomeForm.importForm() return render(request,"home/index.html",{"obj":obj})
home/index.html
<form action="/index/"> <p>{{ obj.host }}</p> <p>{{ obj.host_type }}</p> </form>
我们考虑一个问题,有的时候我们设置的类型可能会有变化,但是我们上面的代码并不能实时的进行改变,如果此时我们修改HOST_TYPE元组,然后去刷新页面会发现select标签的数据并未改变。
当我们从文件或者数据库 读取配置的时候,无法确定文件或者数据库的内容是否已经改变。
HOST_TYPE这里可设置为从文件或者数据库读取的数据
我们来看一下数据不能实时刷新的原因。
首先 ,我们 写了一个 importForm 类,当我们执行 obj = HomeForm.importForm() 的时候,importForm被实例化, 在实例化的时候,会执行类的__init__方法 ,HOST_TYPE 属于类的静态字段,静态字段属于类且 加载到内存后就不在改变(静态字段只在第一次加载类的时候被执行,加载到内存后,多个实例可以共享类的静态字段),这个类就被加载到了内存。 当我们修改HOST_TYPE的时候,类并不会 向内存中重新加载一次, 所以在我们执行了obj = HomeForm.importForm() 之后,我们刷新页面,并不会再次执行该语句,而是从内存中读取已经存在的obj对象,数据也就不会改变。
如果要每次都获取最新的数据,我们就要每次都对HOST_TYPE 进行一次读取。而类每次被实例化的时候都要执行__init__方法 ,所以我们只要将HOST_TYPE 放入__init__方法即可。
实现如下,修改importForm 类
from django import forms class importForm(forms.Form): host = forms.CharField() host_type = forms.IntegerField( widget=forms.Select() ) def __init__(self,*args,**kwargs): super(importForm,self).__init__(*args,**kwargs) HOST_TYPE= ( (1,"AAA"), (2,"BBB"), (3,"CCC"), (4,"DDD"), ) self.filed["host_type"].wdiget.choices = HOST_TYPE
每次实例化importForm类的时候 ,都执行一次__init__方法,我们就保证了每次都读取到最新的值。
###################################################
models
django操作数据库都是通过models进行的,models 会自动帮我们闯将sql语句,所以我们不用关心底层使用的是哪一种数据库,无论是mysq还是sqlite 或者其他数据库,我们使用models就可以实现想要的操作。
我们创建的应用app01 下包含一个models.py ,我们在这里就可以。
我们知道django的model 也是一个ORM,我们创建的类就等价于数据库的表,实例化类生成的对象就是一条数据。 对象.id 等就是每行的数据.
model中的字段
1、models.AutoField 自增列 = int(11) 如果没有的话,默认会生成一个名称为 id 的列,如果要显示的自定义一个自增列, 必须将给列设置为主键 primary_key=True。 2、models.CharField 字符串字段 必须 max_length 参数 3、models.BooleanField 布尔类型=tinyint(1) 不能为空,Blank=True 4、models.ComaSeparatedIntegerField 用逗号分割的数字=varchar 继承CharField,所以必须 max_lenght 参数 5*、models.DateField 日期类型 date 对于参数,auto_now = True 则每次更新都会更新这个时间; auto_now_add 则只是第一次创建添加,之后的更新不再改变。 6、models.DateTimeField 日期类型 datetime 同DateField的参数 7、models.Decimal 十进制小数类型 = decimal 必须指定整数位max_digits和小数位decimal_places 8、models.EmailField 字符串类型(正则表达式邮箱) =varchar 对字符串进行正则表达式 9、models.FloatField 浮点类型 = double 10、models.IntegerField 整形 11、models.BigIntegerField 长整形 integer_field_ranges = { 'SmallIntegerField': (-32768, 32767), 'IntegerField': (-2147483648, 2147483647), 'BigIntegerField': (-9223372036854775808, 9223372036854775807), 'PositiveSmallIntegerField': (0, 32767), 'PositiveIntegerField': (0, 2147483647), } 12、models.IPAddressField 字符串类型(ip4正则表达式) 13、models.GenericIPAddressField 字符串类型(ip4和ip6是可选的) 参数protocol可以是:both、ipv4、ipv6 验证时,会根据设置报错 14、models.NullBooleanField 允许为空的布尔类型 15、models.PositiveIntegerFiel 正Integer 16、models.PositiveSmallIntegerField 正smallInteger 17、models.SlugField 减号、下划线、字母、数字 18、models.SmallIntegerField 数字 数据库中的字段有:tinyint、smallint、int、bigint 19、models.TextField 字符串=longtext 20、models.TimeField 时间 HH:MM[:ss[.uuuuuu]] 21、models.URLField 字符串,地址正则表达式 22、models.BinaryField 二进制 23、models.ImageField 图片 24、models.FilePathField 文件
字段的参数
1、null=True 数据库中字段是否可以为空 2、blank=True django的 Admin 中添加数据时是否可允许空值 3、primary_key = False 主键,对AutoField设置主键后,就会代替原来的自增 id 列 4、auto_now 和 auto_now_add auto_now 自动创建---无论添加或修改,都是当前操作的时间 auto_now_add 自动创建---永远是创建时的时间 5、choices GENDER_CHOICE = ( (u'M', u'Male'), (u'F', u'Female'), ) gender = models.CharField(max_length=2,choices = GENDER_CHOICE) 6、max_length 设置最大长度 7、default 默认值 8、verbose_name Admin中字段的显示名称 9、name|db_column 数据库中的字段名称 10、unique=True 不允许重复 11、db_index = True 数据库索引 12、editable=True 在Admin里是否可编辑 13、error_messages=None 错误提示 14、auto_created=False 自动创建 15、help_text 在Admin中提示帮助信息 16、validators=[] 自定义验证,类似于form自定义验证 17、upload-to 指定上传路径
创建models
app01/models.py
# -*- coding:utf-8 -*- from django.db import models # Create your models here. class userInfo(models.Model): name = models.CharField(max_length=22) mtime = models.DateTimeField(auto_now=True) #修改时间 ctime = models.DateTimeField(auto_now_add=True) #创建时间 def __unicode__(self): return self.name #输出对象时,输出name列
在shell中执行如下两句
python manage.py makemigrations
python manage.py migrate
views/home.py
def index(request): before = models.userInfo.objects.all() #返回一个集合 obj = HomeForm.importForm() after = models.userInfo.objects.all() return render(request,"home/index.html",{"obj":obj})
小插曲:上传文件
views.home.py
def upload(request): if request.method=="POST": # inp_post = request.POST inp_files = request.FILES file_obj = inp_files.get("myfile_name") print file_obj.name #获取文件名 print file_obj.size # 获取文件大小 f=open("filename","wb") for data in file_obj.chunks(): f.write(data) f.close() return render(request,'home/upload.html')
home/upload.html
<form action="/upload/" method="post" enctype="multipart/form-data"> # 上传文件时 需要设置 enctype <input type="file" name="myfile_name"> <input type="submit" value="upload"> </form>
models 操作
一对多: 其实就是给一个表创建外键约束:
表一:颜色表 color表
id color
1 red
2 gray
3 blue
表二:球表 ball
id size color
1 10 2
2 20 3
3 10 1
表二的color;列对应表一的id列
创建表
class myColor(models.Model): color = models.CharField(max_length=16) class ball(models.Model): size = models.IntegerField() color = models.ForeignKey('myColor') #生成的列名为 color_id
默认情况下 id 列会自动生成
在shell中执行如下两句
python manage.py makemigrations
python manage.py migrate
创建成功后 ,如果我在向ball表插入数据的时候,ball表的color列的值 就必须是myColor表中存在的值
注意:
models.ForeignKey('myColor',to_field="id")
在创建外键约束的时候,如果要使用指定的字段作为外键,可以使用to_filed 来指定使用的列
应用场景:
当表A中创建数据时,该列的值是另外一张表中的数据的值,(可重复选择)
多对多
适用场景:
举例说明
公司里有N个人 分了M个组 ,每个人可以加入多个组;
这个时候就会出现一种情况
某个人属于多个组 ,每个组有多个人
表一: user_table
username age
alex 18
rain 16
ming 19 female
表二:group_table
groupname
CEO
CTO
CFO
如果在数据库中 ,我们需要建立第三张表 来连接两张表的关系
表san gather_table
username group
alex CEO
alex CFO
rain CEO
ming CTO
rain CTO
而在models中
我们进行如下操作即可
class group_table(models.Model): groupname = models.CharField(max_length=20) class user_table(models.Model): username = models.CharField(max_length=20) age = models.IntegerField() user_group = models.ManyToManyField("group_table")
models生成的第三张表,会出现三列,如下:
id user_table_id group_table_id
一对一:
这种情况是在一对多基础上做的,参考上面的一对多,
class myColor(models.Model): color = models.CharField(max_length=16) class ball(models.Model): size = models.IntegerField() color = models.ForeignKey('myColor') #生成的列名为 color_id
如果myColor表的值 在ball表中不能重复 ,这就是一对一。
修改后的代码为
class myColor(models.Model): color = models.CharField(max_length=16) class ball(models.Model): size = models.IntegerField() color = models.OneToOneField('myColor') #生成的列名为 color_id
假设myColor表中有三种颜色: red blue gray
设ball表为空表,我们想其中插入一条数据,颜色为red,那么在插入第二条数据的时候,可用的颜色就只有blue 和gray。
注意:
一对多 和 多对多 用的比较多
一对一 使用的相对来说少一些, 但是我们要知道三者之间的区别 及 如何实现
models 基本操作
基本操作
增加:
第一种方式:
models.table1.objects.create(col01='aa', col02='bb')
第二种方式:
obj = models.table1(col01='aa', col02='bb')
obj.save()
第三种方式:
dic = {'col01':'aa', 'col02':'bb'}
models.table1.objects.create(**dic) #form提交的数据 ,获取后为字典,可以用在这里
删除
models.table1.objects.filter(name='seven').delete()可以接受字典型参数,类似于增加的第三种方式
修改
第一种:
models.table1.objects.filter(name='seven').update(gender='0') 更新指定条件的数据,
可接受字典类型的参数
第二种:
obj = models.table1.objects.get(id=1)
obj.c1 = '111'
obj.save()
查询
获取单条数据:
models.table1.objects.get(id=123) 如果条id不存在的时候,django会报黄页,不推荐使用
获取全部数据
models.table1.objects.all()
获取符合条件的数据
models.table1.objects.filter(name='seven') 可以使用字典,类似于增加的第三种方式
获取第一条数据
models.table1.objects.all().first()
models.table1.objects.all().values() 获取结果 每一条数据为一个字典
models.table1.objects.all().values_list() 获取结果为元组(每条数据为一个元组)
可以用于select的choices
更多操作: 注意双下划线的使用
获取个数
models.Tb1.objects.filter(name='seven').count()
大小比较
models.Tb1.objects.filter(id__gt=1) 获取id大于1的值
models.Tb1.objects.filter(id__lt=10) 获取id小于10的值
models.Tb1.objects.filter(id__lt=10, id__gt=1) 获取id大于1 且 小于10的值
in 和 not in 操作
models.Tb1.objects.filter(id__in=[11, 22, 33]) in操作,获取id等于11、22、33的数据
models.Tb1.objects.exclude(id__in=[11, 22, 33]) not in操作
contains 操作
models.Tb1.objects.filter(name__contains="ven") 区分大小写
models.Tb1.objects.filter(name__icontains="ven") icontains不区分大小写
models.Tb1.objects.exclude(name__icontains="ven") 不包含操作
range操作
models.Tb1.objects.filter(id__range=[1, 20]) # 范围bettwen and
其他
startswith: 以指定字符串开头 ,区分大小写
istartswith: 以指定字符串开头 ,不区分大小写
endswith: 以指定字符串结尾 ,区分大小写
iendswith: 以指定字符串结尾 ,不区分大小写
order by操作
models.Tb1.objects.filter(name='seven').order_by('id') asc正序,默认
models.Tb1.objects.filter(name='seven').order_by('-id') # desc反序
limit 、offset 操作
models.Tb1.objects.all()[10:20] 分页的时候会用到
group by操作
from django.db.models import Count, Min, Max, Sum
models.Tb1.objects.all().values('id').annotate(c=Count('num'))
根据id进行分组,并增加一个字段c 计算 num的个数
###############################
连表操作 (注意双下划线的使用)
我们有如下两张表:
class myColor(models.Model): color = models.CharField(max_length=16) class ball(models.Model): size = models.IntegerField() color = models.ForeignKey('myColor')
创建数据:
第一种方式:
models.myColor.objects.create( color = "pink") color_obj = models.myColor.objects.get(color="pink") models.ball.objects.create(size=10,color= color_obj)
第二种方式:
models.myColor.objects.create(color="pink") models.ball.objects.create(size= 10,color_id= "pink")
注意: 第二种方式: 在models做连表操作的时候,ball类的color 关联了myColor类的 color ,ball中的color 为一个对象,对应的, 在数据库表中,ball表中的color列的名称为 color_id
###############################
val = request.POST["color"]
obj = models.ball.objects.filter(color__color= val)
color 这里的color是ball中的color
__color 这里的__color 是myColor中的color
注意:
获取数据的时候使用 点 .
跨表查询的时候,需要使用双下划线 __