Django Model操作(个人备忘录)

Django这将是我个人的备忘录。

本次我们将总结一下关于Model的操作。

开发环境

操作系统:mac
编辑器:vscode
Python版本:3.10.9
Django版本:4.1.0

创建模型的基本语法

from django.db import models

class Person(models.Model):
    first_name=CharField(max_length=30)
    last_name=CharField(max_length=30)

创建迁移文件

在执行迁移操作之前,需要创建迁移文件。迁移文件是指将model.py中的内容处理为可以在数据库中保存的形式的文件。

$ python manage.py makemigrations <アプリ名> --name <つけたい名前>

只需要运行 python manage.py makemigrations 就可以了。
如果想要在迁移文件夹中创建一个有意义的文件夹而不是自动生成的名称,
可以在运行 makemigrations 后加上 –name 参数。

我搬到海外

$ python manage.py migrate <アプリ名>

在VScode中如何查看表格的内容

按住“Command+Shift+P”, 然后输入“sqlite open Datebase”,然后选择“sqlite”选项,这样就会在vscode的左下角出现一个名为“SQLITE EXPLORER”的标签页。在那里,右键点击后选择“Show Table ‘sqlite_master’”,就可以查看其中的内容。

其他操作

$ python manage.py showmigrations <アプリ名>
    #適応されているマイグレーションファイルを見る
$ python manage.py migrate <アプリ名> <戻りたいマイグレーションファイル名>
    #マイグレーションファイルを指定したファイルまで適応されていない状態にする
$ python manage.py migrate <アプリ名> zero
    #全てのマイグレーションファイルの適応を外す

如果将文件恢复到未应用状态,请确保还删除了位于migrations文件夹中未应用的文件。

主要领域清单

field名概要BooleanField論理型、TrueとFalseを入れられるCharField文字列型。VARCHARとしてカラムが作成される。max_lengthで長さを指定するDateField,DatetimeField日付型、タイムスタンプ型EmailFieldメールアドレスを格納する。バリデーションあり。デフォルトでVARCHAR(254)FileFieldファイルのアップロードの際のファイルパスを格納。デフォルトでVARCHAR(100)DecimalField正確な数値を格納されるIntegerField,FloatField整数型(INTEGER)、浮動小数点(FLOAT)を格納されるTextField長い文字列を入れる。TEXT型としてカラムが作成されるURLFieldURLを入れる。VARCHAR(200)としてカラムが作成される

在制作模型时学到的新东西

from django.db import models
from django.utils import timezone

class Person(models.Model):
    email = models.EmailField(db_index=True)#indexをはる という高速化の処理
#全てにdb_index=Trueとするとメモリを喰うので検索したい項目にだけ設定すると⚪︎
    create_at =models.DateTimeField(default =timezone.datetime.now)
#デフォルト設定をすると登録時の時間を入れられる

使得可以在管理界面上查看已创建的模型。

from django.contrib import admin
from .models import Person

admin.site.register(Person)

元信息选项

Meta指的是元类,用于定义类的行为。

from django.db import models
from django.utils import timezone
import pytz #timezoneを設定するモジュール

class BaseMeta(models.Model): #抽象クラス
    create_at = models.DateTimeField(default=timezone.datetime.now(pytz.timezone('Asia/Tokyo')))
    update_at = models.DateTimeField(default=timezone.datetime.now(pytz.timezone('Asia/Tokyo')))
    
    class Meta:
        abstract = True #! 1.抽象クラス(abstract)として定義するためメタクラスを設定する


