【Django】Django 模型 使用指南

简介

Django的模型功能强大,更加重要的是ORM让你体验非凡(请跟着本文慢慢的体会ORM的强大之处)
因为研发部最近需要一个打卡器的数据库,那面我就简单谈谈Django的models。希望给研发部,以及之后想要使用一个简单易行方式来搭建一台网络服务器的小伙伴学习。
注意:这并不是一个正统的Django教学贴,默认大家已经入门了Django,如果没有请移步:自强学堂学习前五章!

面向对象

假定大家并没有过多的理解什么叫做面向对象。
所谓的面向对象编程,就是程序的最基本元素从函数或方法(针对C语言)到实例对象(C++ Python等语言)的转变。
我们从两方面来理解面向对象:

- 举个例子

比方说你要有一个函数,函数的输入是两个数,函数的功能是返回两个数的和
1.如果是C语言这很容易

int add(int a,int b){
    return a+b;
}

很容易对吧,这样每次我们只要调用就好了。
2.如果是Python呢? 实际上也可以这样去写,没问题。
但是如果是面向对象呢?
我们认为算加法这个行为是一个人能够做的,这样我们先定义’人类’

class People:
    #人类有个能力就是算加法
    def add(self, a, b):
        return a + b

但是对于人类来说,你并不能让他去算加法(因为人类是一个笼统的概念,或者说叫抽象的概念)
好吧,这要怎么办呢?
没错,既然所有的人类都能做加法,我们可以让具体的一个人类来做,对吧?
我们叫来了小明(为什么不是李华?因为李华只会写作文)

xiaoming = People()
print xiaoming.add(3, 4)

7
>>>

(这么多你居然就算个加法?!)

- 另外的例子

还记得在C语言中,我们处理一系列相关的变量的时候是怎么做的吧?
恩 struct!

typedef struct student{
    long num;
    string name;
    float score;
}Stu;

这是一个学生的结构体,里面存了学号,姓名,分数。
他们都是对应一个学生的吧?
是不是到这你突然有些想法了?
恩…你想的不错

class People:
    name = '' #there is no name
    age = 0

>>> xiaoming = People()
>>>xiaoming.name = 'lihua'
>>>xiaoming.age = 5
>>>print xiaoming.name 
lihua
>>>print xiaoming.age
5
>>> 

这样的话这个像不像一个结构体。
对的,结构体就是存储一个对象(C语言中没有这个概念)的相关属性变量,但是通过上面小明算加法的例子你能又了解到,一个类不单单有成员变量,还有成员方法!

这样我们又可以改变我们‘设计’的人类了
设计是这样的,人有左手和右手,如果在左、右手分别放上糖,人就可以告诉你他有几块糖,恩这样是不是更好玩?

#coding:utf-8
class People:
    name = ''
    left_hand = 0
    right_hand = 0
    #人类有个能力就是算加法
    def add(self):
        return str(self.left_hand + self.right_hand)

    def speak(self):
        #在这个例子里,人类的成员方法调用了自己的另一个成员方法!希望通过这里大家理解下每个成员方法形参里面的self是干啥用的
        return "I'm " + self.name + "! I have " + self.add() + " candies!"

xiaoming = People()
xiaoming.name = 'lihua'
xiaoming.left_hand = 1
xiaoming.right_hand = 3
print xiaoming.speak()
#-------------------------------------------执行结果
I'm lihua! I have 4 candies!
>>> 

这就叫做面向对象,当然这只是基本概念,关于继承,派生,多态等等的相关知识并没有过于详细的讲解,但是这些已经足够大家应付Django的ORM模型的理解了!

数据库的设计

因为是需要研发部的小伙伴背锅,所以举例子我都拿我物联网项目设计举例(如果那打卡器服务器举例的话,就相当于我在干活了)——3#如是说

对于一个用户,可以有多个鱼缸,一个鱼缸里可以有多种鱼
用一个图表示就是:

这里写图片描述

为了表达的简单,我会将我数据库进行简化

如此设计的数据库在models.py里是什么样的呢?


class User(models.Model):
    username = models.CharField(max_length = 16)

class fishTank(models.Model):
    Tid = models.IntegerField(default = 0)    #Tank's ID
    owner = models.ForeignKey(User)     #这是这个鱼缸的所有者,这样一个人就可以有很多鱼缸

#这代表一个鱼群,一个种类的鱼总是成群出现的,所以以群作为一个最小个体
class fishs(models.Model):    
    livein = models.ForeignKey(fishTank)  #这是这群鱼所生活的鱼缸
    fishKinds = models.CharField(max_length = 16, default = 'null')   #鱼种
    num  = models.IntegerField(default = 0)#这一种鱼养了几条

这样我们就快速建立上面图片的的一个数据库的结构
可以请注意因为一人对应多个鱼缸,一个鱼缸对应多种鱼,这里是简单的一对多的关系。不存在一个人有多个鱼缸,一个鱼缸又有多个主人,这种manytomany(多对多)的情况!
观察上面,我们是如何体现对应关系的呢?
没错就是在下一级存在指向其上一级的‘外键’(ForeignKey)
以鱼缸的主人为例:

owner = models.ForeignKey(User)

注意 这里指向的是User这个类(请结合上面 面向对象 的讲解)所以在实际应用的时候,我们需要传递应该是一个实例化的’用户‘

