python(Django之数据库操作一对多)
创建数据库表结构:
#资产管理表格属于的业务线 class Business(models.Model): #业务线字段(汉字类型) caption = models.CharField(max_length=64) #资产管理 class Assets(models.Model): #把nid这一列设置为主键 nid = models.AutoField(primary_key=True) #主机字段,创建索引 hostname = models.CharField(max_length=64,db_index=True) #设置为IP字段,(原models.IPAddressField在python3上已经更改为models.GenericIPAddressField) #protocol='',有两个参数,ipv4地址,或ipv6.默认是both(两种都支持) ip = models.GenericIPAddressField(protocol="ipv4",db_index=True) #设置为端口字段。 port = models.CharField(max_length=32)
#创建关联关系,跟Busioness数据库的id列做关联关系。
b = models.ForeignKey(to="Business",to_field="id")
生成数据库结构:
#找到这个项目的文件路径,并执行下面语句(也可以直接在pycharm里面的Terminal中执行) python manage.py makemigrations python manage.py migrate
那么我想半中腰想新加一个字段code怎么办?看下面
#资产管理表格属于的业务线 class Business(models.Model): #业务线字段(汉字类型) caption = models.CharField(max_length=64) #新加字段,null表示可以为空(null=True),或者设置默认写的是什么(default="Finance") code = models.CharField(max_length=64) #资产管理 class Assets(models.Model): #把nid这一列设置为主键 nid = models.AutoField(primary_key=True) #主机字段,创建索引 hostname = models.CharField(max_length=64,db_index=True) #设置为IP字段,(原models.IPAddressField在python3上已经更改为models.GenericIPAddressField) #protocol='',有两个参数,ipv4地址,或ipv6.默认是both(两种都支持) ip = models.GenericIPAddressField(protocol="ipv4",db_index=True) #设置为端口字段。 port = models.CharField(max_length=32)
#创建关联关系,跟Busioness数据库的id列做关联关系。
b = models.ForeignKey(to="Business",to_field="id")
如果就简单的写上
code = models.CharField(max_length=64)
当执行数据库生成的时候肯定会提示你下面信息。
它让你选择要不选择1,并设置你的新增字段的默认值(必须要用引号引起来),要不选择2退出。
其实我们都不用这么麻烦,上面我也写清楚了。要不写null表示可以为空(null=True),要不写上让它默认是什么default="Finance"。
D:\Python上课及作业\day22hw>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 >>> "Finance" Migrations for 'cmdb': cmdb\migrations\0003_business_code.py: - Add field code to business
D:\Python上课及作业\day22hw>python manage.py migrate
Operations to perform:
Apply all migrations: admin, auth, cmdb, contenttypes, sessions
Running migrations:
Applying cmdb.0003_business_code... OK
结果:

