Django 框架 数据库操作
數據庫與ORM
1??? django默認支持sqlite,mysql, oracle,postgresql數據庫。
? ???<1> sqlite
? ? ? ? ? ? django默認使用sqlite的數據庫,默認自帶sqlite的數據庫驅動 , 引擎名稱:django.db.backends.sqlite3
? ? ?<2> mysql
? ? ? ? ? ? 引擎名稱:django.db.backends.mysql
2 ? ?mysql驅動程序
- ?? MySQLdb(mysql python)
- ?? mysqlclient
- ?? MySQL
- ?? PyMySQL(純python的mysql驅動程序)
3 ? ? 在django的項目中會默認使用sqlite數據庫,在settings里有如下設置:
# Database # https://docs.djangoproject.com/en/2.0/ref/settings/#databasesDATABASES = {'default': {'ENGINE': 'django.db.backends.sqlite3','NAME': os.path.join(BASE_DIR, 'db.sqlite3'),} }如果我們需要更改數據庫,就需要改其配置信息,一般是mysql
DATABASES = {'default': {'ENGINE': 'django.db.backends.mysql','NAME': 'django_learn', #你的數據庫名稱'USER': 'root', #你的數據庫用戶名'PASSWORD': '', #你的數據庫密碼'HOST': '', #你的數據庫主機,留空默認為localhost'PORT': '3306', #你的數據庫端口}}NAME即數據庫的名字,在mysql連接前該數據庫必須已經創建,而上面的sqlite數據庫下的db.sqlite3則是項目自動創建USER和PASSWORD分別是數據庫的用戶名和密碼
?這樣我們的數據庫就基本配置完成,我們可以創建一個表來測試一下:
我簡單的創建一個數據表:
from django.db import models# Create your models here.class Book(models.Model): #必須繼承name = models.CharField(max_length=32)price = models.FloatField()然后啟動:
python manage.py makemigrations啟動后會報錯,報錯信息如下:
Traceback (most recent call last):File "G:\PythonLearning\django_project\venv\lib\site-packages\django\db\backends\mysql\base.py", line 15, in <module>import MySQLdb as Database ModuleNotFoundError: No module named 'MySQLdb'The above exception was the direct cause of the following exception:Traceback (most recent call last):File "manage.py", line 15, in <module>execute_from_command_line(sys.argv)File "G:\PythonLearning\django_project\venv\lib\site-packages\django\core\management\__init__.py", line 371, in execute_from_command_lineutility.execute()File "G:\PythonLearning\django_project\venv\lib\site-packages\django\core\management\__init__.py", line 347, in execute django.setup() File "G:\PythonLearning\django_project\venv\lib\site-packages\django\__init__.py", line 24, in setup apps.populate(settings.INSTALLED_APPS) File "G:\PythonLearning\django_project\venv\lib\site-packages\django\apps\registry.py", line 112, in populate app_config.import_models() File "G:\PythonLearning\django_project\venv\lib\site-packages\django\apps\config.py", line 198, in import_models self.models_module = import_module(models_module_name) File "G:\PythonLearning\django_project\venv\lib\importlib\__init__.py", line 126, in import_module return _bootstrap._gcd_import(name[level:], package, level) File "<frozen importlib._bootstrap>", line 994, in _gcd_import File "<frozen importlib._bootstrap>", line 971, in _find_and_load File "<frozen importlib._bootstrap>", line 955, in _find_and_load_unlocked File "<frozen importlib._bootstrap>", line 665, in _load_unlocked File "<frozen importlib._bootstrap_external>", line 678, in exec_module File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed File "G:\PythonLearning\django_project\venv\lib\site-packages\django\contrib\auth\models.py", line 2, in <module> from django.contrib.auth.base_user import AbstractBaseUser, BaseUserManager File "G:\PythonLearning\django_project\venv\lib\site-packages\django\contrib\auth\base_user.py", line 47, in <module> class AbstractBaseUser(models.Model): File "G:\PythonLearning\django_project\venv\lib\site-packages\django\db\models\base.py", line 114, in __new__ new_class.add_to_class('_meta', Options(meta, app_label)) File "G:\PythonLearning\django_project\venv\lib\site-packages\django\db\models\base.py", line 315, in add_to_class value.contribute_to_class(cls, name) File "G:\PythonLearning\django_project\venv\lib\site-packages\django\db\models\options.py", line 205, in contribute_to_class self.db_table = truncate_name(self.db_table, connection.ops.max_name_length()) File "G:\PythonLearning\django_project\venv\lib\site-packages\django\db\__init__.py", line 33, in __getattr__ return getattr(connections[DEFAULT_DB_ALIAS], item) File "G:\PythonLearning\django_project\venv\lib\site-packages\django\db\utils.py", line 202, in __getitem__ backend = load_backend(db['ENGINE']) File "G:\PythonLearning\django_project\venv\lib\site-packages\django\db\utils.py", line 110, in load_backend return import_module('%s.base' % backend_name) File "G:\PythonLearning\django_project\venv\lib\importlib\__init__.py", line 126, in import_module return _bootstrap._gcd_import(name[level:], package, level) File "G:\PythonLearning\django_project\venv\lib\site-packages\django\db\backends\mysql\base.py", line 20, in <module> ) from err django.core.exceptions.ImproperlyConfigured: Error loading MySQLdb module. Did you install mysqlclient? 這是因為django默認你導入的驅動是MySQLdb,可是MySQLdb對于py3有很大問題,所以我們需要的驅動是PyMySQL 所以,我們只需要找到項目名文件下的__init__,在里面寫入: #在該文件寫入如下代碼import pymysql pymysql.install_as_MySQLdb()
?這樣問題就解決了。
?
但表并未成功創建,還需運行:
python manage.py migrate這樣就完全成功,可以在數據庫上查看我們創建的表了。
ORM表模型
表(模型)的創建:
實例:我們來假定下面這些概念,字段和關系
作者模型:一個作者有姓名。
學生模型:每個學生對應一張身份證,每張身份證對應一位學生,學生和身份證模型之間是一對一的關系(one-to-one)
班級模型:一個班級有多個學生,但一個學生不能在多個班上,學生和班級是一對多關聯關系(one-to-many),也被稱作外鍵。
班級老師模型:一個老師可以教多個班級,一個班級可以由多個老師教,老師和班級模型就是多對多的關聯關系(many-to-many)
?表關系一對一:
#實質就是在主外鍵(author_id就是foreign key)的關系基礎上,# 給外鍵加了一個UNIQUE=True的屬性,基本上很少用到一對一,就一張表表示就可以了
單表操作
創建表: class Student(models.Model):name = models.CharField(max_length=32)age = models.IntegerField()gender = models.BooleanField()若表已經被創建,想要增加新的字段,直接在我們創建的類里面加,例:
class student(models.Model):name = models.CharField(max_length=30)age = models.IntegerField()gender = models.BooleanField()sign_date = models.CharField(max_length=10) #新加字段然后運行:
python manage.py makemigrations這時會出現選擇框,讓我們填一下,我們之前上傳數據后,該列的默認值:
(venv) G:\PythonLearning\orm_learn>python manage.py makemigrations You are trying to add a non-nullable field 'sign_date' to student 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 #這里選擇一,然后填寫對應的數值增加數據(也叫添加表記錄):
def one_increate(request):#添加表數據一 推薦使用student.objects.create(name="wallace",age=12,gender=True)student.objects.create(**{"name":"夏露","age":13,"gender":False})#添加表數據二stu1 = student(name="小米",age=14,gender=False)stu1.save()stu2 = student()stu2.name="小張"stu2.age=13stu2.gender=Truestu2.save()return HttpResponse("創建成功")
?刪除表記錄
student.objects.filter(name="wallace").delete()修改表記錄
#方法一student.objects.filter(id=6).update(age=20) #找到直接修改對應字段#方法二stu1 = student.objects.filter(id=4)[0] #找到后全部修改一遍,再保存不推薦用stu1.age=50stu1.save()查詢表記錄
關于查詢的API
# <1>filter(**kwargs): 它包含了與所給篩選條件相匹配的對象,結果是一個QuerySet對象,里面的元素是表對象,也叫表記錄# <2>all(): 查詢所有結果,結果是Query對象,里面的元素是表對象,也叫表記錄# <3>get(**kwargs): 返回與所給篩選條件相匹配的對象,返回結果有且只有一個就是表對象,也叫表記錄,如果符合篩選條件的對象超過一個或者沒有都會拋出錯誤。# <4>exclude(**kwargs): 它包含了與所給篩選條件不匹配的對象,與filter相反,結果是一個QuerySet對象,里面元素是表對象也叫表記錄
例:
#關于查找的API def one_filter(request):#單用filter得到是一個QuerySet的對象,類似列表,可迭代,可切片stu_obj = student.objects.filter(id=4)print(stu_obj)#將里面的數據迭代,結構是一個表記錄對象,可以通過點的方式取值for i in stu_obj:print(i) #表對象,就是一個表的記錄print(i.name) #取值return HttpResponse("查詢結束")def one_get(request):#直接得到一個表對象,也就是表記錄 如果得到多個會報錯stu_obj=student.objects.get(id=4)print(stu_obj)#取值print(stu_obj.name)return HttpResponse("查詢結束")def one_all(request):#查詢結果是一個QuerySet,類似列表,里面是所有的表對象也叫表記錄stu_obj_list=student.objects.all()print(stu_obj_list)#迭代出每一個表記錄,通過屬性對其取值for i in stu_obj_list:print(i)print(i.name)return HttpResponse("查詢結束")def one_exclude(request):
#查詢結果是QuerySet對象,里面的元素是除了給定條件的所有表對象,也叫表記錄
stu_obj = student.objects.exclude(name="wallace")
#和上面的效果一樣
stu_obj1 = student.objects.all().exclude(name="wallace")
print(stu_obj)
for i in stu_obj:
print(i.name)
print(stu_obj1)
return HttpResponse("exclude success")
對查詢結構處理的方法:
values:返回得到的是一個Queryset對象,但里面的元素是一個個字典。單表情況下配合all或直接引用。多表以后介紹
def one_value(request):#values得到的是一個特殊的QuerySet對象,類似列表,但里面的元素是一個一個的字典stu_obj = student.objects.values("name")print(stu_obj)#得到的是一個特殊的QuerySet對象,類似列表,里面的元素是一個一個字典stu_obj2 = student.objects.filter(id=3).values("name")print(stu_obj2)
#all取得了全部的表記錄,類似于一張表,所以可以去的對應的值stu_obj3 = student.objects.all().values("name")print(stu_obj3)return HttpResponse("value success") def one_value_list(request):#和value類似,返回的是QuerySet對象,不過里面元素是列表的形式stu_obj = student.objects.values_list()print(stu_obj)
正向排序order_by_反向排序reverse
# <6>order_by(*field): 對查詢結果排序,默認是正向排序,*field為按照那個字段排序# <7>reverse(): 在排序的基礎上加上這個語句,進行反向排序,單獨使用無意義例
def one_order(request):#排序stu_obj = student.objects.all().order_by("age")stu_obj1 = student.objects.order_by("age")stu_obj3 = student.objects.filter(age__gt=20).order_by("age")print(stu_obj3)for i in stu_obj3:print(i.age)return HttpResponse("order success")def one_reverse(request):stu_obj = student.objects.all().order_by("age").reverse()stu_obj1 = student.objects.filter(age__gte=20).order_by("age").reverse()print(stu_obj)for i in stu_obj:print(i.age)return HttpResponse("rever success")distinct:從返回結果中剔除重復記錄
def one_distinct(request):#取重,這里的去重指的是全部字段都重復時進行去重,除了id字段stu_obj = student.objects.all().distinct().values("age","name")stu_obj1 = student.objects.distinct().values("age","name")print(stu_obj)print(stu_obj1)return HttpResponse("distinct success")count:返回數據庫中匹配查詢(QuerySet)的對象數量
def one_count(request):#統計得到表對象的數量stu_obj = student.objects.all().count()print(stu_obj)stu_obj1 = student.objects.filter(age__gte=30).count()print(stu_obj1)stu_obj2 = student.objects.count()print(stu_obj2)return HttpResponse("success")first和last:返回得到QuerySet對象中的第一或最后一個表對象
def one_first_last(request):#fiest返回找到的第一個表對象stu_obj = student.objects.first()stu_obj1 = student.objects.filter(age=13).first()print(stu_obj,stu_obj1)#last返回的是最后一個表對象stu_obj2 = student.objects.last()print(stu_obj2)return HttpResponse('success')單表的雙下劃線操作
__gt 大于__lt 小于__gte 大于等于__lte 小于等于__in 在幾個值中__range 在一定范圍內例
#雙下滑線機制,單表 def one__select(request):#大于13stu_obj = student.objects.filter(age__gt=13).values("age")#大于等于13stu_obj1 = student.objects.filter(age__gte=13).values("age")print(stu_obj)print(stu_obj1)#小于stu_obj2 = student.objects.filter(age__lt=13).values("age")#小于等于stu_obj3 = student.objects.filter(age__lte=13).values("age")print(stu_obj2)print(stu_obj3)#等于13stu_obj4 = student.objects.filter(age__exact=13).values("age")print(stu_obj4)#在多個值里面stu_obj5 = student.objects.filter(age__in=[12,13,14]).values("age")print(stu_obj5)#在一個范圍里面stu_obj6 = student.objects.filter(age__range=[12,14]).values("age")print(stu_obj6)return HttpResponse("success")注意:Publisher.objects.all()或者.filter()等都只是返回了一個QuerySet(查詢結果集對象),它并不會馬上執行sql,而是當調用QuerySet的時候才執行。如在遍歷或條件
判斷的時候,查詢數據庫的操作才會執行。
查找表字段,也叫對象查找:
def one_obj(request):stu_obj_list = student.objects.all()#從Queryset集合中得到表對象,通過對象獲取里面的字段for stu_obj in stu_obj_list:print(stu_obj.name)print(stu_obj.age)print(stu_obj.gender)return HttpResponse("success")一對多的表操作
在創建多表關系時,先討論一下,FroeignKey的創建時需注意的地方:
我現在用的是django2.0.2版本,當使用models.ForeignKey設置外鍵,但是不添加on_delete時,總是會報錯:TypeError: __init__() missing 1 required positional argument: 'on_delete'而django自從1.9版本之后,on_delete這個參數就必須設置了看看官網怎么說的吧:ForeignKey.on_delete當一個ForeignKey 引用的對象被刪除時,Django 默認模擬SQL 的ON DELETE CASCADE 的約束行為,并且刪除包含該ForeignKey的對象。這種行為可以通過設置on_delete 參數來改變。例如,如果你有一個可以為空的ForeignKey,在其引用的對象被刪除的時你想把這個ForeignKey 設置為空:user = models.ForeignKey(User, blank=True, null=True, on_delete=models.SET_NULL)on_delete 在django.db.models中可以找到的值有: CASCADE 級聯刪除;默認值。 PROTECT 拋出ProtectedError 以阻止被引用對象的刪除,它是django.db.IntegrityError 的一個子類。 SET_NULL? 把ForeignKey 設置為null; null 參數為True 時才可以這樣做。 SET_DEFAULT? ForeignKey 值設置成它的默認值;此時必須設置ForeignKey 的default 參數。 SET()? 設置ForeignKey 為傳遞給SET() 的值,如果傳遞的是一個可調用對象,則為調用后的結果。在大部分情形下,傳遞一個可調用對象用于避免models.py 在導入時執行查詢: from django.conf import settings from django.contrib.auth import get_user_model from django.db import models def get_sentinel_user():return get_user_model().objects.get_or_create(username='deleted')[0] class MyModel(models.Model):user = models.ForeignKey(settings.AUTH_USER_MODEL,on_delete=models.SET(get_sentinel_user)) DO_NOTHING? Take no action. 如果你的數據庫后端強制引用完整性,它將引發一個IntegrityError ,除非你手動添加一個ON DELETE 約束給數據庫自動(可能要用到初始化的SQL)。 View Code創建一對多關系表Fromkey:
class Teacher(models.Model):name = models.CharField(max_length=30)galary = models.IntegerField()book = models.ForeignKey("Book",null=True,on_delete=models.SET_NULL) #外鍵關聯我們要關聯的表class Book(models.Model):name = models.CharField(max_length=30)price = models.FloatField()
增加表數據:
def one_more_create(request):#添加方式一(推薦) 通過下劃線的方式獲取書籍idteach_obj = Teacher.objects.create(name="天蠶土豆",galary=3000,book_id=1)teach_obj2 = Teacher.objects.create(name="老男孩",galary=4000,book_id=2)#添加方式二,先獲取書籍對象,再將對象賦值給bookbook_obj = Book.objects.filter(id=3).first()teach_obj3 = Teacher.objects.create(name="wallace",galary=1000000,book=book_obj)return HttpResponse("SUCCESS")刪除和修改和單表操作一致,這里就不再贅述了。
一對多查詢表記錄:
方法一:從一個表中得到關聯表的對象,然后從對象中取值,分為正向查詢和反向查詢
def one_more_filter(request):#正向查詢,由多的一方查詢一個的一方,通過老師查詢出版的書籍名字#查詢方式一# teach_obj = Teacher.objects.get(name="wallace")# book_obj = teach_obj.book# print(book_obj.name)#查詢過程:得到表對象,找到對應的外鍵字段,這個外鍵字段就是一個表記錄對象#通過這個表記錄對象去查找對應表對象的字段# 反向查詢:一個的一方查多個的一方,比如查詢出版某本書籍的老師book_obj1 = Book.objects.filter(name="傲視九重天").first()teach_name = book_obj1.teacher_set.all().values("name")#通過關聯的表的類名加上_set得到對應表的對象 classname_set#類似于在父表也創建了一個隱藏的字段print(teach_name)return HttpResponse("查詢成功")方式二:通過(filter,values)的雙下滑線機制,理論是將兩個表內聯結在一起:
def one_more_filter1(request):#一對多表查詢(filter,values)的雙下劃線的使用:當你要跨表操作時,就通過雙下劃線來操作#這種雙下劃線就像吧兩個表內聯結在一起,同過下劃線獲取關聯表的字段#正向 classname__filed#查找老師為wallace的所有書的書名book_name = Teacher.objects.filter(name="wallace").values("book__name")print(book_name)
#查找數目為極品家丁的老師:通過老師表,得到書籍名,跨表teach_name = Teacher.objects.filter(book__name="極品家丁").values("name")print(teach_name)#反向book_name1 = Book.objects.filter(teacher__name="wallace").values("name")teach_name1 = Book.objects.filter(name="大主宰").values("teacher__name")print(book_name1)print(teach_name1)#更多篩選條件 classname__filed__邏輯條件teach_name2=Book.objects.filter(name="大主宰",teacher__galary__gt=5000).values("teacher__name")print(teach_name2)return HttpResponse("success")
多對多表關系
創建多對多表關系:
class Author(models.Model):name = models.CharField(max_length=100)age = models.IntegerField()class Book(models.Model):title = models.CharField(max_length=100)price = models.IntegerField()author = models.ManyToManyField("Author") #通過該字段就可以創建一個Book和Author的多對多表字段#這種方式的創建會自動幫我們生成一張關系表,不需要我們自己手動創建還有另一種創建方式就是我們自己手動的創建第三張關系表,表中只有兩表的主鍵id,因為這種用的不多所以在這里就不贅述了。
多對多表添加綁定關系,如果是單純的添加字段,可以直接進行單表添加:
def more_create(request):#其他字段正常添加,這里添加的是兩個表之間的關系#例如:向給id=3的書,添加作者'''第一步:獲取該書的對象第二步: 獲取你給書綁定的作者的集合第三步: 通過書的表對象獲取添加多對多表關系的字段用add方式添加'''book_obj = Book.objects.get(id=4)author_obj = Author.objects.all()#author_obj是一個表集合,所以要加*號# book_obj.author.add(*author_obj)#通過remove方法,可以將我們建立的表關系解除# book_obj.author.remove(*author_obj)#也可以傳人數字,刪除的id為時的關聯關系,不常用#同理反向添加也是一樣的author_obj1 = Author.objects.get(id=2)book_obj1 = Book.objects.all()author_obj1.book_set.add(*book_obj1)return HttpResponse("success")多對多表查詢:
def more_to_more(request):#找書名id為1的作者的名字book_obj = Book.objects.filter(id=1).values("author__name")print(book_obj)book_obj2 = Book.objects.filter(id=1).first()print(book_obj2.author)book_obj3 = Book.objects.get(id=3)# 這里得到的是一個author的Qureyset的對象print(book_obj3.author)# 所以需要對他進行去取值print(book_obj3.author.all())# 而反向查找的時候用set的方式查詢author_obj = Author.objects.get(id=3)print(author_obj.book_set.all())return HttpResponse("success")聚合查詢和分組查詢:
#聚合查詢 def aggre_query(request):#這里是選擇對應的作者,查詢他所有的出的書的價格price_avg = Author.objects.filter(id=1).aggregate(Avg("book__price"))print(price_avg)price_avg2 = Book.objects.all().aggregate(Avg("price"))price_max = Book.objects.all().aggregate(Max("price"))price_min = Author.objects.filter(id=1).aggregate(Min("book__price"))print(price_avg2,price_max,price_min)return HttpResponse("success")#分組查詢 def anno_query(request):#對作者進行價格的分組,一般分組時會聯合聚合函數price_avg = Author.objects.values("name").annotate(Avg("book__price"))print(price_avg)return HttpResponse("success")F查詢和Q查詢:是一種自定義的查詢手段,當聚合和組合無法滿足我們時,可以使用F和Q查詢
def q_query(request):#這里得到的是一個Queryset集合q1 = Author.objects.filter(Q(name__startswith="天")).all()#可以用邏輯運算符一起作用q2 = Author.objects.filter(Q(name__startswith="天") | Q(name__startswith="失"))print(q1.first().name)return HttpResponse("success")def f_query(request):#F查詢是當你需要對表中的某個字段進行操作時,例如運算等的時候使用book_obj = Book.objects.update(price=F("price")+100)admin
admin是django強大功能之一,它能共從數據庫中讀取數據,呈現在頁面中,進行管理。默認情況下,它的功能已經非常強大,如果你不需要復雜的功能,它已經夠用,但是有時候,一些特殊的功能還需要定制,比如搜索功能,下面這一系列文章就逐步深入介紹如何定制適合自己的admin應用。
如果你覺得英文界面不好用,可以在setting.py 文件中修改以下選項:
LANGUAGE_CODE = 'zh-hans'第二步:
admin.site.register(Book) #將你要使用的數據庫進行注冊,這是默認樣式第三步:如果希望使用更多的樣式,可以進行定制
class Myadmin(admin.ModelAdmin):list_display = ("title","price")search_fields = ("title","price")admin.site.register(Book,Myadmin)定制樣式的語句字段:
list_display: 指定要顯示的字段search_fields: 指定搜索的字段list_filter: 指定列表過濾器ordering: 指定排序字段第二種使用樣式方法:不推薦
# @admin.register(Book) class Myadmin(admin.ModelAdmin):list_display = ("title","price")search_fields = ("title","price")#一般是單個表進行樣式添加?
?
轉載于:https://www.cnblogs.com/tashanzhishi/p/9241392.html
總結
以上是生活随笔為你收集整理的Django 框架 数据库操作的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 学习shell脚本之乘法口诀
- 下一篇: 树莓派 -- 按键 (key)使用BCM