class Person(BaseMeta):#! 2.共通のカラムを持ちたいとき抽象クラスを継承する
    first_name=models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)
    birthday = models.DateField(default='1900-01-01')
    email = models.EmailField(db_index=True)#!indexをはる という高速化の処理
    salary = models.FloatField(null=True)
    memo = models.TextField()
    web_site = models.URLField(null=True,blank = True)
    # create_at =models.DateTimeField(default =timezone.now) #! 継承したカラムを使うためこちらは削除
    
    class Meta:
        db_table = 'person' #!テーブル名をpersonに設定
        index_together = [['first_name','last_name']] #!二つセットで検索する際に高速化できて便利
        ordering = ['salary'] #DBから取り出す際のデフォルトのorder「順番」を設定
        #降順にするときは['-salary']とする

    def __str__(self):
        return f'{self.first_name} {self.last_name}' #!データを取得した際にわかりやすくするために名前を設定

作为另一个Meta选项,
如果将unique_together=[[‘first_name’,’last_name’]]设置为一组,
还可以配置字段为UNIQUE。

请参考Django官方网站获取更详细的信息。

可以使用三种方法将数据插入到数据库中。

#1. インスタンスのsaveメゾット(DBに同じものが存在しないときDBに挿入、存在する場合は更新
web_site=Website(url='www.sample.com',name='sample')
web_site.save() #Websiteというクラスで作られたweb_siteインスタンスをsaveする

#2. クラスメゾットのcreateメゾット(DBに同じものが存在しないときDBに挿入、存在する場合はエラー
Website.objects.create(
    url = 'www.sample.com', name = 'sample'
) #存在した場合IntegrityError発生

#3. get_or_createメゾット(DBに同じものが存在しない場合作成して返す。存在する場合はそのものを返す
obj,created = Website.objects.get_or_create(url='www.sample.com',name='sample')
#2つ変数が返ってくる。objには作成したデータを。createdには存在しなくて作られた場合はTrueがはいり、
#作成しなかったときはFalseがはいる

请尝试将数据实际插入到数据库中。

在与manage.py相同的目录中创建一个名为main.py的文件。

#! djangoの設定を読み込んでDBに保存する
import os

os.environ.setdefault('DJANGO_SETTINGS_MODULE','ModelProject.settings')
from django import setup
setup()


from ModelApp.models import Person

#インスタンスを作成
p = Person(
    first_name = 'Taro',
    last_name = 'Sato',
    birthday = '2000-01-01',
    email = 'aa@example.com',
    salary=None,
    memo='memo taro',
    web_site = 'https://www.com',
)
#インスタンスをsave
p.save()

#classmethod create
Person.objects.create(
    first_name = 'Jiro',
    last_name = 'Ito',
    email = 'bb@example.com',
    salary = 2000,
    memo='class method実行',
    web_site=None,
)

#get_or_create(取得or作成)
obj,created = Person.objects.get_or_create(
    first_name = 'Saburo',
    last_name = 'Ito',
    #birthdayはdefaultを設定しているため記述しない場合デフォルト値がはいる
    email = 'bb@example.com',
    salary = 2000,
    memo='class method実行',
    web_site=None,
)

print(obj) #models.pyで設定したdef __str__(self)の名前で返る
print(created) #作られた場合はTrue、すでに存在している場合はFalse

在创建文件后,右键单击main.py文件→选择在终端中运行,数据将保存在数据库中。

请记住,在数据库中,Null和空白是不同的。

从数据库中进行SELECT的三种方法(获取)

在与manage.py相同的目录中创建一个名为select_sample.py的文件,用于获取数据。

#データの取得
#Djangoの設定を読み込む
import os
os.environ.setdefault('DJANGO_SETTINGS_MODULE','ModelProject.settings')
from django import setup
setup()


from ModelApp.models import Person

#全て取得
persons = Person.objects.all()
for person in persons:
    print(person.id,person,person.salary)
    
#1件だけ取得
# person = Person.objects.get(first_name='Taro') #複数取得できるからエラーに
# person = Person.objects.get(first_name='taro') #1件も獲得できない時もエラーに
person = Person.objects.get(pk=1) #主キーは必ず1件なので取得できる
print(person.id,person)

#filter(絞り込み、エラーにならない、複数取得可)
persons = Person.objects.filter(first_name='Taro').all()

