~~ Du hast gesagt "Django hat viele Experten in der Firma" !!!! ~~
Future Advent Calendar 2019 Dies ist der Artikel am 10. Tag. Der diesjährige Adventskalender ist beängstigend, weil es zu viele Sachen gibt ...
Dieses Mal schrieb ich Golang und Rails, Es wird das erste Mal sein, dass ein System mit Python ~~ Rushing ~~ erstellt wird, und ich werde veröffentlichen, wovon ich süchtig war.
Das Modell von Django spiegelt keine Einstellungen wie die Standardeinstellungen in der Datenbank wider!
Die Umgebung basiert auf der Annahme, dass Einführung in Python Django (1) in der Reihenfolge bis zum Artikel (6) abgeschlossen ist. Es ist keine offizielle Referenz, aber es war ein guter Artikel. Ich bin froh, dass das fertige Produkt unter https://github.com/kakky/mybook20 verfügbar ist. (Die folgende Überprüfung wird mit diesem Commit durchgeführt. Https://github.com/kakky/mybook20/commit/82e741652bfd7f82f5c0bc601e04b7585632d266)
Wenn Sie das oben Gesagte geklont haben, gehen Sie als vorläufige Vorbereitung wie folgt vor.
$ python manage.py migrate
$ python manage.py createsuperuser
$ python manage.py runserver
Wenn Sie hier stolpern, lesen Sie bitte den angenommenen Artikel. Der obige Befehl ist in diesem Artikel geschrieben. Einführung in Python Django (3)
Lassen Sie uns das "Klassenbuch" von "cms / models.py" wie folgt ändern.
cms/models.py
class Book(models.Model):
"""Bücher"""
name = models.CharField('Buchtitel', max_length=255, unique=True)
publisher = models.CharField('der Herausgeber', max_length=255)
page = models.IntegerField('Seitenzahl', blank=True, default=0)
on_sale = models.BooleanField('Verkauf', default=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def __str__(self):
return self.name
Fügen Sie created_at
und updated_at
hinzu, geben Sie die aktuelle Zeit beim Einfügen bzw. Aktualisieren ein, fügen Sie on_sale
hinzu und belassen Sie den Standardwert auf True.
Zusätzlich wird name
mit unique = True
hinzugefügt.
Standardmäßig haben alle Spalten "null = False", was das Verhalten der Nicht-Null-Einschränkung ist.
Da wir das Modell geändert haben, erstellen Sie eine Migrationsdatei wie folgt. Ich bin wütend, den Anfangswert einzugeben, also setze ihn auf "timezone.now".
$ python manage.py makemigrations
You are trying to add the field 'created_at' with 'auto_now_add=True' to book without a default; the database needs something to populate existing rows.
1) Provide a one-off default now (will be set on all existing rows)
2) Quit, and let me add a default in models.py
Select an option: 1
Please enter the default value now, as valid Python
You can accept the default 'timezone.now' by pressing 'Enter' or you can provide another value.
The datetime and django.utils.timezone modules are available, so you can do e.g. timezone.now
Type 'exit' to exit this prompt
[default: timezone.now] >>> timezone.now
Migration anwenden.
python manage.py migrate
Gehen Sie zu http://127.0.0.1:8000/admin/ und fügen Sie ein Buch hinzu. (Details weggelassen)
Werfen wir einen Blick auf den Inhalt der Datenbank.
$ sqlite> select * from cms_book;
id|name|page|created_at|on_sale|updated_at|publisher
1|Der Liebling des Teufels|100|2019-12-09 13:03:29.102973|1|2019-12-09 13:03:29.132151|Kakugawa Bunko
Es enthält created_at
updated_at und sieht gut aus. * On_sale
ist 1 und steht für True.
Fügen wir es nun direkt in die DB ein.
sqlite> insert into cms_book(name, publisher, page) values('Teufelshandlied', 'Shueisha', 200);
Error: NOT NULL constraint failed: cms_book.created_at
Aus irgendeinem Grund ärgere ich mich darüber, dass created_at
, das automatisch die aktuelle Zeit eingeben sollte, die Nicht-Null-Einschränkung verletzt.
Versuchen Sie also, created_at
und updated_at
mit CURRENT_TIMESTAMP zu füllen.
sqlite> insert into cms_book(
name,
publisher,
page,
created_at,
updated_at
)
values(
'Teufelshandlied',
'Shueisha',
200,
CURRENT_TIMESTAMP,
CURRENT_TIMESTAMP
)
;
Error: NOT NULL constraint failed: cms_book.on_sale
Dieses Mal ärgere ich mich, dass on_sale, das den Standardwert hätte angeben sollen, null ist.
Da es keine Hilfe dafür gibt, gibt on_sale
auch den Wert explizit an.
sqlite> insert into cms_book(
name,
publisher,
page,
on_sale,
created_at,
updated_at
)
values(
'Teufelshandlied',
'Shueisha',
200,
0,
CURRENT_TIMESTAMP,
CURRENT_TIMESTAMP
)
;
sqlite> select * from cms_book;
id|name|page|created_at|on_sale|updated_at|publisher
1|Der Liebling des Teufels|100|2019-12-09 13:03:29.102973|1|2019-12-09 13:03:29.132151|Kakugawa Bunko
2|Teufelshandlied|200|2019-12-09 13:12:17|0|2019-12-09 13:12:17|Shueisha
Diesmal konnte ich erfolgreich einfügen. __ Warum ist in einer Spalte mit "default", "auto_now_add", "auto_now" "NOT NULL Constraint" aufgetreten? __ __ Ich werde sie der Reihe nach anschauen.
sqlite> .schema cms_book
CREATE TABLE IF NOT EXISTS "cms_book"(
"id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,
"name" varchar(255) NOT NULL UNIQUE,
"page" integer NOT NULL,
"created_at" datetime NOT NULL,
"on_sale" bool NOT NULL,
"updated_at" datetime NOT NULL,
"publisher" varchar(255) NOT NULL
)
;
Zum Zeitpunkt der Tabellendefinition sind die Systeme default
und auto_now
bereits gelöscht.
Überprüfen Sie die Migrationsdatei und die generierte SQL.
cms/migrations/0002_auto_20191209_2202.py
operations = [
migrations.AddField(
model_name='book',
name='created_at',
field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now),
preserve_default=False,
),
migrations.AddField(
model_name='book',
name='on_sale',
field=models.BooleanField(default=True, verbose_name='Verkauf'),
),
migrations.AddField(
model_name='book',
name='updated_at',
field=models.DateTimeField(auto_now=True),
),
migrations.AlterField(
model_name='book',
name='name',
field=models.CharField(max_length=255, unique=True, verbose_name='Buchtitel'),
),
migrations.AlterField(
model_name='book',
name='publisher',
field=models.CharField(max_length=255, verbose_name='der Herausgeber'),
),
]
$ python manage.py showmigrations
admin
[X] 0001_initial
(Kürzung)
cms
[X] 0001_initial
[X] 0002_auto_20191209_2202
(Kürzung)
$ python manage.py sqlmigrate cms 0002_auto_20191209_2202
BEGIN;
(Kürzung)
--
-- Alter field publisher on book
--
CREATE TABLE "new__cms_book"(
"id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,
"name" varchar(255) NOT NULL UNIQUE,
"page" integer NOT NULL,
"created_at" datetime NOT NULL,
"on_sale" bool NOT NULL,
"updated_at" datetime NOT NULL,
"publisher" varchar(255) NOT NULL
)
;
INSERT INTO "new__cms_book"(
"id",
"name",
"page",
"created_at",
"on_sale",
"updated_at",
"publisher"
)
SELECT
"id",
"name",
"page",
"created_at",
"on_sale",
"updated_at",
"publisher"
FROM
"cms_book"
;
DROP TABLE "cms_book"
;
ALTER TABLE "new__cms_book" RENAME TO "cms_book"
;
COMMIT
;
In der Migrationsdatei können Sie sehen, dass die Notation wie folgt lautet: "default = True". Ich habe das generierte SQL weggelassen, weil es länger ist (ich weiß nicht, warum Sie sich die Mühe machen, es zu erstellen, zu löschen, zu ändern). Bitte beachten Sie die folgenden Teile.
CREATE TABLE "new__cms_book"(
"id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,
"name" varchar(255) NOT NULL UNIQUE,
"page" integer NOT NULL,
"created_at" datetime NOT NULL,
"on_sale" bool NOT NULL,
"updated_at" datetime NOT NULL,
"publisher" varchar(255) NOT NULL
)
Der Standardwert und auto_now sind brillant gesunken. Übrigens war dieses Verhalten nicht nur in SQLite, sondern auch in Postgresql usw. dasselbe.
Anfangs konnte ich es nicht leicht finden, selbst wenn ich gegoogelt habe, aber dieses Phänomen wurde in diesem Stapelüberlauf erwähnt. https://stackoverflow.com/questions/53706125/django-default-at-database
Mit anderen Worten, "Modell und DB-Schema sind unterschiedlich mon. Nicht null und eindeutig werden angewendet, aber Standard ist unmöglich!" ...
Ich denke, dass es viele Fälle gibt, in denen eine Datenbank aus mehreren Anwendungen referenziert / aktualisiert oder manuell gepatcht wird, aber Django-Benutzer werden keine Probleme haben ... Um dieses Problem zu umgehen, scheint es besser zu sein, DDL (Raw SQL) kontinuierlich aus ERD zu generieren, als DDL, das aus einem Modell generiert wurde.
Ich war überrascht, wie beliebt FW ein solches Verhalten mit praktischen Problemen zulässt. Ich habe erneut bekräftigt, dass es wichtiger ist, Low-Layer-Teile wie das Lesen von Raw-SQL zu unterdrücken, um Probleme zu lösen.
Recommended Posts