python学习笔记-Day19 -django(第一部分)

静态文件路径的设置

在开始的时候我们写静态文件的路径的时候,写的路径都是固定的路径

如果这样的话,如果静态文件的路径发生变化的时候,我们就需要修改很多文件的静态文件的路径

最开始的代码如下

<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

 

注意:

获取数据的时候使用 点 .

跨表查询的时候,需要使用双下划线 __

 







你可能感兴趣的:(python,django,models)