print(persons[0].email) #配列なのでこの形で取り出せる
for person in persons:
    print(person.id , person) #for文でも取り出せる

请参考一下Qiita(查询集)。

Django逆引き小抄(QuerySet部分)

你知道objects本质上是模型管理器吗?.all()和.first()是方法哦!下面简单解释一下如何使用Django objects,可以作为参考。

从数据库中提取(get_object_or_404 get_list_or_404)

from django.shortcuts import get_object_or_404
get_object_or_404
#指定したモデルを呼び出し、getを行う。値を取得できなかった場合raise Http404を送出する
#例)item = get_object_or_404(Items,pk=id)

get_list_or_404
#指定したモデルを呼び出し、filterを行う。同上
#リストで取り出すためリストの中身がない状態で取り出すと404を返す
#例)items = get_list_or_404(Items,id__gt=2) idが2より大きいものを取り出す

Django View的应用
在这里概括了有关错误处理的内容

数据的更新

创建一个名为 update_sample.py 的文件,用于在与 manage.py 相同的目录中更新数据。

#データの更新(update)
import os

os.environ.setdefault('DJANGO_SETTINGS_MODULE','ModelProject.settings')
from django import setup
setup()

from ModelApp.models import Person
from django.utils import timezone
import pytz

#1件だけ取得してbirthdayとupdate_atを更新する
person = Person.objects.get(id=1)
person.birthday='2001-09-01'
person.update_at=timezone.datetime.now(pytz.timezone('Asia/Tokyo'))
person.save() #saveで更新完了

#first_nameが'Taro'であるデータを全て更新する
persons = Person.objects.filter(first_name='Taro').all()
for person in persons:
    person.first_name = person.first_name.lower()
    person.update_at = timezone.datetime.now(pytz.timezone('Asia/Tokyo'))
    person.save()
#上記のやり方は一つ一つクエリを作成するため、何万件ともなると処理が遅くなってしまう

#下記はupdateで一気に実行するためこちらのほうが処理が軽くなりおすすめ
Person.objects.filter(first_name='Saburo').update(
    web_site='http://sample.jp',
    update_at = timezone.datetime.now(pytz.timezone('Asia/Tokyo'))
)

删除数据

创建一个名为delete_sample.py的文件,用于在与manage.py相同的目录中删除数据。

#データの削除(delete)
import os

os.environ.setdefault('DJANGO_SETTINGS_MODULE','ModelProject.settings')
from django import setup
setup()

from ModelApp.models import Person

#filterを使って条件にあったデータを削除する
Person.objects.filter(first_name='Saburo').delete()
Person.objects.filter(first_name = 'taro',birthday='2001-09-01').delete()

#全件削除
Person.objects.all().delete()

让模型拥有外键

通过在表中添加外键(ForeignField),实现表之间的关联。

#外部キー練習
class Students(models.Model):
    name = models.CharField(max_length=20)
    age = models.IntegerField()
    major = models.CharField(max_length=20)
    school = models.ForeignKey(
        'Schools', on_delete=models.CASCADE
    )
    
    class Meta:
        db_table = 'students'
        
class Schools(models.Model):
    name = models.CharField(max_length=20)
    prefecture = models.ForeignKey(
        'Prefectures',on_delete=models.CASCADE
    )
    
    class Meta:
        db_table = 'schools'
        
class Prefectures(models.Model):
    name=models.CharField(max_length=20)
    
    class Meta:
        db_table='prefectures'

学生表与学校表之间存在一对多的关系,
学校表与县表也是一对多的关系。

体验对于on_delete=models.CASCADE的效果

在与manage.py相同的层级中创建一个名为foreignkey_sample.py的文件。

#外部キーの練習
import os

os.environ.setdefault('DJANGO_SETTINGS_MODULE','ModelProject.settings')
from django import setup
setup()

from ModelApp.models import Students,Schools,Prefectures

