Django-Modellebenenoperationen (Django-05)

1. Interpretation der Modellschicht

Django verfügt über ein eingebettetes ORM-Framework. Es ist nicht erforderlich, SQL-Anweisungen direkt zu schreiben, um die Datenbank zu betreiben. Stattdessen definiert es Modellklassen zum Betreiben des Modells. Klasse zum Abschließen von Vorgängen wie dem Hinzufügen, Löschen, Ändern, Überprüfen und Erstellen von Tabellen in der Datenbank.

  • istein Objekt,funktioniert auch indiesem Beispiel < /span>s Absicht.
  • ist Beziehung, ins Chinesische übersetzt ist es eine Beziehung, das heißt in einer relationalen Datenbank < /a >Die Bedeutung der Datentabelle.
  • istZuordnung, ist reflektierende Absicht.

1.1 Vorteile von ORM

  • Die Datenmodellklassen sind alle an einem Ort definiert, wodurch sie einfacher zu aktualisieren und zu warten sind und auch die Wiederverwendung von Code begünstigen.

  • ORM verfügt über vorgefertigte ToolsViele Funktionen können automatisch ausgeführt werden, wie z. B. Dateneliminierung, Vorverarbeitung, Transaktionen usw..

  • Es zwingt Sie zur Verwendung der MVC-Architektur. ORM ist ein natürliches Modell, das den Code letztendlich klarer macht.

  • ORM-basierter Geschäftscode ist relativ einfach,weniger Code, gute Semantik und leicht zu verstehen.

  • Anfänger neigen dazu, SQL mit schlechter Leistung für komplexe Unternehmen zu schreiben. Mit ORM müssen keine komplexen SQL-Anweisungen geschrieben werden. Sie müssen nur das Modellobjekt bedienen, um die Daten in der Datentabelle synchron zu ändern.

  • Wenn Sie in Zukunft die Datenbank wechseln möchten, wenn Sie ORM während der Entwicklung anwenden, . Sie Sie müssen nur die zugrunde liegende ORM-Docking-Datenbank wechseln. Treiber[Ändern Sie einfach die Verbindungsadresseder Konfigurationsdatei]

1.2 ORM-Fehlerbehebung

  • Die ORM-Bibliothek ist kein leichtes Tool. Sie erfordert viel Aufwand zum Erlernen und Einrichten. Sogar verschiedene Frameworks verfügen über ORMs verschiedene Operationen. .

  • Fürkomplexe Geschäftsabfragen ist ORM schwieriger und komplexer auszudrücken als natives SQL .

  • Die Leistung der ORM-Operationsdatenbank ist schlechter als bei der Verwendung von nativem SQL.

  • ORM abstrahiert die Datenbankschicht, und Entwickler  können die zugrunde liegenden Datenbankoperationen nicht verstehen und können auch kein spezielles SQL anpassen. [Sie können pymysql verwenden, um separat zu arbeiten. Die Verwendung von ORM bedeutet nicht, dass das aktuelle Projekt keine anderen Datenbankbetriebstools verwenden kann. 】

2. Django-Datenbankoperationen

Wir können die Datenbankoperationen von Django durch die folgenden Schritte nutzen:

  1. Konfiguration Datenbankverbindungsinformationen.
  2. vorhandene models.py mittlere Modellkategorie.
  3. Datenbankmigrationsdatei generieren und Migrationsdatei ausführen [Hinweis: Die Datenmigration ist eine unabhängige Funktion. Diese Funktion ist möglicherweise nicht in ORM in anderen Web-Frameworks integriert.]
  4. Schließen Siedas Hinzufügen, Löschen, Ändern und Abfragen der Datentabelle abdurch die vom Modellklassenobjekt bereitgestellten Methoden oder Attribute.

2.1 Datenbankverbindung konfigurieren

Die Informationen zur Datenbankverbindungskonfiguration werden in Settings.py gespeichert. Djangos standardmäßige Erstkonfiguration verwendet die SQLite-Datenbank.

(1) Um die MySQL-Datenbank nutzen zu können, müssen Sie zunächst den Treiber installieren

Fügen Sie die folgende Anweisung zur Datei  init.py im gleichnamigen Unterverzeichnis des Django-Projekts hinzu:

from pymysql import install_as_MySQLdb
# 让pymysql以MySQLDB的运行模式和Django的ORM对接运行作用是让Django的ORM能以mysqldb的方式来调用PyMySQL。
install_as_MySQLdb() 

(2) Settings.py ÜberarbeitetDATENBANKENPlatzierungsinformationen:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'HOST': '127.0.0.1',  # 数据库主机
        'PORT': 3306,  # 数据库端口
        'USER': 'root',  # 数据库用户名
        'PASSWORD': '123',  # 数据库用户密码
        'NAME': 'student'  # 数据库名字
    }
}

(3) Erstellen Sie eine Datenbank in MySQL

Die Modellebene kann nicht auf Datenbankebene, sondern nur auf Datentabellenebene betrieben werden. Daher muss die Erstellung einer Datenbank durch Ausführen der Tabellenerstellungsanweisung abgeschlossen werden.Datenbank erstellen Student;

Konfigurieren Sie die Protokolldruckstufe: Debug

create database student; # mysql8.0默认就是utf8mb4;
create database student default charset=utf8mb4; # mysql8.0之前的版本
# 注意3: 如果想打印orm转换过程中的sql,需要在settings中进行如下配置:

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'console':{
            'level':'DEBUG',
            'class':'logging.StreamHandler',
        },
    },
    'loggers': {
        'django.db.backends': {
            'handlers': ['console'],
            'propagate': True,
            'level':'DEBUG',
        },
    }
}

2.2 Modellklassen definieren

Modellklasse definieren:

  • Die Modellklasse ist in der Datei „subapplication /models.py“ definiert.

  • Die Modellklasse muss direkt oder indirekt von der Klasse django.db.models.Model  erben.

Nehmen Sie als Nächstes das Studentenmanagement als Beispiel zur Demonstration. [Das System verfügt über etwa 3-4 Tabellen, Studenteninformationen, Kursinformationen, Lehrerinformationen], erstellen Sie eine Unteranwendung für den Schüler, registrieren Sie die Unteranwendung und führen Sie das Weiterleiten der Unteranwendung ein.

2.2.1 settings.py 代码 

INSTALLED_APPS = [
    # ...
    'student',
]

2.2.2 urls.py Yujiro Yudai

urlpatterns = [
    # 省略,如果前面有重复的路由,改动以下。
    path("student/", include("student.urls")),
]

2.2.3 models.py

Definieren Sie Modellklassen in der Datei models.py.

from django.db import models
from datetime import datetime

# 模型类必须要直接或者间接继承于 models.Model
class BaseModel(models.Model):
    """公共模型[公共方法和公共字段]"""
    # created_time = models.IntegerField(default=0, verbose_name="创建时间")
    created_time = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
    # auto_now_add 当数据添加时设置当前时间为默认值
    # auto_now= 当数据添加/更新时, 设置当前时间为默认值
    updated_time = models.DateTimeField(auto_now=True)
    class Meta(object):
        abstract = True # 设置当前模型为抽象模型, 当系统运行时, 不会认为这是一个数据表对应的模型.

