@(Django)[筆記](méi)
django 項(xiàng)目手動(dòng)刪除數(shù)據(jù)庫(kù)表后重新同步出錯(cuò)的問(wèn)題解決辦法
http://blog.csdn.net/runner__1/article/details/74171979
python manage.py sqlmigrate your_app_name 0001
把your_app_name換成自己的app名字,0001是you_app_name/migrations目錄下的記錄,執(zhí)行即可看到框架自動(dòng)生成的創(chuàng)建表sql語(yǔ)句
目錄
一、模板(Templates)進(jìn)階
1.1 模板繼承
1.2 自定義filter 和simple_tag
二、ORM 進(jìn)階
2.1 將數(shù)據(jù)庫(kù)引擎改為MySQL
2.2 創(chuàng)建表
2.2.1建立一對(duì)一的關(guān)系
2.2.2 建立一對(duì)多和多對(duì)多的關(guān)系
2.2.3 執(zhí)行命令
2.3 添加表記錄
2.3.1 普通字段插入數(shù)據(jù)
2.3.2 外鍵字段插入數(shù)據(jù)
2.3.3 多對(duì)多字段插入數(shù)據(jù)
2.3.4 解除多對(duì)多關(guān)系
2.3.5 通過(guò)web界面添加表記錄
2.4 查詢表記錄
all()
filter()
exclude()
values()
values_list()
order_by()
reverse()
distinct()
count()
exits()
get()
first()
last()
2.5 雙下線之單表查詢
http://www.cnblogs.com/yuanchenqi/articles/7552333.html
一、模板(Templates)進(jìn)階
1.1 模板繼承
網(wǎng)站模板的設(shè)計(jì),一般的,我們做網(wǎng)站有一些通用的部分,比如 導(dǎo)航,底部,訪問(wèn)統(tǒng)計(jì)代碼等等
nav.html, bottom.html, tongji.html
可以寫一個(gè) base.html 來(lái)包含這些通用文件(include)
<!DOCTYPE html>
<html>
<head>
<title>{% block title %}默認(rèn)標(biāo)題{% endblock %} - 自強(qiáng)學(xué)堂</title>
</head>
<body>
{% include 'nav.html' %}
{% block content %}
<div>這里是默認(rèn)內(nèi)容,所有繼承自這個(gè)模板的,如果不覆蓋就顯示這里的默認(rèn)內(nèi)容。</div>
{% endblock %}
{% include 'bottom.html' %}
{% include 'tongji.html' %}
</body>
</html>
注意:
block
中的title、content都是自定義的名字,也就是為{% block xxx %} {% endblock %}
包含的這一區(qū)域取一個(gè)名字,名字不能重復(fù)。
如果需要,寫足夠多的 block
以便繼承的模板可以重寫該部分,include
是包含其它文件的內(nèi)容,就是把一些網(wǎng)頁(yè)共用的部分拿出來(lái),重復(fù)利用,改動(dòng)的時(shí)候也方便一些,還可以把廣告代碼放在一個(gè)單獨(dú)的html中,改動(dòng)也方便一些,在用到的地方include進(jìn)去。其它的頁(yè)面繼承自 base.html
就好了,繼承后的模板也可以在 block 塊中 include 其它的模板文件。
比如我們的首頁(yè) home.html,繼承或者說(shuō)擴(kuò)展(extends)原來(lái)的 base.html
,可以簡(jiǎn)單這樣寫,重寫部分代碼(默認(rèn)值的那一部分不用改)
{% extends 'base.html' %} <!-- 必須寫在第一行 -->
{% block title %}歡迎光臨首頁(yè){% endblock %} <!-- 覆蓋base.html模板中的title區(qū)域 -->
{% block content %} <!-- 覆蓋base.html模板中的content區(qū)域 -->
{% include 'ad.html' %}
這里是首頁(yè),歡迎光臨
{% endblock %}
{{ block.super }}的用法
模板繼承,在做block
替換時(shí),如果你不想將基板(base.html)中的內(nèi)容覆蓋,而是將基板(base.html)中的內(nèi)容引用過(guò)來(lái),再加上新內(nèi)容,就需要用到{{ block.super }}
變量;如下:
基板(base.html)內(nèi)容如下:
<!DOCTYPE html>
<html>
<head>
<title>{% block title %}默認(rèn)標(biāo)題{% endblock %} - 自強(qiáng)學(xué)堂</title>
</head>
<body>
{% block content %}
<div>在子模板中引用此部分內(nèi)容</div>
{% endblock %}
</body>
</html>
子模板內(nèi)容如下:
{% extends 'base.html' %} <!-- 必須寫在第一行 -->
{% block title %}歡迎光臨首頁(yè){% endblock %} <!-- 覆蓋base.html模板中的title區(qū)域 -->
{% block content %}
{{ block.super }} <!--會(huì)將基板中block content中的div標(biāo)簽引用到這里-->
<p>這里是首頁(yè),歡迎光臨</p>
{% endblock %}
最終展示到瀏覽的文件內(nèi)容如下:
<!DOCTYPE html>
<html>
<head>
<title>歡迎光臨首頁(yè) - 自強(qiáng)學(xué)堂</title>
</head>
<body>
<div>在子模板中引用此部分內(nèi)容</div>
<p>這里是首頁(yè),歡迎光臨</p>
</body>
</html>
特別關(guān)注的點(diǎn)
注意:模板一般放在app下的templates中,Django會(huì)自動(dòng)去這個(gè)文件夾中找。但 假如我們每個(gè)app的templates中都有一個(gè) index.html,當(dāng)我們?cè)趘iews.py中使用的時(shí)候,直接寫一個(gè) render(request, 'index.html'),Django 能不能找到當(dāng)前 app 的 templates 文件夾中的 index.html 文件夾呢?(答案是不一定能,有可能找錯(cuò))
Django 模板查找機(jī)制: Django 查找模板的過(guò)程是在每個(gè) app 的 templates 文件夾中找(而不只是當(dāng)前 app 中的代碼只在當(dāng)前的 app 的 templates 文件夾中找)。各個(gè) app 的 templates 形成一個(gè)文件夾列表,Django 遍歷這個(gè)列表,一個(gè)個(gè)文件夾進(jìn)行查找,當(dāng)在某一個(gè)文件夾找到的時(shí)候就停止,所有的都遍歷完了還找不到指定的模板的時(shí)候就是 Template Not Found (過(guò)程類似于Python找包)。這樣設(shè)計(jì)有利當(dāng)然也有弊,有利是的地方是一個(gè)app可以用另一個(gè)app的模板文件,弊是有可能會(huì)找錯(cuò)了。所以我們使用的時(shí)候在 templates 中建立一個(gè) app 同名的文件夾,這樣就好了。
這就需要把每個(gè)app中的 templates 文件夾中再建一個(gè) app 的名稱,僅和該app相關(guān)的模板放在 app/templates/app/ 目錄下面,
例如:項(xiàng)目 zqxt 有兩個(gè) app,分別為 tutorial 和 tryit
zqxt ├── tutorial │ ├── __init__.py │ ├── admin.py │ ├── models.py │ ├── templates │ │ └── tutorial │ │ ├── index.html │ │ └── search.html │ ├── tests.py │ └── views.py ├── tryit │ ├── __init__.py │ ├── admin.py │ ├── models.py │ ├── templates │ │ └── tryit │ │ ├── index.html │ │ └── poll.html │ ├── tests.py │ └── views.py ├── manage.py └── zqxt ├── __init__.py ├── settings.py ├── urls.py └── wsgi.py
這樣,使用的時(shí)候,模板就是 "tutorial/index.html" 和 "tryit/index.html" 這樣有app作為名稱的一部分,就不會(huì)混淆。
1.2 自定義filter 和simple_tag
- 在settings.py中的INSTALLED_APPS配置當(dāng)前app,不然django無(wú)法找到自定義的simple_tag.
- 在app中創(chuàng)建templatetags模塊(模塊名只能是templatetags),也就是在應(yīng)用中創(chuàng)建一個(gè)名叫templatetags的python包;
- 創(chuàng)建任意.py文件,如:my_tag.py,內(nèi)容如下:
from django import template
from django.utils.safestring import mark_safe
register = template.Library() #register的名字是固定的,不可改變
@register.filter #自定義過(guò)濾器必須加上這個(gè)裝飾器
def filter_multi(v1,v2):
return v1 * v2
#過(guò)濾器只能接收兩個(gè)參數(shù),simple_tag可以接收多個(gè)參數(shù)
@register.simple_tag
def simple_tag_multi(v1,v2,v3):
return v1 * v2 * v3
@register.simple_tag
def my_input(id,arg):
result = "<input type='text' id='%s' class='%s' />" %(id,arg,)
return mark_safe(result)
#mark_safe函數(shù)的功能和過(guò)濾器safe功能一樣,都是把html標(biāo)簽當(dāng)作標(biāo)簽渲染到頁(yè)面上,而不是當(dāng)作字符串
- 在使用自定義simple_tag和filter的html文件中導(dǎo)入之前創(chuàng)建的 my_tags.py
{% load my_tag %}
- 在html模板中使用simple_tag和filter(如何調(diào)用)
{% load my_tag %}
# num=12
{{ num|filter_multi:2 }} #24
{{ num|filter_multi:"[22,333,4444]" }}
{% simple_tag_multi 2 5 3 %} #參數(shù)不限,但不能放在if for語(yǔ)句中
{% simple_tag_multi num 5 %}
注意:filter可以用在if等語(yǔ)句后,simple_tag不可以
{% if num|filter_multi:30 > 100 %} {{ num|filter_multi:30 }} {% endif %}
二、ORM 進(jìn)階
2.1 將數(shù)據(jù)庫(kù)引擎改為MySQL
- settings.py配置
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 's18day18', #你的數(shù)據(jù)庫(kù)名稱
'USER': 'root', #你的數(shù)據(jù)庫(kù)用戶名
'PASSWORD': '', #你的數(shù)據(jù)庫(kù)密碼
'HOST': '', #你的數(shù)據(jù)庫(kù)主機(jī),留空默認(rèn)為localhost
'PORT': '3306', #你的數(shù)據(jù)庫(kù)端口
}
}
- 數(shù)據(jù)庫(kù)引擎更改
假設(shè)應(yīng)用的名稱為app01,修改app01的__init__.py
,即 app01/init.py
import pymysql
pymysql.install_as_MySQLdb()
如果想查看操作數(shù)據(jù)庫(kù)對(duì)應(yīng)的SQL語(yǔ)句,那么可以在settings.py中加入如下LOGGING
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'console':{
'level':'DEBUG',
'class':'logging.StreamHandler',
},
},
'loggers': {
'django.db.backends': {
'handlers': ['console'],
'propagate': True,
'level':'DEBUG',
},
}
}
接下來(lái)創(chuàng)建表
2.2 創(chuàng)建表
作者模型:一個(gè)作者有姓名和年齡。
作者詳細(xì)信息模型:把作者的詳情放到詳情表,包含生日,手機(jī)號(hào),家庭住址等信息。作者詳情模型和作者模型之間是一對(duì)一的關(guān)系(one-to-one)
出版商模型:出版商有名稱,所在城市以及email。
書籍模型: 書籍有書名和出版日期,一本書可能會(huì)有多個(gè)作者,一個(gè)作者也可以寫多本書,所以作者和書籍的關(guān)系就是多對(duì)多的關(guān)聯(lián)關(guān)系(many-to-many);一本書只應(yīng)該由一個(gè)出版商出版,所以出版商和書籍是一對(duì)多關(guān)聯(lián)關(guān)系(one-to-many)。
2.2.1建立一對(duì)一的關(guān)系
用models.OneToOneField(to="關(guān)聯(lián)表名")
建立一對(duì)一的關(guān)系
from django.db import models
class Author(models.Model):
nid = models.AutoField(primary_key=True)
name=models.CharField( max_length=32)
age=models.IntegerField()
# 與AuthorDetail建立一對(duì)一的關(guān)系
authorDetail=models.OneToOneField(to="AuthorDetail")
class AuthorDetail(models.Model):
nid = models.AutoField(primary_key=True)
birthday=models.DateField()
telephone=models.BigIntegerField()
addr=models.CharField( max_length=64)
2.2.2 建立一對(duì)多和多對(duì)多的關(guān)系
建立一對(duì)多:models.ForeignKey(to="Publish",to_field="nid")
建立多對(duì)多:models.ManyToManyField(to='Author')
class Publish(models.Model):
nid = models.AutoField(primary_key=True)
name=models.CharField( max_length=32)
city=models.CharField( max_length=32)
email=models.EmailField()
class Book(models.Model):
nid = models.AutoField(primary_key=True)
title = models.CharField( max_length=32)
publishDate=models.DateField()
price=models.DecimalField(max_digits=5,decimal_places=2)
keepNum=models.IntegerField()
commentNum=models.IntegerField()
# 與Publish建立一對(duì)多的關(guān)系,外鍵字段建立在多的一方
publish=models.ForeignKey(to="Publish",to_field="nid")
# 與Author表建立多對(duì)多的關(guān)系,ManyToManyField可以建在兩個(gè)模型中的任意一個(gè),自動(dòng)創(chuàng)建第三張表
authors=models.ManyToManyField(to='Author')
2.2.3 執(zhí)行命令
python manage.py makemigrations
python manage.py migrate
2.3 添加表記錄
2.3.1 普通字段插入數(shù)據(jù)
方式一:
publish_obj=Publish(name="人民出版社",city="北京",email="renMin@163.com")
publish_obj.save() # 將數(shù)據(jù)保存到數(shù)據(jù)庫(kù)
方式二:
publish_obj=Publish.objects.create(name="人民出版社",city="北京",email="renMin@163.com")
方式三:
publish_obj=Publish.objects.create(**request.POST.dict())
返回值puhlish_obj是添加記錄的對(duì)象,也就是表中每個(gè)數(shù)據(jù),將其封裝成的一個(gè)對(duì)象。
2.3.2 外鍵字段插入數(shù)據(jù)
外鍵字段就是多對(duì)一字段
方式一:
基于對(duì)象的方式
publish_obj=Publish.objects.get(nid=1)
Book.objects.create(title="金瓶眉",publishDate="2012-12-12",price=665,pageNum=334,publish=publish_obj)
注意:是直接將對(duì)象賦值給Book類下的publish屬性,book_obj.publish是一個(gè)出版商對(duì)象
方式二:
直接賦值,這個(gè)值必須是關(guān)聯(lián)表已存在的
Book.objects.create(title="金瓶眉",publishDate="2012-12-12",price=665,pageNum=334,publish_id=1)
這是直接給數(shù)據(jù)庫(kù)book表中的publish_id字段賦值
2.3.3 多對(duì)多字段插入數(shù)據(jù)
#先創(chuàng)建一個(gè)book_obj書籍對(duì)象
book_obj=Book.objects.create(title="追風(fēng)箏的人",publishDate="2012-11-12",price=69,pageNum=314,publish_id=1)
#再創(chuàng)建兩個(gè)作者對(duì)象
author_yuan=Author.objects.create(name="yuan",age=23,authorDetail_id=1)
author_egon=Author.objects.create(name="egon",age=32,authorDetail_id=2)
#將兩個(gè)作者對(duì)象添加至authors里面,注意:authors是Book類下面的多對(duì)多定義的authors
book_obj.authors.add(author_egon,author_yuan)
# set()方法
#如果需要修改書籍的作者,比如將原來(lái)的author_egon和author_yuan換為author_alex、author_wu和author_oldboy,就需要用到**set()**方法了
book_obj.authors.set(author_alex,author_wu,author_oldboy) #這樣就可以直接覆蓋原有的作者對(duì)象了。
注意: book_obj.authors是作者對(duì)象的集合,里面包含多個(gè)作者對(duì)象。all()和set()方法還可以直接添加作者對(duì)象的id,也可以直接添加作者對(duì)象或者作者id的列表,假如作者id列表
author_ids=[1,2,3]
,添加可以這樣寫:book_obj.authors.all(author_ids)
,修改可以這樣寫:book_obj.authors.set(author_ids)
2.3.4 解除多對(duì)多關(guān)系
book_obj.authors.remove()
# 將某個(gè)特定的對(duì)象從被關(guān)聯(lián)對(duì)象集合中去除。還可以這樣用book_obj.authors.remove(*[])
book_obj.authors.clear()
#清空被關(guān)聯(lián)對(duì)象集合。
注意:對(duì)于所有類型的關(guān)聯(lián)字段,add()、create()、remove()和clear(),set()都會(huì)馬上更新數(shù)據(jù)庫(kù)。換句話說(shuō),在關(guān)聯(lián)的任何一端,都不需要再調(diào)用save()方法
2.3.5 通過(guò)web界面添加表記錄
編輯admin.py
from . import models
admin.site.register(models.Author)
admin.site.register(models.Publish)
# python manage.py createsuperuser
輸入賬號(hào)和密碼
# python manage.py runserver
瀏覽器訪問(wèn)
http://127.0.0.1:8000/admin
2.4 查詢表記錄
獲取QuerySet對(duì)象的方法
QuerySet是盛放model對(duì)象的集合(類似一個(gè)列表),每個(gè)model對(duì)象就是一條表記錄
all()
查詢所有數(shù)據(jù)
res=Book.objects.all()
# res結(jié)果<QuerySet [<Book: Book object>, <Book: Book object>, ...]
# 得到的結(jié)果是一個(gè)個(gè)對(duì)象,不直觀,可以在model中加入__str__方法,讓它返回某一個(gè)字段,這里讓它返回書名:
#例如:
class Book(models.Model):
...
title = models.CharField( max_length=32)
publishDate=models.DateField()
...
def __str__(self):
return self.title
#這時(shí)再查詢all(),返回的結(jié)果就是書名了
#<QuerySet [<Book: 俊友>, <Book: 基督山伯爵>, ...]
filter()
查詢符合過(guò)濾條件的記錄
#查詢書名是'俊友',并且價(jià)格為123的書
res=Book.objects.filter(title='俊友',price=123)
#res結(jié)果<QuerySet [<Book: 俊友>]>
#查詢價(jià)格小于100的書
res=Book.objects.filter(price__lt=100)
#res結(jié)果<QuerySet [<Book: 呼嘯山莊>, <Book: 威尼斯商人>,...]
exclude()
取反,篩選與條件不匹配的對(duì)象
#取價(jià)格不大于50的書
res=Book.objects.exclude(price__gt=50)
#res結(jié)果<QuerySet [<Book: 呼嘯山莊>, <Book: 圍城>,...]
values()
括號(hào)里面放字段,要顯示哪個(gè)字段就放在括號(hào)里,字段名稱要用引號(hào)包含,返回的結(jié)果是QuerySet[]中包含著字典
#獲取每本書的價(jià)格
res=Book.objects.values('price')
#res結(jié)果<QuerySet [{'price': Decimal('123.00')}, {'price': Decimal('111.00')}, ...]
#過(guò)濾價(jià)格大于300的書,顯示其價(jià)格
Book.objects.filter(price__gt=300).values('title','price')
#<QuerySet [{'price': Decimal('999.00'), 'title': '五穆遺書'}]>
values_list()
它與values()非常相似,它返回的是一個(gè)元組序列,values返回的是一個(gè)字典序列。
res=Book.objects.filter(price__gt=300).values_list('title','price')
#結(jié)果<QuerySet [('五穆遺書', Decimal('999.00'))]>
order_by()
對(duì)查詢結(jié)果排序,將查詢字段放在括號(hào)中,用引號(hào)包括。默認(rèn)是從小到大排序,要想從大到小排序,則需要在字段名前加一個(gè)負(fù)號(hào)“-”即可。
#正向按價(jià)格排序
res=Book.objects.filter(price__gt=280).order_by("price")
#返回排序
res=Book.objects.filter(price__gt=280).order_by("-price")
reverse()
對(duì)查詢結(jié)果反向排序
res=Book.objects.filter(price__lt=30).reverse()
distinct()
去重,從返回結(jié)果中剔除重復(fù)紀(jì)錄
#去除重復(fù)的publisher_id
res=Book.objects.values('publisher_id').distinct()
#結(jié)果<QuerySet [{'publisher_id': 1}, {'publisher_id': 2}, {'publisher_id': 3}, ...]
count()
返回?cái)?shù)據(jù)庫(kù)中符合條件的對(duì)象數(shù)量
#查詢價(jià)格大于250的書籍的數(shù)量
res=Book.objects.filter(price__gt=250).count()
#res結(jié)果是23
exits()
查詢?nèi)绻袛?shù)據(jù)就返回True,否則就返回False
#判斷是否有單價(jià)大于500的書
res=Book.objects.filter(price__gt=500).exists()
#res結(jié)果為True
獲取model對(duì)象的方法
也就是獲取某一條表記錄對(duì)象的方法
get()
返回與所給篩選條件相匹配的對(duì)象,返回結(jié)果有且只有一個(gè),如果符合篩選條件的對(duì)象超過(guò)一個(gè)或者沒(méi)有都會(huì)拋出錯(cuò)誤。
res=Book.objects.get(title='小婦人')
數(shù)據(jù)庫(kù)中有多個(gè)書名叫小婦人,所以拋出如下異常
MultipleObjectsReturned at /query/
get() returned more than one Book -- it returned 2!
過(guò)濾的條件只能獲取到一個(gè)對(duì)象時(shí),就不會(huì)報(bào)錯(cuò),如下:
res=Book.objects.get
#res結(jié)果:碧雪劍
first()
返回QuerySet中第一條表記錄對(duì)象
res=Book.objects.all().first()
#res結(jié)果:俊友
last()
返回QuerySet中的最后一條表記錄對(duì)象
res=Book.objects.all().last()
#res結(jié)果:老友記
2.5 雙下線之單表查詢
Person.objects.filter(name__exact="abc") 名稱嚴(yán)格等于 "abc" 的人
Person.objects.filter(name__iexact="abc") # 名稱為 abc 但是不區(qū)分大小寫,可以找到 ABC, Abc, aBC,這些都符合條件
Person.objects.filter(name__contains="abc") # 名稱中包含 "abc"的人
Person.objects.filter(name__icontains="abc") #名稱中包含 "abc",且abc不區(qū)分大小寫
Person.objects.filter(name__regex="^abc") # 正則表達(dá)式查詢
Person.objects.filter(name__iregex="^abc") # 正則表達(dá)式不區(qū)分大小寫
Person.objects.filter(id__lt=10, id__gt=1) # 獲取id大于1 且 小于10的值
Person.objects.filter(id__in=[11, 22, 33]) # 獲取id等于11、22、33的數(shù)據(jù)
Person.objects.exclude(id__in=[11, 22, 33]) # not in
Person.objects.filter(id__range=[1, 2]) # 范圍bettwen and
__startswith #以什么字符開(kāi)頭
__istartswith #以什么字符開(kāi)頭,忽略大小寫
__endswith #以什么字符結(jié)尾
__iendswith #以什么字符結(jié)尾,忽略大小寫