Django创建一对多表结构
首先现在models.py中写如下代码:
from django.db import models
# Create your models here.
class Business(models.Model):
caption = models.CharField(max_length=32)
class Host(models.Model):
nid = models.AutoField(primary_key=True)
hostname = models.CharField(max_length=32,db_index=True)
ip = models.GenericIPAddressField(db_index=True)
port = models.IntegerField()
b = models.ForeignKey(to="Business",to_field="id")
这里有几个知识点:
1、b = models.ForeignKey(to="Business",to_field="id")
这里的to参数是表示和那个表创建外键关系
to_field参数表示和表中那个字段创建外键关系,如果不指定to_filed,默认则是与主键建立外键关系
2、同时关于ip地址格式在新版本中是:GenericIPAddressField
3、db_index=True设置索引
然后执行python manage.py makemigrations以及python manage.py migrate就可以在数据库中创建出表结构
这里有个问题需要注意:
如果在创建表结构后,你在Business表中添加了数据,并且这个时候你需要在Business中添加一列新的字段的时候,如将创建Business表结构的类改成如下:
class Business(models.Model):
caption = models.CharField(max_length=32)
code = models.CharField(max_length=32)
这样就比之前增加了一列字段code
如果不做其他设置,执行python manage.py makemigrations,这个时候会提示如下:
D:\python培训\Django_zi_host>python manage.py makemigrations
You are trying to add a non-nullable field 'code' to business without a default; we can't do that (the database needs something to populate existing rows).
Please select a fix:
1) Provide a one-off default now (will be set on all existing rows with a null value for this column)
2) Quit, and let me add a default in models.py
Select an option: 1
Please enter the default value now, as valid Python
The datetime and django.utils.timezone modules are available, so you can do e.g. timezone.now
Type 'exit' to exit this prompt
>>> "sa"
Migrations for 'app01':
app01\migrations\0002_business_code.py:
- Add field code to business
D:\python培训\Django_zi_host>python manage.py migrate
因为你的表中在添加code字段之前已经有了数据,所以当添加新的字段的时候你需要对之前已经有数据的数据行进行设置,这里选择1表示给之前已经有数据的行设置一个默认值,这里我全部设置为sa
另外可以通过将类中code字段的代码进行修改如下:
code =models.CharField(max_length=32,null=True,default="SA")
这样设置就表示code字段可以为空,并且给这个字段设置了一个默认值为SA
获取数据库数据的三种方式
三种方式为:
models.Business.objects.all()
models.Business.objects.all().values("id","caption")
models.Business.objects.all().values_list("id","caption")
在views.py中写如下代码:
from django.shortcuts import render
from app01 import models
# Create your views here.
def business(request):
v1 = models.Business.objects.all()
v2 = models.Business.objects.all().values("id","caption")
v3 = models.Business.objects.all().values_list("id","caption")
return render(request,"business.html",{"v1":v1,"v2":v2,"v3":v3})
在urls.py中写如下代码:
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^business$', views.business),
]
url(r'^business$', views.business),通过$,可以防止如果还有:
url(r'^business_add/', views.business),匹配不到,这通过$符号,解决此类问题,如果没有$符号,就只会匹配上面的business,而不会匹配下面的bussiness_add
在business.html中写如下代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>业务线列表(对象)</h1>
{{ v1 }}
<ul>
{% for row in v1 %}
<li>{{ row.id }}-{{ row.caption }}-{{ row.code }}</li>
{% endfor %}
</ul>
<h1>业务线列表(字典)</h1>
{{ v2 }}
<ul>
{% for row in v2 %}
<li>{{ row.id }}-{{ row.caption }}</li>
{% endfor %}
</ul>
<h1>业务线列表(元组)</h1>
{{ v3 }}
<ul>
{% for row in v3 %}
<li>{{ row.0}}-{{ row.1 }}</li>
{% endfor %}
</ul>
</body>
</html>
查看运行结果如下:
可以看出v1和v2以及v3其实都是QuerySet类型
区别在于:
v1中是QuerySet中存着每行数据的对象
v2中是QuerySet中存着数据对应的字典
v3中是QuerySet中存着数据对应的元组
这也是objects.all()、objects.all().values()、objects.all().values_list()的区别
一对多的跨表操作的三种方式
其实我们在建立ForeignKey的时候代码中:
class Host(models.Model):
nid = models.AutoField(primary_key=True)
hostname = models.CharField(max_length=32,db_index=True)
ip = models.GenericIPAddressField(db_index=True)
port = models.IntegerField()
b = models.ForeignKey(to="Business",to_field="id")
其实这个b就是另外一张表的Business表的对象,当我们在views.py中写host函数的时候,v1 = models.Host.objects.filter(nid__gt=0),这个时候我们可以知道v1是一个QuerySet,并且存着所有行数据的对象。
如果这个时候我们需要注意:如果我们通过for循环可以v1可以获得每行数据任意列的数据,但是这里host表中最后一列有点特殊
如果我们用如下代码:
for row in v1:
print(row.nid,row.hostname,row.port,row.ip,row.b_id,sep="\t")
我们知道数据库中host表的最后一别是b_id,所以我们可以通过row.b_id获得最后一列的值,我们也可以获取row.b,这样获取的就是一个对象,而这个对象就是Business表中一行数据的对象,同样的我们可以通过row.b.id、row.b.caption以及row.b.code,这就是跨表操作。
我们在views.py中添加如下代码:
def host(request):
v1 = models.Host.objects.filter(nid__gt=0)
return render(request,"host.html",{"v1":v1})
host.html代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>业务线列表</h1>
<table border="1">
<thead>
<tr>
<th>主机名</th>
<th>IP</th>
<th>端口</th>
<th>业务线id</th>
</tr>
</thead>
<tbody>
{% for row in v1 %}
<tr hid="{{ row.nid }}" bid="{{ row.b_id }}">
<td>{{ row.hostname }}</td>
<td>{{ row.ip }}</td>
<td>{{ row.port }}</td>
<td>{{ row.b.caption }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</body>
</html>
这里有个小知识需要注意:对于用户id以及Bussines表的id、code我们并不需要在页面上显示,但是用户id以及Bussines表的id是唯一的,后面可能需要获取,所以将这两个值作为了tr标签的属性,而code则不是必须的。最终页面的效果如下:
同时这里有一种跨表操作的方式:
当我们在host函数中:
v2 = models.Host.objects.filter(nid__gt=0).values("nid","hostname","b_id","b__caption")
这里我们注意到跨表操作的时候用了b__caption,这里其实无法用b.caption来跨表获取数据,所以这是也是双下划线的一种用法
最终代码如下:
host函数的代码:
def host(request):
v1 = models.Host.objects.filter(nid__gt=0)
v2 = models.Host.objects.filter(nid__gt=0).values("nid","hostname","b_id","b__caption")
v3 = models.Host.objects.filter(nid__gt=0).values_list("nid","hostname","b_id","b__caption")
return render(request,"host.html",{"v1":v1,"v2":v2,"v3":v3})
host.html代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>主机列表(对象)</h1>
{{ v1 }}
<table border="1">
<thead>
<tr>
<th>主机名</th>
<th>IP</th>
<th>端口</th>
<th>业务线id</th>
</tr>
</thead>
<tbody>
{% for row in v1 %}
<tr hid="{{ row.nid }}" bid="{{ row.b_id }}">
<td>{{ row.hostname }}</td>
<td>{{ row.ip }}</td>
<td>{{ row.port }}</td>
<td>{{ row.b.caption }}</td>
</tr>
{% endfor %}
</tbody>
</table>
<h1>主机列表(字典)</h1>
{{ v2 }}
<table border="1">
<thead>
<tr>
<th>主机名</th>
<th>业务线id</th>
</tr>
</thead>
<tbody>
{% for row in v2 %}
<tr hid="{{ row.nid }}" bid="{{ row.b_id }}">
<td>{{ row.hostname }}</td>
<td>{{ row.b__caption }}</td>
</tr>
{% endfor %}
</tbody>
</table>
<h1>主机列表(元组)</h1>
{{ v3 }}
<table border="1">
<thead>
<tr>
<th>主机名</th>
<th>业务线id</th>
</tr>
</thead>
<tbody>
{% for row in v3 %}
<tr hid="{{ row.0 }}" bid="{{ row.2 }}">
<td>{{ row.1 }}</td>
<td>{{ row.3 }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</body>
</html>
效果如下:
这里有个小知识点:
如果想要在表单的最左侧有个序号列,方法如下:
在模板语言中只有有for循环,里面就会有一个forloop
如果想要有一个需要直接添加forloop.counter,就可以了
这里有几个参数:
forloop.counter :表示从1开始计数
forloop.counter0:表示从0开始计数
forloop.first:如果是第一个则会会True,否则为False
forloop.last:如果是最后一个则会为True,否则为False
forloop.revcounter:将序号从大到小,最小为1
forloop.revcounter0:将序号从大到小,最小为0
forloop.parentloop:记录外层循环的层数
初识Ajax
通过jQuery可以调用Ajax,方式如下:
$("#ajax_submit").click(function () {
$.ajax({
url:"/test_ajax",
type:"POST",
data:{"hostname":$("#hostname").val(),"ip":$("#ip").val(),"port":$("#port").val(),"b_id":$("#sel").val()},
success: function(data) {
var obj = JSON.parse(data)
}
})
})
关于ajax参数的解释:
url:表示要传递数据的地址
type:表示传递的方式
data:表示要传递的数据
success:function{data}表示如果成功就会执行这个函数,这里的data是服务器返回的数据或者结果
这里JSON.parse将字典进行反序列化
一般情况,建议让服务器返回一个字典:
return HttpResponse(json.dumps(字典))
这里有个知识点需要注意:
$.ajax({
data:$("#edit_form").serialize()
})
data:$("#edit_form").serialize()这种方式就可以将form表单中的数据提交,而不用一个一个写了
Django创建多对多
这里有两种方式:
自定义关系表
代码例子如下:
class Business(models.Model):
caption = models.CharField(max_length=32)
code = models.CharField(max_length=32,null=True,default="SA")
class Host(models.Model):
nid = models.AutoField(primary_key=True)
hostname = models.CharField(max_length=32,db_index=True)
ip = models.GenericIPAddressField(db_index=True)
port = models.IntegerField()
b = models.ForeignKey(to="Business",to_field="id")
class Application(models.Model):
name = models.CharField(max_length=32)
class HostToApp(models.Model):
hobj = models.ForeignKey(to="Host",to_field="nid")
aobj = models.ForeignKey(to="Application",to_field="id")
自动创建关系表
代码例子如下:
class Host(models.Model):
nid = models.AutoField(primary_key=True)
hostname = models.CharField(max_length=32,db_index=True)
ip = models.GenericIPAddressField(db_index=True)
port = models.IntegerField()
b = models.ForeignKey(to="Business",to_field="id")
class Application(models.Model):
name = models.CharField(max_length=32)
r = models.ManyToManyField("Host")
如果是通过自动创建的则无法直接对第三张表进行操作,可以间接操作
例子如下:
obj = Application.objects.get(id=1)
obj.r.add(1) :表示创建Application表的id=1和host表中的id=1创建一个对应关系
obj.r.add(2) :表示创建Application表的id=1和host表中的id=1创建一个对应关系
obj.r.add(1,2,3,4):表示增加多个对应关系
obj.r.add(*[1,2,3,4]):表示增加多个对应关系
obj.r.remove(*[1,2,3,4]):表示删除多个对应关系
obj.r.clear():这样会删除Application中id=1的对应关系都会给清空
obj.r.set([3,5,7]):这样表示重置,将原有的关系删除,然后只有和3,5,7的对应关系
obj.r.all():这里获得是所有相关的主机对象的“列表”即QuerySet