比方说:

u = User()
u.username = 'laomi'
u.save()

三行语句完成了在数据库当中建立了一个叫做’laomi’的用户

这时候我们建立两个鱼缸,这两个鱼缸是 laomi 的

其中设计数据的时候Tid是用来方便查询用的,(推荐大家采用这个设计!)

t1 = fishTank()
t1.Tid = 0
t1.owner = ( u ) #这里我们跟上面的那串建立用户的代码是处于一个文件
t1.save()

#建立第二个鱼缸
t2 = fishTank()
t2.Tid =1
t2,owner = User.objects.get(username = 'laomi') #这里是对于一个已经建立好用户 之后很久(久到不是在一个文件中创立的时候)我们从数据中查找‘laomi’用户再传递给owner这个外键
t2.save()

这样老米就有两个鱼缸了!

老米又在第一个鱼缸里面养了三种鱼,分别是:
小鲤鱼 10条
小龙鱼 5条
食人鱼 1条 (放心食人鱼只吃人,不吃其他的小鱼,这三种鱼能快乐的生活在一起)

因为跟第一步差不多我就直接简单写了

f1 = fishs()
f1.fishKinds = '小鲤鱼'
f1.livein = fishTank.objects.get(Tid = 0)
f1.num = 10
f1.save()

f2 = fishs()
f2.fishKinds = '小龙鱼'
f2.livein = fishTank.objects.get(Tid = 0)
f2.num = 5
f2.save()

f3 = fishs()
f3.fishKinds = '食人鱼'
f3.livein = fishTank.objects.get(Tid = 0)
f3.num = 1
f3.save()

不知不觉间,我们讲解了‘数据库’的第一种操作——增

老米很满意,心满意足的看着自己的鱼缸,可是老米的忘性很大,一回身的功夫老米居然忘记了自己一共买了多少条鱼!于是老米打算查一查自己一共养了几条鱼!

注意在这个 ‘查’之下老米是一口气操作完的,只不过我在中间给‘打断了’(一下的代码框们,是一段代码,只不过我中间的讲解给分成了几个框而已)
首先我们先请出老米出来,因为我们大家都知道老米养了多少条鱼,(不知道的往上面翻翻也知道了)
(在实例中,用户不可能只有老米一人)

u = User.objects.get(username = 'laomi')

问题来了,老米有两个鱼缸(尽管第二个鱼缸没有鱼),所以老米居然忘记了自己的鱼缸在哪,老米得先找到自己的两个鱼缸!

tanks = u.fishtank_set.all()

对于指向自己的外键,调用方式就是用这个实例‘点’指向他的类(这里不可能是实例,因为你不知道有多少指向他)的小写加下划线_set
如我们鱼缸类叫做fishTank,调用的时候就是fishtank_set ,之后的.all()用于取出所有对象!
这时tanks保存的就是一个’set’
老米找到了鱼缸们,知道了标号为0的鱼缸里面由鱼

t = tanks.get(Tid = 0)

鱼游得很快,以至于在光与影的特效之间,老米数不鱼有几条,老米很生气,决定觉得把所有的鱼都捞出来,然后慢慢查

 fishss = t.fishs_set.all()
 sum = 0
 for each in fishss:
     sum = sum + each.num
 print sum

这样老米就知道了自己有10+5+1= 16条鱼

这个‘改’也是跟着上面‘查’的操作!!!!
老米看看鱼,又看看鱼缸,感觉食人鱼有点少(只有一条),于是老米又放了两条进去

f = fishss.get(findKinds = '食人鱼')
f.num = 3
f.save()  #注意更改保存啊

这个‘删’也是跟着上面‘查’‘改’的操作!!!!

老米很高兴,给鱼喂了食之后就上班了.
然而事情会这么简单么?
老米刚刚多养了两条食人鱼,但是还是按照1条鱼喂的食
虽然食人鱼不吃其他小鱼,但是它很饿,于是小龙鱼全部被吃光了!

fishss.filter(findKinds = '小龙鱼').delete()

吃了小龙鱼还不够,又吃了小鲤鱼

f = fishss.filter(findKinds = '小鲤鱼').get()
t.remove(f)

这里注意下filter 与 get的区别和联系,filter用于在一个set中(好多鱼的集合),根据条件进行筛选,(可以多条件)。而get是用来得到实例化对象的,当get的条件,对应多个对象时,程序就会报错!

老米回家之后很伤心决定不再养鱼
小伙伴们?老米需要怎样的一顿操作才能把两个鱼缸扔掉?


结语,这篇文章集合了数据库的“增删改查”四大基本操作,同学们有没有发现,在ORM下本来枯燥的SQL语言(回一下战老师的大学计算机数据库一章)也变得格外生动,这就是面向对象的魅力!(什么?没有对象?你有‘类’么?没有‘类’,赶紧感觉create一个!(这是Java创建实例的方法))
研发部的小伙伴相信对照着这篇blog,能够搭建一个良好的猎狐打卡数据库,以便我们开发出更多的猎狐玩法,希望用咱们的设备,进行的玩法能够叫做“标准BY2HIT玩法”!

BY2HIT——让世界听见我们的声音
posted @ 2017-07-13 15:16  ArtisticZhao  阅读(142)  评论(0编辑  收藏  举报