prefectures = ['東京','大阪']
schools = ['東高校','西高校','北高校','南高校']
students = ['太郎','二郎','三郎']

#データの用意
def insert_records():
    for prefecture_name in prefectures:
        prefecture = Prefectures(
            name = prefecture_name
        )
        prefecture.save()
        for school_name in schools:
            school = Schools(
                name = school_name,
                prefecture = prefecture
                #左のprefectureはmodels.pyで定義した外部キーのprefecture
                #右のprefectureはfor内で作成したインスタンスのprefecture
                #こうすることで紐付けされる
            )
            school.save()
            for student_name in students:
                student = Students(
                    name = student_name,age=17,
                    major = '物理',school = school
                )
                student.save()
#データを一旦保存させてコメントアウト              
# insert_records()

#データを表示するための関数
def select_students():
    students = Students.objects.all()
    for student in students:
        print(student.id,student.name,student.age,student.major,student.school.id,student.school.name,student.school.prefecture.id,student.school.prefecture.name)
#student.school.nameやstudent.school.prefeture.nameのように外部キーを伝って紐付けされたテーブルのデータににアクセスすることが可能
        
# select_students()

#東高校を削除すると同時にstudentが3人削除される
Schools.objects.filter(id=1).delete()
# select_students()
#prefectureの'東京'を削除すると東京を持つデータがすべて削除される
Prefectures.objects.filter(name='東京').delete()
select_students()

除了on_delete=models.CASCADE之外的选项

school = models.ForeignKey(
        #親を削除しようとするとエラーがでる
        'Schools', on_delete=models.PROTECT
        #親を参照している項目はすべてNullをいれる
        'Schools', on_delete=models.SET_NULL,null=True
)

除了on_delete=models.CASCADE以外的选项2,RESTRICT。

当删除 Schools 时,会受到 Students 的 RESTRICT 保护,
而当删除 Prefecture 时,由于使用了 CASCADE 进行关联,所有下属都将被同时删除。

如果参照对象(父母)与参照对象(祖父母)之间使用CASCADE进行关联,那么当删除祖父母时,父母与子女也会一起被删除。

#外部キー練習
class Students(models.Model):
    name = models.CharField(max_length=20)
    age = models.IntegerField()
    major = models.CharField(max_length=20)
    #ここからポイント
    school = models.ForeignKey(
        'Schools', on_delete=models.RESTRICT #
    )
    prefecture = models.ForeignKey(
        'Prefectures',on_delete=models.CASCADE #
    )
    class Meta:
        db_table = 'students'
        
class Schools(models.Model):
    name = models.CharField(max_length=20)
    prefecture = models.ForeignKey(
        'Prefectures',on_delete=models.CASCADE #
    )
    class Meta:
        db_table = 'schools'
        
class Prefectures(models.Model):
    name=models.CharField(max_length=20)
    class Meta:
        db_table='prefectures'
def insert_records():
    for prefecture_name in prefectures:
        prefecture = Prefectures(
            name = prefecture_name
        )
        prefecture.save()
        for school_name in schools:
            school = Schools(
                name = school_name,
                prefecture = prefecture
                #左のprefectureはmodels.pyで定義した外部キーのprefecture
                #右のprefectureはfor内で作成したインスタンスのprefecture
                #こうすることで紐付けされる
            )
            school.save()
            for student_name in students:
                student = Students(
                    name = student_name,age=17,
                    major = '物理',school = school,
                    #RESTRICTの場合のみ追加 
                    prefecture = prefecture, #idを持たせるためこちらを追加
                )
                student.save()



OneToOneField用于将表格之间进行一对一的关联

#OneToOne
class Places(models.Model):
    name = models.CharField(max_length=50)
    address = models.CharField(max_length=80)
    
    class Meta:
        db_table = 'places'
        
class Restaurant(models.Model):
    place = models.OneToOneField( #
        Places,
        on_delete=models.CASCADE,
        primary_key=True #
    )
    name = models.CharField(max_length=50)
    
    class Meta:
        db_table = 'restaurants'