class Student(BaseModel):
    """Student模型类"""
    #1. 字段[数据库表字段对应]
    SEX_CHOICES = (
        (0,"女"),
        (1,"男"),
        (2,"保密"),
    )

    # 字段名 = models.数据类型(约束选项1,约束选项2, verbose_name="注释")
    # SQL: id bigint primary_key auto_increment not null comment="主键",
    # id = models.AutoField(primary_key=True, null=False, verbose_name="主键") # django会自动在创建数据表的时候生成id主键/还设置了一个调用别名 pk

    # SQL: name varchar(20) not null comment="姓名"
    # SQL: key(name),
    name = models.CharField(max_length=20, db_index=True, verbose_name="姓名" )

    # SQL: age smallint not null comment="年龄"
    age = models.SmallIntegerField(verbose_name="年龄")

    # SQL: sex tinyint not null comment="性别"
    # sex = models.BooleanField(verbose_name="性别")
    sex = models.SmallIntegerField(choices=SEX_CHOICES, default=2)

    # SQL: class varchar(5) not null comment="班级"
    # SQL: key(class)
    classmate = models.CharField(db_column="class", max_length=5, db_index=True, verbose_name="班级")
    # SQL: description longtext default "" not null comment="个性签名"
    description = models.TextField(default="", verbose_name="个性签名")

    #2. 数据表结构信息
    class Meta:
        db_table = 'db_student'  # 指明数据库表名,如果没有指定表明,则默认为子应用目录名_模型名称,例如: users_student
        verbose_name = '学生信息表'  # 在admin站点中显示的名称
        verbose_name_plural = verbose_name  # 显示的复数名称

    #3. 自定义数据库操作方法
    def __str__(self):
        """定义每个数据对象的显示信息"""
        return "<User %s>" % self.name

(1) Name der Datenbanktabelle

Modellklasse Wenn den Tabellennamen db_table nicht angibt, verwendet Django standardmäßig App-Anwendungsname_lowercase in Kleinbuchstaben Der Modellklassenname ist der Name der Datenbanktabelle.

Der Name der Datenbanktabelle kann über db_table angegeben werden.

(2) Über Primärschlüssel

Django erstellt eine automatisch wachsende Primärschlüsselspalte für die Tabelle . Jedes Modell kann nur eine Primärschlüsselspalte haben.

Wenn Sie die Option verwenden, um das Einschränkungsattribut eines Felds auf die Primärschlüsselspalte (primary_key) festzulegen, erstellt Django keine automatisch wachsende Primärschlüsselspalte mehr.

class Student(models.Model):
    # django会自动在创建数据表的时候生成id主键/还设置了一个调用别名 pk
    id = models.AutoField(primary_key=True, null=False, verbose_name="主键") # 设置主键

Das standardmäßig erstellte Primärschlüsselspaltenattribut ist id, das durch pk ersetzt werden kann, wobei pk als Primärschlüssel geschrieben wird.

(3)Attributbenennungseinschränkungen:

  • Es kann kein reserviertes Schlüsselwort von Python sein.

  • Erlaubt nicht die Verwendung von zwei aufeinanderfolgenden Unterstrichen, was durch die Abfragemethode von Django bestimmt wird. __ kommt von Schlüsselwörtern und kann nicht verwendet werden! ! !

  • Beim Definieren von Attributen müssen Sie den Feldtyp angeben und Optionen über die Parameter des Feldtyps angeben. Die Syntax lautet wie folgt: Attributname = Modelle.Feldtyp (Einschränkungsoption, verbose_name="Kommentar")**

(4)Zeichentyp

(5)Auswahl versprechen

Hinweis: Null ist ein Konzept in der Datenbankkategorie und Leerzeichen ist in der Formularvalidierungskategorie.

(6) Fremdschlüssel

Beim Festlegen eines Fremdschlüssels müssen Sie die Option on_delete verwenden, um anzugeben, wie mit den Tabellendaten umgegangen werden soll, auf die der Fremdschlüssel verweist, wenn die Haupttabelle Daten löscht. In Django. db.models enthält optionale Konstanten:

  • CASCADE-Kaskade: Beim Löschen der Haupttabellendaten werden die Daten in der Fremdschlüsseltabelle zusammen gelöscht.

  • Der PROTECT-Schutz verhindert durch Auslösen einer ProtectedError-Ausnahme das Löschen von Daten in der Haupttabelle, die durch Fremdschlüssel angewendet werden.

  • SET_NULL ist auf NULL gesetzt und nur verfügbar, wenn das Feld null=True null zulässt

  • SET_DEFAULT Auf den Standardwert setzen, nur verfügbar, wenn für das Feld ein Standardwert festgelegt ist

  • SET() wird auf einen bestimmten Wert gesetzt oder ruft eine bestimmte Methode auf, zum Beispiel:

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 UserModel(models.Model):
    user = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.SET(get_sentinel_user),
    )
  • DO_NOTHING bewirkt nichts. Wenn die Datenbank zuvor eine Kaskadierung anzeigt, löst diese Option eine IntegrityError-Ausnahme aus.

Produktklassifizierungstabelle:

Produktinformationstabelle:

  1. Wenn das Modellfeld on_delete=CASCADE ist, löschen Sie Gemüse (id=1), dann die Produkt-ID1 und 3 der Fremdschlüssel-ID =1 wird gelöscht. Das Objekt, das diesen Fremdschlüssel oder diese Eins-zu-eins-Beziehung enthält, wird gelöscht, wenn das zugehörige Objekt gelöscht wird.

  2. Wenn on_delete=PROTECT des Modellfelds zum Löschen von Gemüse verwendet wird, überprüft MySQL automatisch die Produktinformationstabelle, um festzustellen, ob ein Datensatz vorhanden ist mit cid=1. Anschließend werden Sie aufgefordert, alle Datensätze mit id=1 in der Produktinformationstabelle zu entfernen, bevor das Gemüse gelöscht werden kann.

  3. Wenn das Modellfeld on_delete=SET_NULL hat und das Gemüse gelöscht wird, werden alle CIDs der Daten mit cid=1 in der entsprechenden Produktinformationstabelle in cid=null geändert.

  4. Wenn on_delete=SET_DEFAULT des Modellfelds gelöscht wird, wird die CID des Datensatzes mit CID=1 in der entsprechenden Produktinformationstabelle angezeigt gelöscht. Standardwert festlegen.

2.3 Datenmigration

Konvertieren Sie den Code, der das Tabellenschema der Modellklasse definiert, in SQL und synchronisieren Sie ihn mit der Datenbank. Dieser Prozess ist Datenmigration. Die Datenmigration in Django ist eine Klasse, die eine Reihe von Terminalbefehlen bereitstellt, die uns bei der Durchführung der Datenmigration unterstützen.

(1) Generieren Sie Migrationsdateien. Die sogenannten Migrationsdateien sind Migrationsklassen, die Modellklassen ähneln. Dabei handelt es sich hauptsächlich um Klassendateien, die die Struktur der Datentabelle beschreiben:

python manage.py makemigrations

(2) Mit der Datenbank synchronisieren:

python manage.py migrate

Ergänzung: Django stellt intern eine Reihe von Funktionen bereit, und diese Funktionen nutzen auch die Datenbank.Wenn also die erste Datenmigration nach der Erstellung des Projekts durchgeführt wird, werden Sie sehen Weitere Datentabellen im Django-Projekt wurden erstellt. Dazu gehört Djangos integrierte Admin-Site-Verwaltung.

