Django_mosh
Django mosh
shell django-admin
django-admin startproject <proj name> .
run server
python manage.py runserver
app 可以通过 proj 初 始 settings.py 集成
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'new proj name',
]
创建新 app
python manage.py startapp <appname>
添加进路由
from django.contrib import admin
from django.urls import include, path
urlpatterns = [
path('admin/', admin.site.urls),
path('__debug__/', include('debug_toolbar.urls')),
path('playground', include('playground.urls')),
]
views: 类似 Controller req->res, request handler
debug: django-debug-toolbar 配置方法文档
urlconf
# --- app added
from django.urls import path
from . import views
# URLconf
urlpatterns = [
path('hello/', views.say_hello) # '/' is important
]
# --- main proj
from django.contrib import admin
from django.urls import include, path
urlpatterns = [
path('admin/', admin.site.urls),
path('__debug__/', include('debug_toolbar.urls')),
path('playground/', include('playground.urls')),
]
其中 urlpatterns 是 一个内置路由变量
model 类似 entity
from django.db import models
# Create your models here.
class Product(models.Model):
title = models.CharField(max_length=255)
description = models.TextField()
# 9999.99
price = models.DecimalField(max_digits=6, decimal_places=2)
inventory = models.IntegerField()
last_update = models.DateTimeField(auto_now=True)
class Customer(models.Model):
first_name = models.CharField(max_length=255)
last_name = models.CharField(max_length=255)
email = models.EmailField(unique=True)
phone = models.CharField(max_length=20)
birth_date = models.DateField(null=True) # nullable
注意:
- 没有 id field django 自动创建(如果没有指定主键)
类似枚举和@JsonProperty
MEMBERSHIP_BRONZE = 'B'
MEMBERSHIP_SILVER = 'S'
MEMBERSHIP_GOLD = 'G'
MEMBERSHIP_CHOICES = [
(MEMBERSHIP_BRONZE, 'Bronze'),
(MEMBERSHIP_SILVER, 'Silver'),
(MEMBERSHIP_GOLD, 'Gold'),
]
membership = models.CharField(max_length=1, choices=MEMBERSHIP_CHOICES,
default=MEMBERSHIP_BRONZE)
其中'B'是实际存在数据库之中的值,'Bronze'是实际对上呈现的值
OneToOne Mapping
class Address(models.Model):
city = models.CharField(max_length=255)
customer = models.OneToOneField(Customer, on_delete=models.CASCADE, primary_key=True)
on_delete 可以设置多种级联,例如 SETNULL,SETDEFAULT,PROTECT,CASCADE
django 里面 OneToOne 默认是双向的,会自动在 Customer 之中生成 address 属性
OneToMany: db view,直接使用 ForeignKey
e.g
class Cart(models.Model):
customer = models.OneToOneField(Customer, on_delete=models.CASCADE, primary_key=True)
class CartItem(models.Model):
cart = models.ForeignKey(Cart, on_delete=models.CASCADE)
product = models.ForeignKey(Product, on_delete=models.CASCADE)
number = models.IntegerField()
added_at = models.DateTimeField(auto_now_add=True)
ManyToMany
class Promotion(models.Model):
# 促销, 和产品是多对多关系
description = models.CharField(max_length=255)
discount = models.FloatField()
start_at = models.DateTimeField(null=True)
end_at = models.DateField(null=True)
class Product(models.Model):
title = models.CharField(max_length=255)
description = models.TextField()
# 9999.99
price = models.DecimalField(max_digits=6, decimal_places=2)
inventory = models.IntegerField()
last_update = models.DateTimeField(auto_now=True)
collection = models.ForeignKey('Collection', on_delete=models.PROTECT)
promotion = models.ManyToManyField('Promotion') # get by default 'product_set' in promotion
处理循环依赖:
Collection 类之中有一个 feature product,同时 product 被 Collection 包含,解决方法为加上''
相当于留了解析符号,但会影响修改时的改动,所以一般不要用
解决 django 自动创建反向依赖导致的重名问题,一种是指定 related_name,另一种直接指定为'+'意思是不生成反向依赖
from django.db import models
class Collection(models.Model):
feature_product = models.ForeignKey('Product', on_delete=models.SET_NULL,null=True, related_name='+')
class Product(models.Model):
collection = models.ForeignKey(Collection, on_delete=models.PROTECT)
泛型关系
如果我们想要有一个 tag, 用于对任意物体打标签(因而需要与具体的 store 解耦),怎么做?
from django.db import models
from django.contrib.contenttypes.fields import GenericForeignKey
# Create your models here.
class Tag(models.Model):
title = models.CharField(max_length=255)
class TagItem(models.Model):
tag = models.ForeignKey(Tag, on_delete=models.CASCADE)
# Generic
# Type, ID -> content
content_type = models.ForeignKey('contenttypes.ContentType', on_delete=models.CASCADE)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey('content_type', 'object_id')
也就是说 content_type 入库的实际上是一个序列化后的类型信息变量(例如 string),而 object_id 是 int,运行时可以计算的结果 content_obj?
答: 是的,
content_type 字段存储的是一个 ContentType 对象的 ID,这个对象代表了关联对象的类型。ContentType 是 Django 的一个内置模型,它存储了所有已注册模型的信息,包括模型的名字和它所在的应用的名字。
object_id 字段存储的是关联对象的 ID。这个 ID 是关联对象在它所在的数据库表中的主键。
content_object 是一个 GenericForeignKey 字段,它不会在数据库中创建对应的列,而是在运行时通过 content_type 和 object_id 的值去获取关联对象。访问 content_object 属性时,Django 会根据 content_type 和 object_id 的值去查询对应的对象,并返回这个对象。
练习:LikeItem
from django.db import models
from django.contrib.auth.models import User
from django.contrib.contenttypes.fields import GenericForeignKey
# Create your models here.
class LikeItem(models.Model):
# who likes what
user = models.ForeignKey(User, on_delete=models.CASCADE)
content_type = models.ForeignKey('contenttypes.ContentType', on_delete=models.CASCADE)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey('content_type', 'object_id')
migrations
应该让 Django 完成建库建表等操作
python manage.py makemigrations
migration 是 django 自动生成的以库为单位的 db 修改操作的抽象,包含 log 等功能
修改 entity 之后也简单的重新运行 migration 就行(可能要改改文件名(生成的文件名类似 git commit 的 hashID,是会出现在后续 migration 的 depandency 里面的))
migration 只是创建了操作,之后使用如下入库
python manage.py migrate
slug
slug = models.SlugField(default='-')
slug 是一个可以匹配字母数字下划线和连字符的动态路由, 用于使一个东西对搜索引擎检索更加友好
例如,如果想检索一篇博客some-blog,一个 url 为myweb/blogs/some-blog的子网页肯定比myweb/blogs/1容易检索