数据库数据的三种查法:
*使用上面的Business数据库
views中的写法:
def assets(request): now = time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time())) #QuerySet(查到的是QuerySet对象) v1 = models.Business.objects.all() #QuerySet(查到的是字典形式) v2 = models.Business.objects.values('id','caption','code') #QuerySet(查到的是元祖的形式) v3 = models.Business.objects.values_list('id','caption','code') return render(request,'assets.html',{'nowdate':now,"v1":v1,'v2':v2,'v3':v3})
前端页面写法:
<h1>业务线列表(对象)</h1>
<ul>
{% for row in v1 %}
<p>{{ row.id }}--{{ row.caption }}--{{ row.code }}</p>
{% endfor %}
</ul>
<br />
<h1>业务线列表(字典)</h1>
<ul>
{% for row in v2 %}
<p>{{ row.id }}--{{ row.caption }}--{{ row.code }}</p>
{% endfor %}
</ul>
<h1>业务线列表(元祖)</h1>
<ul>
{% for row in v3 %}
<p>{{ row.0 }}--{{ row.1 }}--{{ row.2 }}</p>
{% endfor %}
</ul>
坑一:
#如果使用get方式,如果id=1不存在会报错。 v4 = models.Business.objects.get(id=1) #如果使用下面的方法,就算没有id=1的数据,也不会报错。 v5 = models.Business.objects.filter(id=1).first()
一对多(增删改查)
查询(对象)(一):
def assets(request): now = time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time())) #gt表示大于,lt表示小于。大于等于gte,小于等于lte,写法跟下面相同 v4 = models.Assets.objects.filter(nid__gt=0) # v4 = models.Assets.objects.all() return render(request,'assets.html',{'nowdate':now,'v4':v4})
html文件(因为直接打印b字段的话,显示的是一个对象,所以使用的是row.b.关联关系表的字段名称)
<h1>业务线列表</h1> <ul> {% for row in v4 %} <p>{{ row.id }}--{{ row.hostname }}--{{ row.ip }}--{{ row.port }}--{{ row.b_nid }}--{{ row.b.caption }}--{{ row.b.code }}</p> {% endfor %} </ul>
查询(字典)(二):
神奇的下划线(注意python程序里面取值跟html取值方式不一样)
v5 = models.Assets.objects.values('nid','hostname','b_id','b__caption') for row in v5: print(row['nid'],row['hostname'],row['b_id'],row['b__caption']) return render(request,'assets.html',{'nowdate':now,'v5':v5})
html:
<h1>一对多查询(神奇的下划线)</h1> <ul> {% for row in v5 %} <p>{{ row.nid }}--{{ row.hostname }}--{{ row.b_id }}--{{ row.b__caption }}</p> {% endfor %} </ul>
查询(元祖)(三):
*注意
我们用神奇的下划线从数据库中只取到自己数据库的nid和hostname字段及关联关系的b_id(也就是b,只是数据库根据关联关系给我们生成了b_id),b__caption是业务线(跨表查询)
因为我们就从数据库里面查到了3个字段的数据,所以就是row[0-x]
v5 = models.Assets.objects.values_list('nid','hostname','b_id','b__caption') for row in v5: print(row[0],row[1],row[2],row[3]) return render(request,'assets.html',{'nowdate':now,'v5':v5})
html:
<h1>一对多查询((元祖)神奇的下划线)</h1> <ul> {% for row in v5 %} <p>{{ row.0 }}--{{ row.1 }}--{{ row.2 }}--{{ row.3 }}</p> {% endfor %} </ul> <br />
增加:
表结构:
#资产管理表格属于的业务线 class Business(models.Model): #业务线字段(汉字类型) caption = models.CharField(max_length=64) #新加字段,null表示可以为空(null=True),或者设置默认写的是什么(default="Finance") code = models.CharField(max_length=64,null=True) #资产管理 class Assets(models.Model): #把nid这一列设置为主键 nid = models.AutoField(primary_key=True) #主机字段,创建索引 hostname = models.CharField(max_length=64,db_index=True) #设置为IP字段,(原models.IPAddressField在python3上已经更改为models.GenericIPAddressField) #protocol='',有两个参数,ipv4地址,或ipv6.默认是both(两种都支持) ip = models.GenericIPAddressField(protocol="ipv4",db_index=True) #设置为端口字段。 port = models.CharField(max_length=32) #创建关联关系,跟Busioness数据库的id列做关联关系。 b = models.ForeignKey(to="Business",to_field="id")
前端html文件:
<form action="/cmdb/assets/" method="post"> {% csrf_token %} <div> <input type="text" placeholder="服务器名称" name="h"> </div> <div> <input type="text" placeholder="IP地址" name="ip"> </div> <div> <input type="text" placeholder="端口号" name="port"> </div> <div> <select name="b_id"> {% for row in v1 %} <option value="{{ row.id }}">{{ row.caption }}</option> {% endfor %} </select> </div> <span><input type="submit" value="提交"></span> <span><input id = quxiao type="button" value="取消"></span> </form>
views函数:
def assets(request): now = time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time())) if request.method == "GET": #QuerySet(查到的是QuerySet对象) v1 = models.Business.objects.all() #gt表示大于,lt表示小于。大于等于gte,小于等于lte,写法跟下面相同 v2 = models.Assets.objects.filter(nid__gt=0) return render(request,'assets.html',{'nowdate':now,"v1":v1,'v2':v2}) elif request.method == "POST": n = request.POST.get('h') i = request.POST.get('ip') po = request.POST.get('port') bid = request.POST.get('b_id') try: #因为我们没做form表单验证,所以这里先用try一下 #增加的时候涉及到跨表操作,我们知道ForeignKey这个字段关联了Business的id列(一一对应的关系) #所以我们只要拿到Business的id列的数字,并把它写入到b__id这列就行(神奇的下划线),减少了跨表操作。 models.Assets.objects.create(hostname=n,ip=i,port=po,b_id=bid) except: error = "数据不能为空" return redirect("/cmdb/assets")

浙公网安备 33010602011771号