在与manage.py相同的层级下创建一个名为onetoone_sample.py的文件。

#OneToOne
#import等省略。上記のファイルと同じ

places = [
    ('Motomachi','Yokohama'),('Tsukiji','Tokyo')
]
restaurants=['restaurantA','restaurantB']

for place_name,place_address in places:
    p = Places(name=place_name, address=place_address)
    p.save()
    for restaurant_name in restaurants:
        r = Restaurant(place=p, name=restaurant_name)
        r.save()
        #>>> 結果はrestaurantsテーブルにはplace_id1,2とrestaurantBの2つのデータしか入らない
        #インスタンスのsaveメゾットは
        #DBに同じものが存在しないときはDBに保存、存在する場合は更新なので今回はplaceが
        #primarykeyで同じものなのでnameがrestaurantBに更新される
    
        Restaurant.objects.create(
            place =p,name=restaurant_name
        )
        #クラスメゾットのcreateメゾットを使う場合
        #こちらもDBにすでに存在する場合はエラーを返すので保存はできない

OneToOne是一种用于将表之间关联的字段,因此对于一个其他表的id,它只能持有一个数据。

多对多

用于关联多对多关系表的字段
在内部,创建了另一个新表以在两个表之间进行关联。通过使用该表进行关联。

#ManyToMany
class Authors(models.Model):
    name = models.CharField(max_length=50)
    
    def __str__(self):
        return self.name
    
    class Meta:
        db_table = 'authors'
        
class Books(models.Model):
    name = models.CharField(max_length=50)
    authors = models.ManyToManyField(Authors) #
    
    def __str__(self):
        return self.name
    
    class Meta:
        db_table = 'books'

在manage.py的同一層目录中创建一个名为manytomany_sample.py的文件。

#manytomany
#import等省略

#データの挿入
def insert_books():
    book1 = Books(name='Book1')
    book2 = Books(name='Book2')
    book3 = Books(name='Book3')
    book1.save()
    book2.save()
    book3.save()
    
def insert_authors():
    author1 = Authors(name='Author1')
    author2 = Authors(name='Author2')
    author3 = Authors(name='Author3')
    author1.save()
    author2.save()
    author3.save()

#関数の実行
insert_books()
insert_authors()

# データを取り出して
book1 = Books.objects.get(pk=1)
book3 = Books.objects.get(pk=3)
author1 = Authors.objects.get(pk=1)
author2 = Authors.objects.get(pk=2)
author3 = Authors.objects.get(pk=3)

#book1にaddで追加する
book1.authors.add(author1,author2)
print(book1.authors.all())

book3.authors.add(author1,author2,author3)
print(book3.authors.all())

print(book1.authors)

可以用add方法进行添加,不需要save。
authors拥有多本书。
books也拥有多位作者的关系。

从合并的记录中提取数据

在选择是处理一个还是处理多个对象时,提取方式不同。
在manage.py的同一层级下创建select_foreign_table.py文件。

#! 結合したデータの取り出し
import os
os.environ.setdefault('DJANGO_SETTINGS_MODULE','ModelProject.settings')
from django import setup
setup()

from ModelApp.models import Students,Schools,Prefectures
from ModelApp.models import Places,Restaurant
from ModelApp.models import Authors,Books


s=Schools.objects.first()
print(type(s))
print(dir(s)) #このオブジェクトが持つ使える属性を返す中にprefectureとstudents_setが存在することがわかる
# SchoolsのオブジェクトはStudentsに対しては1対多、Prefectureに対しては多対1であるため
print(s.prefecture.name)

print('*'*100)
st = s.students_set #多を取り出すには_set
print(type(st))
print(dir(st))
print(st.all())
st = st.all() #allで取得する
for s in st:
    print(s.school.prefecture.name) #大阪 を取り出せる
    