Die Admin-Site ist standardmäßig aktiviert. Wir können http://127.0.0.1:8000/admin verwenden

Diese Site muss über ein Administratorkonto verfügen, um sich anzumelden, damit wir die Daten zum ersten Mal migrieren können. Nachdem wir die Datentabelle haben, können wir den folgenden Terminalbefehl verwenden um ein Superadministratorkonto zu erstellen.

python manage.py createsuperuse

(3) Testdaten hinzufügen

INSERT INTO `db_student`  
(`id`,`name`,`sex`,`class`,`age`,`description`,`created_time`,`updated_time`) 
VALUES
(1,'赵华',1,307,22,'对于勤奋的人来说,成功不是偶然;对于懒惰的人来说,失败却是必然。','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(2,'程星云',1,301,20,'人生应该如蜡烛一样,从顶燃到底,一直都是光明的。','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(3,'陈峰',1,504,21,'在不疯狂,我们就老了,没有记忆怎么祭奠呢?','2020-11-20 10:00:00','2020-11-20 10:00:00'),(4,'苏礼就',1,502,20,'不要为旧的悲伤,浪费新的眼泪。','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(5,'张小玉',2,306,18,'没有血和汗水就没有成功的泪水。','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(6,'吴杰',1,307,19,'以大多数人的努力程度之低,根本轮不到去拼天赋','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(7,'张小辰',2,405,19,'人生的道路有成千上万条, 每一条路上都有它独自的风景。','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(8,'王丹丹',2,502,22,'平凡的人听从命运,坚强的人主宰命运。','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(9,'苗俊伟',1,503,22,'外事找谷歌,内事找百度。','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(10,'娄镇明',1,301,22,'不经三思不求教,不动笔墨不读书。','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(11,'周梦琪',2,306,19,'学习与坐禅相似,须有一颗恒心。','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(12,'欧阳博',1,503,23,'春去秋来,又一年。What did you get ?','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(13,'颜敏莉',2,306,20,'Knowledge makes humble, ignorance makes proud.','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(14,'柳宗仁',1,301,20,'有志者事竟成。','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(15,'谢海龙',1,402,22,'这世界谁也不欠谁,且行且珍惜。','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(16,'邓士鹏',1,508,22,'青,取之于蓝而青于蓝;冰,水为之而寒于水。','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(17,'宁静',2,502,23,'一息若存 希望不灭','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(18,'上官屏儿',2,502,21,'美不自美,因人而彰。','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(19,'孙晓静',2,503,20,'人生本过客,何必千千结;无所谓得失,淡看风和雨。','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(20,'刘承志',1,306,20,'good good study,day day up! ^-^','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(21,'王浩',1,503,21,'积土而为山,积水而为海。','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(22,'钟无艳',2,303,19,'真者,精诚之至也,不精不诚,不能动人。','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(23,'莫荣轩',1,409,22,'不管发生什么事,都请安静且愉快地接受人生,勇敢地、大胆地,而且永远地微笑着。','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(24,'张裕民',1,303,21,'伟大的目标形成伟大的人物。','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(25,'江宸轩',1,407,22,'用最少的悔恨面对过去。','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(26,'谭季同',1,305,21,'人总是珍惜未得到的,而遗忘了所拥有的。','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(27,'李松风',1,504,19,'明天的希望,让我们忘了今天的痛苦。','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(28,'叶宗政',1,407,20,'因害怕失败而不敢放手一搏,永远不会成功。','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(29,'魏雪宁',2,306,20,'成功与失败只有一纸之隔','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(30,'徐秋菱',2,404,19,'年轻是我们唯一拥有权利去编织梦想的时光。','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(31,'曾嘉慧',2,301,19,'有一分热,发一分光。就令萤火一般,也可以在黑暗里发一点光,不必等候炬火。','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(32,'欧阳镇安',1,408,23,'青春虚度无所成,白首衔悲补何及!','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(33,'周子涵',2,309,19,'青春是一个普通的名称,它是幸福美好的,但它也是充满着艰苦的磨炼。','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(34,'宋应诺',2,501,23,'涓滴之水终可以磨损大石,不是由于它力量强大,而是由于昼夜不舍的滴坠。','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(35,'白瀚文',1,305,19,'一个人假如不脚踏实地去做,那么所希望的一切就会落空。','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(36,'陈匡怡',2,505,19,'一份耕耘,一份收获。','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(37,'邵星芸',2,503,22,'冰冻三尺非一日之寒。','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(38,'王天歌',2,302,21,'任何的限制,都是从自己的内心开始的。','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(39,'王天龙',1,302,22,'再长的路,一步步也能走完,再短的路,不迈开双脚也无法到达。','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(40,'方怡',2,509,23,'智者不做不可能的事情。','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(41,'李伟',1,505,19,'人之所以能,是相信能。','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(42,'李思玥',2,503,22,'人的一生可能燃烧也可能腐朽,我不能腐朽,我愿意燃烧起来。','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(43,'赵思成',1,401,18,'合抱之木,生于毫末;九层之台,起于累土。','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(44,'蒋小媛',2,308,22,'不积跬步无以至千里,不积细流无以成江河。','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(45,'龙华',1,510,19,'只要持续地努力,不懈地奋斗,就没有征服不了的东西。','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(46,'牧婧白夜',2,501,21,'读不在三更五鼓,功只怕一曝十寒。','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(47,'江俊文',1,304,19,'立志不坚,终不济事。','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(48,'李亚容',2,304,18,'Keep on going never give up.','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(49,'王紫伊',2,301,22,'最可怕的敌人,就是没有坚强的信念。','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(50,'毛小宁',1,501,19,'要从容地着手去做一件事,但一旦开始,就要坚持到底。','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(51,'董 晴',2,507,19,'常常是最后一把钥匙打开了门。贵在坚持','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(52,'严语',2,405,18,'逆水行舟,不进则退。','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(53,'陈都灵',2,503,19,'无论什么时候,不管遇到什么情况,我绝不允许自己有一点点灰心丧气。','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(54,'黄威',1,301,23,'我的字典里面没有“放弃”两个字','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(55,'林佳欣',2,308,23,'梦想就是一种让你感到坚持,就是幸福的东西。','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(56,'翁心颖',2,303,19,'有目标的人才能成功,因为他们知道自己的目标在哪里。','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(57,'蒙毅',1,502,22,'所谓天才,就是努力的力量。','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(58,'李小琳',2,509,22,'每天早上对自己微笑一下。这就是我的生活态度。','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(59,'伍小龙',1,406,19,'一路上的点点滴滴才是我们的财富。','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(60,'晁然',2,305,23,'人的价值是由自己决定的。','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(61,'端木浩然',1,507,18,'摔倒了爬起来再哭。','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(62,'姜沛佩',2,309,21,'Believe in yourself.','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(63,'李栋明',1,306,19,'虽然过去不能改变,但是未来可以。','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(64,'柴柳依',2,508,23,'没有实践就没有发言权。','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(65,'吴杰',1,401,22,'人生有两出悲剧。一是万念俱灰;另一是踌躇满志','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(66,'杜文华',1,507,19,'有智者立长志,无志者长立志。','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(67,'邓珊珊',2,510,18,'Action is the proper fruit of knowledge.','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(68,'杜俊峰',1,507,23,'世上无难事,只要肯登攀。','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(69,'庄信杰',1,301,22,'知识就是力量。','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(70,'宇文轩',1,402,23,'如果你想要某样东西,别等着有人某天会送给你。生命太短,等不得。','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(71,'黄佳怿',2,510,19,'Learn and live.','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(72,'卫然',1,510,18,'神于天,圣于地。','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(73,'耶律齐',1,307,23,'如果不是在海市蜃楼中求胜,那就必须脚踏实地去跋涉。','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(74,'白素欣',2,305,18,'欲望以提升热忱,毅力以磨平高山。','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(75,'徐鸿',1,403,23,'最美的不是生如夏花,而是在时间的长河里,波澜不惊。','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(76,'上官杰',1,409,19,'生活之所以耀眼,是因为磨难与辉煌会同时出现。','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(77,'吴兴国',1,406,18,'生活的道路一旦选定,就要勇敢地走到底,决不回头。','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(78,'庄晓敏',2,305,18,'Never say die.','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(79,'吴镇升',1,509,18,'Judge not from appearances.','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(80,'朱文丰',1,304,19,'每个人都比自己想象的要强大,但同时也比自己想象的要普通。','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(81,'苟兴妍',2,508,18,'Experience is the best teacher.','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(82,'祝华生',1,302,21,'浅学误人。','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(83,'张美琪',2,404,23,'最淡的墨水,也胜过最强的记性。','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(84,'周永麟',1,308,21,'All work and no play makes Jack a dull boy.','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(85,'郑心',2,404,21,'人生就像一杯茶,不会苦一辈子,但总会苦一阵子。','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(86,'公孙龙馨',1,510,21,'Experience is the father of wisdom and memory the mother.','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(87,'叶灵珑',2,401,19,'读一书,增一智。','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(88,'上官龙',1,501,21,'别人能做到的事,自己也可以做到。','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(89,'颜振超',1,303,19,'如果要飞得高,就该把地平线忘掉。','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(90,'玛诗琪',2,409,22,'每天进步一点点,成功不会远。','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(91,'李哲生',1,309,22,'这不是偶然的失误,是必然的结果。','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(92,'罗文华',2,408,22,'好走的都是下坡路。','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(93,'李康',1,509,19,'Deliberate slowly, promptly.','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(94,'钟华强',1,405,19,'混日子很简单,讨生活比较难。','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(95,'张今菁',2,403,23,'不经一翻彻骨寒,怎得梅花扑鼻香。','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(96,'黄伟麟',1,407,19,'与其诅咒黑暗,不如燃起蜡烛。没有人能给你光明,除了你自己。','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(97,'程荣泰',1,406,22,'明天不一定更好,。但更好的明天一定会来。','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(98,'范伟杰',1,508,19,'水至清则无鱼,人至察则无徒。凡事不能太执着。','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(99,'王俊凯',1,407,21,'我欲将心向明月,奈何明月照沟渠。','2020-11-20 10:00:00','2020-11-20 10:00:00'),
(100,'白杨 ',1,406,19,'闪电从不打在相同的地方.人不该被相同的方式伤害两次。','2020-11-20 10:00:00','2020-11-20 10:00:00');

2.4 MySQL-Operationen

-- 1. 完成student表的创建,导入上面的数据。
-- 2. 使用原来学过的SQL语句,然后对上面导入的学生信息,完成增删查改的操作。
   -- 2.0 查询所有的学生信息(name,age)
       SELECT name,age FROM db_student
   -- 2.1 查询年龄在18-20之间的学生信息[name,age,sex]
       select name,age,sex from db_student where age >=18 and age <=20;
   -- 2.2 查询年龄在18-20之间的男生信息[name,age,sex]
       select name,age,if(sex=1,'男','女') as sex from db_student where age >=18 and age <=20 and sex=1;
   -- 2.3 查询401-406之间所有班级的学生信息[name,age,sex,class]
       select name,age,sex,class from db_student where class between 401 and 406;
   -- 2.4 查询401-406之间所有班级的总人数
       select count(1) as c from db_student where class between 401 and 406;
   -- 2.5 添加一个学生,男,刘德华,302班,17岁,"给我一杯水就行了。",'2020-11-20 10:00:00','2020-11-20 10:00:00'
       insert into db_student (name,sex,class, age, description, created_time,updated_time) values ('刘德华',1,'302', 17, "给我一杯水就行了。",'2020-11-20 10:00:00','2020-11-20 10:00:00');
   -- 2.6 修改刘德华的年龄,为19岁。
       update db_student set age=19 where name='刘德华';
   -- 2.7 刘德华毕业了,把他从学生表中删除
       delete  from db_student where name='刘德华';
   -- 2.8 找到所有学生中,年龄最小的5位同学和年龄最大的5位同学
       select * from db_student order by age asc limit 5;
       select * from db_student order by age desc limit 5;
   -- 2.9 【进阶】找到所有班级中人数超过4个人班级出来
       select class,count(id) as total from db_student group by class having total >= 4;
   -- 2.10【进阶】把上面2.8的要求重新做一遍,改成一条数据实现
       (select * from db_student order by age asc limit 5) union all (select * from db_student order by age desc limit 5);

Drei grundlegende Datenbankoperationen

3.1  Zusatzdatensatz

(1)Speichern

Führen Sie beim Erstellen eines Modellklassenobjekts die save()-Methode des Objekts aus, um es in der Datenbank zu speichern.

student = Student(
    name="刘德华",
    age=17,
    sex=True,
    clasmate=301,
    description="一手忘情水"
)
student.save()
print(student.id) # 判断是否新增有ID

(2)create法

Speichern Sie über model class.objects.create () und geben Sie das generierte Modellklassenobjekt zurück.

student = Student.objects.create(
    name="赵本山",
    age=50,
    sex=True,
    class_number=301,
    description="一段小品"
)
print(student.id)

3.2 Grundlegende Abfrage

ORM stellt einen Abfragesatz [QuerySet] zur Einschränkung der Abfrageergebnisse bereit. Ein neuer Datentyp, dieses QuerySet, ist ein Typ in ORM, der Daten für Abfrageergebnisse speichert. Wir können dieses QuerySet verstehen und es verwenden, um eine Abfrageoptimierung zu erreichen oder die Anzahl der Abfrageergebnisse zu begrenzen. (Bitte beachten Sie, ob das Ergebnis der Abfrage ein Abfragesatz oder ein Modellklassenobjekt ist, da ihre Methoden unterschiedlich sind)

(1)all() Alle Objekte abfragen und das queryset-Objekt zurückgeben. Der Abfragesatz, auch Abfrageergebnissatz oder QuerySet genannt, stellt eine Sammlung von Modellklassenobjekten dar, die aus der Datenbank abgerufen werden.

students = Student.objects.all()
print("students:",students)

(2)filter()

Filtern Sie Objekte, die den Bedingungen entsprechen, und geben Sie Abfragesatzobjekte zurück.

# 查询所有的女生
students = Student.objects.filter(sex=0)
print(students)

(3)get()

Gibt Objekte zurück, die den angegebenen Filterbedingungen entsprechen.Gibt ein und nur ein Ergebnis zurück, wenn es mehr als ein Objekt gibt, das die Filterung erfüllt Bedingungen oder Andernfalls wird ein Fehler ausgegeben.

student = Student.objects.get(pk=1)
print(student)
print(student.description)
# get使用过程中的注意点:get是根据条件返回多个结果或者没有结果,都会报错
try:
    student = Student.objects.get(name="刘德华")
    print(student)
    print(student.description)
except Student.MultipleObjectsReturned:
    print("查询得到多个结果!")
except Student.DoesNotExist:
    print("查询结果不存在!")

(4)first()、last()

sind jeweils der erste Datensatz und der letzte Datensatz des Abfragesatzes.

# 没有结果返回none,如果有多个结果,则返回模型对象
students = Student.objects.all()
# print(students.name)
print(students[0].name)
stu01 = Student.objects.first()
stu02 = Student.objects.last()

print(stu01.name)
print(stu02.name)

(5)exclude()

Filtern Sie Objekte, die nicht den Bedingungen entsprechen, und geben Sie Abfragesatzobjekte zurück.

# 查询张三以外的所有的学生
students = Student.objects.exclude(name="张三")
print(students)

(6)order_by()

Abfrageergebnisse sortieren:

# order_by("字段")  # 按指定字段正序显示,相当于 asc  从小到大
# order_by("-字段") # 按字段倒序排列,相当于 desc 从大到小
# order_by("第一排序","第二排序",...)

# 查询所有的男学生按年龄从高到低展示
# students = Student.objects.all().order_by("-age","-id")
students = Student.objects.filter(sex=1).order_by("-age", "-id")
print(students)

(7)count()

Fragen Sie die Anzahl der Objekte ab:

# 查询所有男生的个数
count = Student.objects.filter(sex=1).count()
print(count)

(8)exists()

Bestimmen Sie, ob der Abfragesatz Daten enthält. Wenn ja, wird True zurückgegeben, andernfalls wird False zurückgegeben.

# 查询Student表中是否存在学生
print(Student.objects.exists())

(9)values()、values_list()

  • value():Konvertieren Sie die Modellobjekte in der Ergebnismenge in ein Wörterbuch und legen Sie die konvertierte Feldliste fest, um den Speicherverbrauch zu reduzieren und die Leistung zu verbessern.

  • values_list():Konvertieren Sie die Modellobjekte in der Ergebnismenge in eine Liste, und Sie können die konvertierte Feldliste (Tupel) festlegen, um den Speicher zu reduzieren Verbrauch. Verbessern Sie die Leistung.

# values 把查询结果中模型对象转换成字典
student_list = Student.objects.filter(classmate="301")
student_list = student_list.order_by("-age")
student_list = student_list.filter(sex=1)
ret1 = student_list.values() # 默认把所有字段全部转换并返回
ret2 = student_list.values("id","name","age") # 可以通过参数设置要转换的字段并返回
ret3 = student_list.values_list() # 默认把所有字段全部转换并返回
ret4 = student_list.values_list("id","name","age") # 可以通过参数设置要转换的字段并返回
print(ret4)
return JsonResponse({},safe=False)

(10)distinct()

Entfernen Sie doppelte Datensätze aus den zurückgegebenen Ergebnissen. Abfragesatz zurückgeben.

# 查询所有学生出现过的年龄
print(Student.objects.values("age").distinct())

3.3 Modellpaste (__)

(1) Fuzzy-Abfrage enthält

Hinweis: Wenn Sie % einschließen möchten, müssen Sie es nicht maskieren, sondern schreiben Sie es einfach direkt. Beispiel: Fragen Sie Schüler ab, deren Namen „华“ enthalten.

Student.objects.filter(name__contains='华')  #  %华%

(2) Fuzzy-Abfragebeginnt mit, endet mit

Beispiel: Fragen Sie Schüler ab, deren Namen mit „文“ enden.

Student.objects.filter(name__endswith='文')   # 文%  

Bei den oben genannten Operatoren wird die Groß-/Kleinschreibung beachtet. Fügen Sie i vor diesen Operatoren hinzu, um anzugeben, dass die Groß-/Kleinschreibung nicht beachtet werden soll, z. B. iexact, icontains, istartswith, iendswith.

(3)model paste 查询之 isnull

Beispiel:Fragen Sie die Schüler ab, deren personalisierte Signatur nicht leer ist.

# 修改Student模型description属性允许设置为null,然后数据迁移
description = models.TextField(default=None, null=True, verbose_name="个性签名")
# 添加测试数据
NSERT INTO student.db_student (name, age, sex, class, description, created_time, updated_time) VALUES ('刘德华', 17, 1, '407', null, '2020-11-20 10:00:00.000000', '2020-11-20 10:00:00.000000');
# 代码操作
tudent_list = Student.objects.filter(description__isnull=True)

(4)Modell einfügen 查询之 in

Beispiel: Fragen Sie Schüler ab, deren Nummer 1, 3 oder 5 ist:

Student.objects.filter(id__in=[1, 3, 5])

Fuzzy-Abfragebereichsbereichsabfrage:

Student.objects.filter(age__range=(20,30))

(5) Vergleichsabfrage der Fuzzy-Abfrage

  • gt 大于 (größer als)

  • gte größer als oder gleich (größer als gleich)

  • lt 小于 (weniger als)

  • lte kleiner oder gleich (kleiner als gleich)

Beispiel: Fragen Sie Schüler ab, deren Anzahl größer als 3 ist

Student.objects.filter(id__gt=3)

(6) Fuzzy-Abfrage Datumsabfrage

Jahr, Monat, Tag, Wochentag, Stunde, Minute, Sekunde: Operationen an Attributen des Datums- und Zeittyps durchführen.

Beispiel: Fragen Sie Studierende ab, die 2010 zu den Daten hinzugefügt wurden.

Student.objects.filter(born_date__year=1980)

Beispiel: Studenteninformationen abfragen, die nach dem 20. Juni 2016 hinzugefügt wurden.

from django.utils import timezone as datetime
student_list = Student.objects.filter(created_time__gte=datetime.datetime(2016,6,20),created_time__lt=datetime.datetime(2016,6,21)).all()
print(student_list)

3.4 Erweiterte Abfrage (weniger verwendet, aber wichtig)

(1) F查询

Bei den vorherigen Abfragen ging es ausschließlich um den Vergleich von Objektattributen mit konstanten Werten. Wie vergleiche ich die beiden Attribute? Antwort: Verwenden Sie das F-Objekt, das in django.db.models definiert ist.

Die Syntax lautet wie folgt:

"""F对象:2个字段的值比较"""
# 获取从添加数据以后被改动过数据的学生 created_time  updated_time 两个属性比较
from django.db.models import F
# SQL: select * from db_student where created_time=updated_time;
student_list = Student.objects.exclude(created_time=F("updated_time"))
print(student_list)

(2) Q-Abfrage (logische ODER-Abfrage)

Mehrere Filter werden nacheinander aufgerufen, um die logische UND-Beziehung auszudrücken, die mit dem Schlüsselwort and im where-Teil der SQL-Anweisung identisch ist.

Beispiel: Fragen Sie Schüler ab, deren Alter über 20 und deren Anzahl unter 30 liegt

Student.objects.filter(age__gt=20,id__lt=30)
Student.filter(age__gt=20).filter(id__lt=30)

Wenn Sie eine logische ODER-Abfrage implementieren müssen, müssen Sie das Q()-Objekt in Kombination mit dem |-Operator verwenden. Das Q-Objekt ist in django.db.models definiert. Die Syntax lautet wie folgt:

Q(Attributname-Operator=Wert) Q(Attributname-Operator=Wert) | Q(Attributname__Operator=Wert)

Beispiel: Um Schüler abzufragen, deren Alter jünger als 19 oder älter als 20 ist (Q(agelt=19) | Q(age**gt=20), verwenden Sie das Q-Objekt wie folgt.

from django.db.models import Q
student_list = Student.objects.filter( Q(age__lt=19) | Q(age__gt=20) ).all()

Q-Objekte können mit &, | verbunden werden, & bedeutet logisches UND, , | bedeutet logisches ODER

Beispiel: Die Abfrage von Schülern, deren Alter größer als 20 Jahre ist oder deren Anzahl unter 30 liegt, kann nur mit dem Q-Objekt umgesetzt werden

Student.objects.filter(Q(age__gt=20) | Q(pk__lt=30))

Der Operator ~ kann auf der linken Seite des Q-Objekts verwendet werden, was nicht bedeutet, nicht. Bei der Arbeit verwenden wir jedoch nur Q-Objekte, um ODER-Operationen auszuführen. Nur bei mehreren verschachtelten komplexen Abfragebedingungen verwenden wir & und ~, um UND- und Nicht-Operationen auszuführen

Student.objects.filter( Q(Q(age__gt=20)&Q(pk__lt=30) )

Beispiel: Fragen Sie Schüler ab, deren Anzahl ~ ungleich 30 ist.

Student.objects.filter(~Q(pk=30))

(3)Geben Sie Ihre Daten nicht aus

Verwenden Sie den Filter „aggregat()“, um die Aggregatfunktion aufzurufen. Zu den Aggregationsfunktionen gehören: Durchschnittlicher Durchschnitt, Zählmenge, maximales Maximum, minimales Minimum, Summensummierung, definiert in django.db.models.

Beispiel: Fragen Sie das Durchschnittsalter der Schüler ab.

from django.db.models import Sum,Count,Avg,Max,Min

Student.objects.aggregate(Avg('age'))
# 或
Student.objects.aggregate(avg_avg = Avg('age')) # 返回{'属性名__聚合类小写':值}

Hinweis: Der Rückgabewert von Aggregat ist ein Wörterbuchtyp mit dem folgenden Format:

{'Attributname__Aggregation-Klasse in Kleinbuchstaben':Wert} Im Allgemeinen wird der Filter „aggregat()“ bei Verwendung von „count“ nicht verwendet.

Beispiel: Fragen Sie die Gesamtzahl der Studierenden ab.

Student.objects.count() # count函数的返回值是一个数字。

(4)Zweigauftrag

QuerySet-Objekt .annotate()

# annotate() 进行分组统计,按前面select 的字段进行 group by
# 返回值依然是 queryset对象,增加了分组统计后的键值对<queryset {}{} >
模型对象.objects.values("id").annotate(course=Count('course__sid')).values('id','course')
# values放在annotate()前面 对应的是group by字段  annotate() 统计
# 查询指定模型, 按id分组 , 将course下的sid字段计数,返回结果是 name字段 和 course计数结果 

# SQL原生语句中分组之后可以使用having过滤,在django中并没有提供having对应的方法,但是可以使用filter对分组结果进行过滤
# 所以filter在annotate之前,表示where,在annotate之后代表having
# 同理,values在annotate之前,代表分组的字段,在annotate之后代表数据查询结果返回的字段

(5)Native Abfrage (selten verwendet)

Um native SQL-Anweisungen auszuführen, können Sie das Modell auch direkt überspringen und natives pymysql verwenden.

ret = Student.objects.raw("SELECT id,name,age FROM db_student")  # student 可以是任意一个模型
 # 这样执行获取的结果无法通过QuerySet进行操作读取,只能循环提取
 print(ret,type(ret))
 for item in ret:
    print(item,type(item))

3.5 Änderungsprotokolle

(1) Verwenden Sie Speichern, um Daten zu aktualisieren (basierend auf dem Modellklassenobjekt)

student  
student.classmate = "303"
# save之所以能提供给我们添加数据的同时,还可以更新数据的原因?
# save会找到模型的字段的主键id的值,
# 主键id的值如果是none,则表示当前数据没有被数据库,所以save会自动变成添加操作
# 主键id有值,则表示当前数据在数据库中已经存在,所以save会自动变成更新数据操作
student.save() # save更新所有字段 性能差

(2)Update-Update (empfohlen) (basierend auf dem Queryset-Objekt)

Die Verwendung des Modells class.objects.filter().update() gibt die Anzahl der betroffenen Zeilen zurück

# update是全局更新,只要符合更新的条件,则全部更新,因此强烈建议加上条件!!!
student = Student.objects.filter(name="赵华",age=22).update(name="刘芙蓉",sex=True)
print(student)

3.6 Datensätze löschen

Es gibt zwei Möglichkeiten zum Löschen

(1) Modelleinführung.delete

student = Student.objects.get(id=13)
student.delete()

(2)Modell class.objects.filter().delete()  Basierend auf dem Abfragesatzobjekt

Student.objects.filter(id=14).delete() Code:

# 1. 先查询到数据模型对象。通过模型对象进行删除  (pk指向主键无论主键叫什么)
# student = Student.objects.filter(pk=13).first()
# student.delete()

# 2. 直接删除
ret = Student.objects.filter(pk=100).delete()
print(ret)
# 务必写上条件,否则变成了清空表了。ret = Student.objects.filter().delete()

4. Assoziationsmodell erstellen

-- Version 1 (Zu viel Platz für doppelten Inhalt)
-- Schüler
ID-Name Alter Klassenname Klassenlehrer Klassennummer
1 rain 22 s12 78 
2 alvin 24 s12 78 
3 eric 23 s12 78 

-- Version 2: Eins-zu-viele wird erstellt, indem ein zugehöriges Feld „class_id“ im Multitabellen-Schüler erstellt wird (eine Klasse kann mehreren Schülern entsprechen und ein Schüler kann nur in einer Klasse sein) 2 Alvin 24 1  3 eric 23 1  1 Regen 22 1  ID-Name Alter Klassen-ID  
-- Schüler



-- class
id  class_name  class_tutor  class_num
1    s12         zhangsan     78 
2    s13         lisi         88

-- Fragen Sie den Namen der Klasse ab, in der sich der Schüler-Regen befindet.
Wählen Sie die Klassen-ID des Schülers aus, wobei Name = „Regen“ – 1 ist.< a i=2> wähle Klassenname aus der Klasse aus, wobei die ID = 1 ist

– Der Aufbau einer Viele-zu-Viele-Beziehung wird durch die Erstellung einer dritten Beziehungstabelle erreicht.

-- Kurs (Wahlkurs)
 ID-Name  
 
 1 Python
 2 Java< a i=4> 3 php

 – student2course (many-to-many erstellt die dritte Beziehungstabelle)
 
 id student_id course_id
  1 1 1 1 1 – der Student mit ID 1 Der Student mit ID 1 hat den Kurs mit ID 1 besucht
  2 1 2 2 -- Der Student mit ID 1 hat den Kurs mit ID 2 besucht
  3 2 2 2 – Der Student mit der ID 2 hat den Kurs mit der ID 2 besucht

-- Eins-zu-eins, ähnlich wie eins-zu-viele, eine eindeutige Eindeutigkeitsbeschränkung für verwandte Felder kann in jeder der beiden Beziehungstabellen eingerichtet werden
-- Studentenvereinigung Feld student_detail_id
id name age class_id student_detail_id(unique)  
1 rain 22 1 1 1
2 alvin 24 1 1 3 
3 eric 23 1 2

-- student_detail
id  addr   email   tel   
1   bj     123     110 
2   bj     234     911
3   nj     456     112

create table course(
    id int primary key auto_increment,
    name varchar(32)
);
create table student(
    id int primary key auto_increment,
    name varchar(32),
    class_id int not null, # 这个字段是逻辑字段 有这个就可以了 逻辑上的约束
  
    foreign key (class_id) reference class(id) # 这个是约束是语法上的约束强绑定 向删一个字段不让删 不是必须加的 开发的时候用的少 影响性能
);
create table student2course(
    id int primary key auto_increment,
    student_id int not null,
    course_id int not null,
  
    foreign key (student_id) reference student(id) on delete cascade, # 级联 删除主键以后, 对应的外键所在数据也被删除
    foreign key (course_id) reference course(id),
);

4.1 Beispiel

Gehen wir von folgenden Konzepten, Feldern und Zusammenhängen aus

  • Klassenmodell: Klassenname, Lehrer.

  • Kursmodell: Kursname, Dozent usw.

  • Studentenmodell: Studenten haben Namen, Alter und nur eine Klasse, sodass eine Eins-zu-viele-Beziehung zum Stundenplan besteht. Sie haben mehrere Kurse belegt, sodass eine Viele-zu-viele-Beziehung zum Stundenplan besteht ( viel zu viel)

  • Studentendaten: Die Privatadresse, die Mobiltelefonnummer, die E-Mail-Adresse und andere detaillierte Informationen des Studenten sollten in einer Eins-zu-Eins-Beziehung zum Studentenmodell stehen (Eins-zu-Eins).

Das Modell ist wie folgt aufgebaut:

from django.db import models
# Create your models here.

class Clas(models.Model):
    name = models.CharField(max_length=32, unique=True, verbose_name="班级名称")

    class Meta:
        db_table = "db_class"

class Course(models.Model):
    name = models.CharField(max_length=32, unique=True, verbose_name="课程名称")

    class Meta:
        db_table = "db_course"

class Student(models.Model):
    sex_choices = (
        (0, "女"),
        (1, "男"),
        (2, "保密"),
    )

    name = models.CharField(max_length=32, unique=True, verbose_name="姓名")
    age = models.SmallIntegerField(verbose_name="年龄", default=18)  # 年龄
    sex = models.SmallIntegerField(choices=sex_choices)
    birthday = models.DateField()

    # 一对多 参数设置
    # to="Clas" 和哪个表建立一对多的关系
    # on_delete= 关联关系的设置  删除模式
        # models.CASCADE    删除主键以后, 对应的外键所在数据也被删除
        # models.DO_NOTHING 删除主键以后, 对应的外键不做任何修改
    # db_constraint=False 设置为没有外键约束
    # 反向查找字段 related_name
    # class_id int not null,
    # foreign key (class_id) reference class(id) 下面这句等同于这两句语句
    # 在数据库创建一个关联字段:clas_id
    clas = models.ForeignKey(to="Clas", related_name='student_list',on_delete=models.CASCADE, db_constraint=False)

    # 多对多 :创建第三张表db_student2course, student表 to course表
    # 建立多对多的关系,ManyToManyField可以建在两个模型中的任意一个,自动创建第三张表
    # 数据库迁移时有四个模型类五张表 多了一个关系表
    courses = models.ManyToManyField("Course", db_table="db_student2course")

    # 一对一,使用同一对多 ,建立关联字段 放在两个模型类中任意一个都可以,在数据库中生成关联字段:stu_detail_id
    stu_detail = models.OneToOneField("StudentDetail", on_delete=models.CASCADE)
  
    # 表名
    class Meta:
        db_table = "db_student"

    def __str__(self):
        return self.name

class StudentDetail(models.Model):
    tel = models.CharField(max_length=32)
    email = models.EmailField()
    description = models.TextField(null=True, verbose_name="个性签名")

    class Meta:
        db_table = "db_student_detail"

4.2 Assoziationszusatz

(1) Eins-zu-viele und eins-zu-eins

stu = Student.objects.create(name="王五", age=23, sex=1, birthday="1991-11-12", clas_id=9, stu_detail_id=6)
  print(stu.name)
  print(stu.age)
  print(stu.sex)
  print(stu.clas_id)  # 9
  print(stu.stu_detail_id)  # 6
  print(stu.clas)  # 一个模型类对象 一个学生对应一个班级
  print(stu.stu_detail)  # 模型类对象

  # 查询stu这个学生的班级名称 一对多的关联对象
  print(stu.clas.name)
  print(stu.stu_detail.tel)

(2) Viele zu viele

# 一对一和多 都有自己的模型类
    stu = Student.objects.create(name="rain", age=33, sex=1, birthday="1996-11-12", clas_id=9, stu_detail_id=7)
  
    # 多对多第三张表没有自己的模型类 所以没有向其他表那样直接create
    # (1) 添加多对多的数据

    # 添加多对多方式1
    # 在student模型类中的courses变量中创建的关系表(stu对象里有courses属性) 所有的对这表的方法都赋值到了courses属性里面
    c1 = Course.objects.get(title="思修") # 获取主键id
    c2 = Course.objects.get(title="逻辑学")
    stu.courses.add(c1,c2)

    # 添加多对多方式2
    # 这个stu对象变成张三了 对张三进行添加课程
    stu = Student.objects.get(name="张三")
    stu.courses.add(5,7) # 给学生绑定课程 添加课程id
 
    # 添加多对多方式3 (这个用的多) *[6,7] 星列表 位置传参 客户端会以列表方式传参
    stu = Student.objects.get(name="李四")
    stu.courses.add(*[6,7])

    # (2) 删除多对多记录

   stu = Student.objects.get(name="李四")
   stu.courses.remove(7)

    # (3) 清空多对多记录:clear方法

    stu = Student.objects.get(name="rain")
    stu.courses.clear()

    # (4) 重置多对多记录:set方法 [5,8]

    stu = Student.objects.get(name="李四")
    stu.courses.set([5,8])

    # (5) 多对多记录查询: all
    # 查询李四所报课程的名称
    stu = Student.objects.get(name="李四")
    courses = stu.courses.all()  # 返回 <QuerySet [<Course: Course object (5)>, <Course: Course object (8)>]>
    courses = stu.courses.all().values("title")
    print(courses)

Hinweis: Was bedeuten stu.clas one-to-many, stu.stu_detail one-to-one und stu.courses Many-to-many?

4.3 Verwandte Abfrage

4.3.1 Objektbasierte Abfrage (Unterabfrage)

Unterabfrage – Mehrere Abfragen. Das Ergebnis einer Abfrage ist die Bedingung für die nächste Abfrage:

# **********************************  一对多查询
    # 查询张三所在班级的名称 正向查询 通过关联字段属性查询stu.clas 先把张三的人查出来再查班级
    # stu = Student.objects.get(name="张三")
    # print(stu.clas.name)

    # 查询计算机科学与技术2班有哪些学生

    # clas = Clas.objects.get(name="计算机科学与技术2班")
    # 反向查询方式1:
    # ret = clas.student_set.all()  # 反向查询 按表名小写_set 班级找学生是一个集合所以有_set标识
    # print(ret) # <QuerySet [<Student: 张三>, <Student: 李四>]>
    # 反向查询方2:一般用此
    # 模型类中clas属性的参数设置 反向字段related_name='student_list'
    # print(clas.student_list.all())  # <QuerySet [<Student: 张三>, <Student: 李四>]>

    # **********************************  一对一查询

    # 查询李四的手机号
    # stu = Student.objects.get(name="李四")
    # print(stu.stu_detail.tel)

    # 查询110手机号的学生姓名和年龄

    # stu_detail = StudentDetail.objects.get(tel="110")
    # 反向查询方式1: 表名小写  一对一查询结果是一个对象不是查询集 所以不需要_set
    # print(stu_detail.student.name)
    # print(stu_detail.student.age)
    # 反向查询方式2: related_name
    # print(stu_detail.stu.name)
    # print(stu_detail.stu.age)

    # **********************************  多对多查询

    # 查询张三所报课程的名称

    # stu = Student.objects.get(name="张三")
    # print(stu.courses.all())  # QuerySet [<Course: 近代史>, <Course: 篮球>]>

    # 查询选修了近代史这门课程学生的姓名和年龄
    # course = Course.objects.get(title="近代史")
    # 反向查询方式1: 表名小写_set
    # print(course.student_set.all()) # <QuerySet [<Student: 张三>, <Student: 李四>]>

    # 反向查询方式2:related_name
    # print(course.students.all())
    # print(course.students.all().values("name","age")) # 加values返回的就不是对象集合了 是字典集合<QuerySet [{'name': '张三', 'age': 22}, {'name': '李四', 'age': 24}]>

Bei Vorwärts- und Rückwärtsabfragen können Sie sehen, dass sich die zugehörigen Felder in der Tabelle befinden. Wenn Sie in der Schülertabelle nach anderen Schülern suchen, werden diese in umgekehrter Richtung angezeigt. Wenn Sie nach Schülern suchen, werden alle anderen Suchanfragen angezeigt die Vorwärtsrichtung.

(1) Abfrage nach Feld weiterleiten

(2) Rückwärtsabfrage basierend auf dem Klassennamen in Kleinbuchstaben _set oder related_name

4.3.2 Abfrage basierend auf doppeltem Unterstrich (Join-Abfrage)

Eine Unterabfrage besteht darin, mehrere Anweisungen zu schreiben, und eine Join-Abfrage besteht darin, eine einzelne Anweisung zu schreiben, um die Tabelle zu verknüpfen.

# 查询张三的年龄
    ret = Student.objects.filter(name="张三").values("age")
    print(ret) # <QuerySet [{'age': 22}]>

    # (1) 查询年龄大于22的学生的姓名以及所在名称班级
    # select db_student.name,db_class.name from db_student inner join db_class on db_student.clas_id = db_class.id where db_student.age>22;

    # 方式1 : Student作为基表 正向查询 (filter是做where的 values是做select的)
    # 跨表需要从student join到 clas表 (clas__name)
    ret = Student.objects.filter(age__gt=22).values("name","clas__name")
    print(ret)
    # 方式2 :Clas表作为基表 反向查询  age在student表中 需要跨表查询(__age__gt  __name) clas设置了related_name所以使用student_list(没设置使用表名小写)
    ret = Clas.objects.filter(student_list__age__gt=22).values("student_list__name","name")
    print(ret)

    # (2) 查询计算机科学与技术2班有哪些学生

    ret = Clas.objects.filter(name="计算机科学与技术2班").values("student_list__name")
    print(ret)  #<QuerySet [{'student_list__name': '张三'}, {'student_list__name': '李四'}]>

    # (3) 查询张三所报课程的名称

    ret = Student.objects.filter(name="张三").values("courses__title")
    print(ret) # <QuerySet [{'courses__title': '近代史'}, {'courses__title': '篮球'}]>

    # (4) 查询选修了近代史这门课程学生的姓名和年龄

    ret = Course.objects.filter(title="近代史").values("students__name","students__age")
    print(ret) # <QuerySet [{'students__name': '张三', 'students__age': 22}, {'students__name': '李四', 'students__age': 24}]>

    # (5) 查询李四的手机号

    ret = Student.objects.filter(name='李四').values("stu_detail__tel")
    print(ret)  # <QuerySet [{'stu_detail__tel': '911'}]>

  
    # 连续跨表 stu__clas__name
    # (6) 查询手机号是110的学生的姓名和所在班级名称

    # 方式1
    ret = StudentDetail.objects.filter(tel="110").values("stu__name","stu__clas__name")
    print(ret) # <QuerySet [{'stu__name': '张三', 'stu__clas__name': '计算机科学与技术2班'}]>

    # 方式2:
    ret = Student.objects.filter(stu_detail__tel="110").values("name","clas__name")
    print(ret) # <QuerySet [{'name': '张三', 'clas__name': '计算机科学与技术2班'}]>

(1) Zuordnung nach zugeordnetem Feld weiterleiten

(2) Umgekehrt durch Kleinbuchstaben des Klassennamens oder des zugehörigen_Namens

4.4 Verwandte Gruppenabfrage

# from django.db.models import Avg, Count, Max, Min
# values在annotate前面表示分组 annotate表示统计
# 单独的模型类进行分组
ret = Student.objects.values("sex").annotate(c = Count("name"))
print(ret) # <QuerySet [{'sex': 0, 'c': 1}, {'sex': 1, 'c': 3}]>

# 关联模式下分组
# (1)查询每一个班级的名称以及学生个数
# 反跨表 有related_name , student_list__name

ret = Clas.objects.values("name").annotate(c = Count("student_list__name"))
print(ret) # <QuerySet [{'name': '网络工程1班', 'c': 0}, {'name': '网络工程2班', 'c': 0}, {'name': '计算机科学与技术1班', 'c': 0}, {'name': '计算机科学与技术2班', 'c': 1}, {'name': '软件1班', 'c': 3}]>

# (2)查询每一个学生的姓名,年龄以及选修课程的个数

ret = Student.objects.values("name","age").annotate(c=Count("courses__title"))
print(ret) # <QuerySet [{'name': 'rain', 'c': 0}, {'name': '张三', 'c': 2}, {'name': '李四', 'c': 2}, {'name': '王五', 'c': 0}]>

# 没有values 默认显示所有字段
# Student.objects.all() 返回的是一个queruset集合 每个学生就是一个组
ret = Student.objects.all().annotate(c=Count("courses__title")).values("name","age","sex","c")
# print(ret)

# (3) 每一个课程名称以及选修学生的个数
ret = Course.objects.all().annotate(c = Count("students__name")).values("title","c")
print(ret) # <QuerySet [{'title': '近代史', 'c': 2}, {'title': '思修', 'c': 0}, {'title': '篮球', 'c': 1}, {'title': '逻辑学', 'c': 1}, {'title': '轮滑', 'c': 0}]>

# (4)  查询选修课程个数大于1的学生姓名以及选修课程个数
ret = Student.objects.all().annotate(c=Count("courses__title")).filter(c__gt=1).values("name","c")
print(ret) # <QuerySet [{'name': '张三', 'c': 2}, {'name': '李四', 'c': 2}]>

# (5) 查询每一个学生的姓名以及选修课程个数并按着选修的课程个数进行从低到高排序
ret = Student.objects.all().annotate(c=Count("courses__title")).order_by("c").values("name","c")
print(ret)

おすすめ

転載: blog.csdn.net/March_A/article/details/133588695