#OnetoOneからデータを取り出す
print('********onetoone*********')
p = Places.objects.first()
print(f'レストランの名前は:{p.restaurant.name}')
#逆も同じように取り出せる
r = Restaurant.objects.first()
print(f'場所は{r.place.address}{r.place.name}')


#ManyToManyからデータを取り出す
print('***********manytomany****************')
b = Books.objects.first()
print(type(b))
print(dir(b))
print(b.authors.all())
bs = b.authors.all()
for b in bs:
    print(b.name) #Author1,Author2が表示される

a= Authors.objects.first()
print(a.books_set.all())
#models.pyのAuthorsクラスはBooksと紐づけるプロパティを持っていないのでAuthorsとBooksが1対多のような
# 関係になるからこちらは_setを使う?

a_s = a.books_set.all()
for a in a_s:
    print(a.name) # Book1,Book3が表示される

指定条件下获取数据

在manage.py的相同目录下创建query_01.py至query_04.py文件
以下是练习获取所有数据的内容

#! データを絞り込んで取得
import os
os.environ.setdefault('DJANGO_SETTINGS_MODULE','ModelProject.settings')
from django import setup
setup()

from ModelApp.models import Students

#全件取得
print(Students.objects.all())

#頭五件取得
print(Students.objects.all()[:5])

#5件目よりあと
print(Students.objects.all()[5:])

#5~7件目
print(Students.objects.all()[:8])
print(Students.objects.all()[5:8].query) #実際に発行しているqueryを見ることができる

#一番最初の一件
print(Students.objects.first())

#等価のものだけに絞り込む
print(Students.objects.filter(name='太郎').all())
print(Students.objects.filter(age=17).all())

#AND条件
print(Students.objects.filter(name='太郎',pk=13).all().query)
print(Students.objects.filter(name='太郎',pk__gte=13).all().query)
print(Students.objects.filter(name='太郎',pk__lte=17).all())
print(Students.objects.filter(name='太郎',pk__gte=13,pk__lte=20).all().query)

#前方一致、後方一致
print(Students.objects.all())
print(Students.objects.filter(name__startswith='').all())
print(Students.objects.filter(name__endswith='').all())

#or
from django.db.models import Q
print(Students.objects.filter(Q(name='太郎')|Q(pk__gt=19)).all())

__gte是greater than equal的缩写。
__lte是less than equal的缩写。

##! データを絞り込んで取得 その2
import os
os.environ.setdefault('DJANGO_SETTINGS_MODULE','ModelProject.settings')
from django import setup
setup()

from ModelApp.models import Students,Person

#IN
ids = [13,14,15]
print(Students.objects.filter(pk__in=ids).all())
print(Students.objects.filter(pk__in=[15,16,17]).all())
print(Students.objects.filter(name__in=['二郎','']).all()) #二郎は取り出せるが三では三郎は取り出せない

# contain 部分一致
print(Students.objects.filter(name__contains='').all())

#is null
print(Person.objects.filter(salary__isnull=True).all())

#レコードを取り除くexclude(filterの逆を取り出す)
print(Person.objects.exclude(salary__isnull=True).all())
print(Students.objects.exclude(name='太郎').all())

#カラムを取り出す
print(Students.objects.values('id','name','age').all().query)
students = Students.objects.values('id','name','age').all()
for student in students:
    print('id:{},名前:{}'.format(student['id'],student['name']))
    
#並び替え
print(Students.objects.order_by('name','-id').all()) #第一条件nameを昇順、第二条件idを降順に並び替える
#filterとorder_byを組み合わせることも可
print(Students.objects.filter(name='太郎').order_by('-id').all())
##! データを絞り込んで取得 その3
import os
os.environ.setdefault('DJANGO_SETTINGS_MODULE','ModelProject.settings')
from django import setup
setup()

from ModelApp.models import Students

# #件数
print(Students.objects.count()) #12
print(Students.objects.filter(name='太郎').count()) #4
print(Students.objects.filter(name='Taro').count()) #0

# #件数、最大値、最小値、平均値、合計
from django.db.models import Count,Max,Min,Avg,Sum
print(Students.objects.aggregate(Count('pk'),Max('pk'),Min('pk'),Avg('pk'),Sum('age')))
aggregate_student = Students.objects.aggregate(Count('pk'),Max('pk'),Min('pk'),Avg('pk'),Sum('age'))
#{'pk__count':12,'pk__max':24}といったように辞書型で返されるため下記のような記述で取り出せる
print(aggregate_student['pk__max'])
#別名をつけることもできる
print(Students.objects.aggregate(counted_pk= Count('pk'),max_pk=Max('pk'),min_pk=Min('pk'),avg_pk=Avg('pk'),sum_pk=Sum('age')))

#GROUP BY:ある特定のカラムで集計して、合計、最大などを求める
print(Students.objects.values('name').annotate(
    Max('pk'),Min('pk')
).query) #queryを見る
print(Students.objects.values('name','age').annotate(
    max_id = Max('pk'),min_id = Min('pk')#キーをmax_idと min_idに変更している
)) 
#辞書型が配列の中にはいって渡されるのでfor文で一つ一つ取り出してキーを指定して取り出すことができる
for student in Students.objects.values('name','age').annotate(
    max_id = Max('pk'),min_id = Min('pk')
):
    print(student['name'],student['max_id'])
#! データを絞り込んで取得 その4 外部テーブルをつかった絞り込み
import os
os.environ.setdefault('DJANGO_SETTINGS_MODULE','ModelProject.settings')
from django import setup
setup()

from ModelApp.models import Students,Schools

# for student in Students.objects.all():
#     print(student.name,student.school.name,student.school.prefecture.name)

#外部テーブルを使ったfilterができる(外部テーブル名__カラムとする)
for student in Students.objects.filter(school__name='南高校').all():
    print(student.name,student.school.name,student.school.prefecture.name)

#excludeもできる
for student in Students.objects.exclude(school__name='南高校').all():
    print(student.name,student.school.name,student.school.prefecture.name)
    
#schoolsテーブルからstudentsを取り出す
print(Schools.objects.filter(students__name='太郎').all())
for school in Schools.objects.filter(students__name='太郎').all():
    print(student.name,school.name,school.prefecture.name)
    
print('-'*100)
#順番を並び替える(order_by)
for student in Students.objects.order_by('-school__name').all():
    print(student.name,student.school.name)
print('-'*100)
for student in Students.objects.filter(school__name='西高校').order_by('-school__name').all():
    print(student.name,student.school.name)
print('*'*100)
#リストをつくってinで条件指定すると複数のvalueから一括取得できる(自作)
school_names=['南高校','西高校']
for student in Students.objects.filter(school__name__in=school_names).order_by('school__name').all():
    print(student.name,student.school.name)
    
#外部テーブルを使ったGROUP BY
from django.db.models import Count,Max
print(Students.objects.values('school__name').annotate(Count('id'),Max('id')))
#studentからSchoolのnameごとに数をカウントして返す

练习题目

20230728-121553.png

进行以下操作:
1. 创建项目和应用程序,并完成迁移工作。
2. 在models.py中创建模型。
3. 运行makemigration和migrate命令,创建表格。
4. 存储数据。
5. 从表格中提取数据。

只有一个选项:省略1。

从2开始描述

from django.db import models

class Tests(models.Model):
    name = models.CharField(max_length=50)
    
    class Meta:
        db_table = 'tests'
        
class Test_Results(models.Model):
    test=models.ForeignKey(
        'Tests',on_delete=models.CASCADE
    )
    student = models.ForeignKey(
        'Students',on_delete=models.CASCADE
    )
    score = models.IntegerField()
    
    class Meta:
        db_table = 'test_results'
        

class Students(models.Model):
    name =models.CharField(max_length=50)
    grade = models.IntegerField()
    classes = models.ForeignKey(
        'Classes',on_delete=models.CASCADE
    )
    
    class Meta:
        db_table = 'students'
        
class Classes(models.Model):
    name = models.CharField(max_length=50)
    
    class Meta:
        db_table = 'classes'

只有3个省略
4. 存储数据

import os
os.environ.setdefault('DJANGO_SETTINGS_MODULE','ModelExam.settings')
from django import setup
setup()

from ModelApp.models import Tests,Test_Results,Students,Classes
import random

#classesにデータをいれる
# classes_list=['classA','classB','classC','classD','classE','classF','classG','classH','classI','classJ']
classes_list = ['class'+ c for c in 'ABCDEFGHIJ']
# students_list=['studentA','studentB','studentC','studentD','studentE','stundenF','studentG','studentH','studentI','studentJ']
students_list=['student' + c for c in 'ABCDEFGHIJ']
# print(classes_list)
tests_list=['数学','英語','国語']


#testのインスタンスを作ってリストに格納する
tests_instance_list = []
for test_name in tests_list:
    test_instance = Tests(
        name = test_name
    )
    test_instance.save()
    tests_instance_list.append(test_instance)

#データを格納する関数 
def insert_records():
    for classes_name in classes_list: 
        classes = Classes(
            name=classes_name
        )
        classes.save()
        
        for students in students_list:
            #studentインスタンスを作る
            name = classes_name +' '+students
            student = Students(
                name = name,
                grade = 1,
                classes = classes
            )
            student.save()
            for test_name in tests_instance_list:
                test_results = Test_Results(
                    test = test_name,
                    student = student,
                    score = random.randint(50,100)
                    )
                test_results.save()
    
insert_records()

从表中提取数据

import os
os.environ.setdefault('DJANGO_SETTINGS_MODULE','ModelExam.settings')
from django import setup
setup()

from ModelApp.models import Tests,Test_Results,Students,Classes
from django.db.models import Sum,Avg,Max,Min

print('idが1のstudentの名前とテスト科目と点数を表示する')
for test_result in Test_Results.objects.filter(student__id = 1).all():
    print(
        '生徒名:{}\
        テストの科目:{}\
        点数:{}'.format(test_result.student.name,test_result.test.name,test_result.score)
    )
    
print('クラスごとの各科目のテストの合計、平均、最大、最小を表示する')
# s=Test_Results.objects.values('student__classes__name','test__name').annotate(
#     Max('score'),Min('score'),Sum('score'),Avg('score')
# )
# print(s)
for test_result in Test_Results.objects.values('student__classes__name','test__name').annotate(
    Max('score'),Min('score'),Sum('score'),Avg('score')
):
    print(
        'クラス:{}\
        科目:{}\
        最大値:{}\
        最小値:{}\
        平均値:{}\
        合計:{}'.format(test_result['student__classes__name'],test_result['test__name'],test_result['score__max'],test_result['score__min'],test_result['score__avg'],test_result['score__sum']))
    
print('idが1のstudentの名前とテスト科目と点数を表示する2')
student = Students.objects.get(id = 1) #idも可
# student = Students.objects.get(pk = 1) #pkも可
# student = Students.objects.filter(id = 1) #? こちらではtest_result_setが使えなかったのはなぜ?
#!filterはクエリセットを返し、getはオブジェクトを返す
print(student)
for test_result in student.test_results_set.all():
    print(
        '生徒名:{}\
        テストの科目:{}\
        点数:{}'.format(test_result.student.name,test_result.test.name,test_result.score)
    )
    
print('クエリをみてみる')
print(Test_Results.objects.values('student__classes__name','test__name').annotate(
    Max('score'),Min('score'),Sum('score'),Avg('score')
).query)

filter和get的区别在于
filter返回一个查询集
get返回一个对象。

如果对于以上的模型有任何新的学习,我们会继续更新。

广告
将在 10 秒后关闭
bannerAds