作者:刘宾, [email protected]
请尊重作者著作权,转载请注明出处,谢谢!
数据模型
字段
1. 数据类型
Django内置数据类型
2. 字段选项
null = True
Django存储NULL作为空值,缺省Falseblank = True
Django允许该值为空,缺省False
|Field类型| 设置null=True| 设置blank=True|
|- |- | - |- |
|CharField
TextField
SlugField
EmailField
CommaSeparatedIntegerField等|不要设置
django规定储存空字符串来代表空值, 当从数据库中读取NULL或空值时都为空字符串|可以设置
设置后允许接受widget中为空值(即不填写), 储存到数据库时空值变为空字符串|
|FileField
ImageField|不要设置
django实际储存的是路径的字符串, 因此同上| 可以设置
同上|
|BooleanField|不要设置
因为有NullBooleanField代替|不要设置|
|IntegerField
FloatField
DecimalField等|可以设置
如果你希望在数据库中能储存NULL|可以设置
设置后允许接受widget中为空值(即不填写), 设置为True时必须同时设置null=True|
|DateTimeField
DateField
TimeField等|可以设置
如果你希望在数据库中能储存NULL|可以设置
设置后允许接受widget中为空值(即不填写), 设置为True时必须同时设置null=True|
|ForeignKey
ManyToManyField
OneToOneField|可以设置
如果你希望在数据库中能储存NULL| 可以设置
设置后允许接受widget中为空值(即不填写)|
|GenericIPAddressField|可以设置
如果你希望在数据库中能储存NULL|可以设置
设置后允许接受widget中为空值(即不填写)|
|IPAddressField|不推荐设置
用GenericIPAddressField代替|不推荐设置
用GenericIPAddressField代替|
- choice类型
第一列为数据库中实际存储的内容。
class Person(models.Model):
SHIRT_SIZES = (
('S', 'Small'),
('M', 'Medium'),
('L', 'Large'),
)
name = models.CharField(max_length=60)
shirt_size = models.CharField(max_length=1, choices=SHIRT_SIZES)
default
设置缺省值primary_key = True
设置该字段为模型主键unique = True
设置该字段表内唯一
3. 字段名称
first_name = models.CharField(verbose_name="person's first name", max_length=30)
4. 关系
on_delete和on_update设置为:models.CASCADE, models.SET_NULL, models.SET_DEFAULT, models.DO_NOTHING
models.CASCADE: 级联删除或更新(默认值)
models.SET_NULL:设置成NULL
models.SET_DEFAULT: 设置成default值
models.DO_NOTHING: 什么也不做
- Many-to-one关系,即外键
外键可以递归指向自己。可以定义on_delete
class Car(models.Model):
manufacturer = models.ForeignKey(Manufacturer, verbose_name="field name", on_delete=models.CASCADE)
- Many-to-mangy关系
多对多关系可以递归指向自己。
class Pizza(models.Model):
# ...
toppings = models.ManyToManyField(Topping)
用户定义关联表
class Person(models.Model):
name = models.CharField(max_length=128)
def __str__(self): # __unicode__ on Python 2
return self.name
class Group(models.Model):
name = models.CharField(max_length=128)
members = models.ManyToManyField(Person, through='Membership')
def __str__(self): # __unicode__ on Python 2
return self.name
class Membership(models.Model):
person = models.ForeignKey(Person, on_delete=models.CASCADE)
group = models.ForeignKey(Group, on_delete=models.CASCADE)
date_joined = models.DateField()
invite_reason = models.CharField(max_length=64)
- One-to-one关系
可以定义on_delete
class MySpecialUser(models.Model):
user = models.OneToOneField(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
)
supervisor = models.OneToOneField(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
related_name='supervisor_of',
)
模型重载
将业务逻辑保留在模型层面是优良的设计风格。
1. 扩展model字段
class Person(models.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
birth_date = models.DateField()
def baby_boomer_status(self):
"Returns the person's baby-boomer status."
import datetime
if self.birth_date < datetime.date(1945, 8, 1):
return "Pre-boomer"
elif self.birth_date < datetime.date(1965, 1, 1):
return "Baby boomer"
else:
return "Post-boomer"
@property
def full_name(self):
"Returns the person's full name."
return '%s %s' % (self.first_name, self.last_name)
2. 重载已经定义方法
class Blog(models.Model):
name = models.CharField(max_length=100)
tagline = models.TextField()
def save(self, *args, **kwargs):
do_something()
super(Blog, self).save(*args, **kwargs) # Call the "real" save() method.
do_something_else()
模型继承
用户需要考虑是否允许父模型创建表格,还是仅仅保留common信息,全部在子模型中创建表格。
1. 抽象继承
abstract = True
class CommonInfo(models.Model):
name = models.CharField(max_length=100)
age = models.PositiveIntegerField()
class Meta:
abstract = True
class Student(CommonInfo):
home_group = models.CharField(max_length=5)
2. 多表继承
通过自动追加一个OneToOneField
class Place(models.Model):
name = models.CharField(max_length=50)
address = models.CharField(max_length=80)
class Restaurant(Place):
serves_hot_dogs = models.BooleanField(default=False)
serves_pizza = models.BooleanField(default=False)
3. proxy model
重载父模型中某些方法,不创建子表格。
proxy = True
class Person(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
class MyPerson(Person):
class Meta:
proxy = True
def do_something(self):
# ...
pass
view处理
事务处理
1. 缺省在autocommit模式
ATOMIC_REQUESTS = True,每个http req都作为一个事务处理,需要排除非事务处理部分。
- 不做数据修改的操作, 应当排除在transaction之外
- 做数据修改的操作, 则应在transaction内
- 特殊情况下, 可以违反以上两条
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': '',
'USER': '',
'PASSWORD': '',
'HOST': '',
'PORT': '',
'ATOMIC_REQUESTS': True,
}
}
@transaction.non_atomic_requests # 以下http request不被包裹在一个transaction中
def do_something_to_article(request, pk, title):
article = get_object_or_404(Article, pk=pk)
# 以下代码会以django默认的autocommit模式执行
article.datetime = timezone.now()
article.save()
with transaction.atomic()
# 以下代码被包裹在另一个transaction中
article.title = title
article.datetime = timezone.now()
article.save()
return HttpResponse("success!")
# 如果以上transaction失败了, 返回错误状态
return HttpResponse("oops! failed", status_code=400)
2. 修饰view事务处理
@transaction.atomic
def viewfunc(request):
# This code executes inside a transaction.
do_stuff()
关系的定义和使用
class Asset(models.Model):
asset_model = models.ForeignKey(AssetModel, related_name='assets')
asset_groups = models.ManyToManyField(AssetGroup, blank=True, related_name='assets')
...
operator_group = models.OneToOneField(Group, related_name='asset')
从另外端访问所有设备
asset_model_obj.assets.all()
asset_group_obj.assets.all()
group_obj.asset从asset访问另外端
asset_obj.asset_modle
asset_obj.asset_groups
asset_obj.operator_group添加/删除关系
asset_model_obj.assets.add/remove(asset_obj1, asset_obj2,...)
asset_groups_obj.assets.add/remove(sset_obj1, asset_obj2,...)清除关系
asset_model_obj.assets.clear()
asset_groups_obj.assets.clear()
对象操作
1. 对象查询
- 查询
Asset.objects.all()
Asset.objects.filter()
Asset.objects.exclude()
Asset.objects.get()
Asset.objects.filter().values()
< QuerySet [{'id': 1, 'name': 'Beatles Blog', 'tagline': 'All the latest Beatles news.'}] >
Asset.objects.filter().values_list()
[(1, 'first entry'), ...]
Asset.objects.extra()
entries = Entry.objects.select_for_update().filter(author=request.user)
- 计数,分片和排序,count(),[], order_by(), revise()
Asset.objects.filter(sn=assetSn, did=dataitemID).count()
Asset.objects.filter().order_by('blog__name')[:5] //first 5
Asset.objects.filter().order_by('-blog__name', 'headline')[5:10] // 6-10
Asset.objects.filter().order_by('-blog__name', 'headline').revise() //反序排列
- 高级查询
Asset.objects.filter(Q(question__startswith='Who'), Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)))
2. 对象创建
b = Blog(name='Beatles Blog', tagline='All the latest Beatles news.')
b.save()
3. 对象删除
obj_queryset.delete()
or
asset_obj.delete()
4. 运算
Book.objects.aggregate(Avg('price'), Max('price'), Min('price'))
{'price__avg': 34.35, 'price__max': Decimal('81.20'), 'price__min': Decimal('12.99')}
5. 字符串查询
Author.objects.filter(name__unaccent__icontains='Helen')
Author.objects.filter(name__contains='Terry')
Serializer
参考Django REST Serializer
1. StringRelatedField
用unicode方法表示只读关系,
参数:
- many = True
class AlbumSerializer(serializers.ModelSerializer):
tracks = serializers.StringRelatedField(many=True)
class Meta:
model = Album
fields = ('album_name', 'artist', 'tracks')
{
'album_name': 'Things We Lost In The Fire',
'artist': 'Low',
'tracks': [
'1: Sunflower',
'2: Whitetail',
'3: Dinosaur Act',
...
]
}
2. PrimaryKeyRelatedField
用主键表示关系,
参数:
- queryset - The queryset used for model instance lookups when validating the field input. Relationships must either set a queryset explicitly, or set read_only=True.
- many - If applied to a to-many relationship, you should set this argument to True.
- allow_null - If set to True, the field will accept values of None or the empty string for nullable relationships. Defaults to False.
- pk_field - Set to a field to control serialization/deserialization of the primary key's value. For example, pk_field=UUIDField(format='hex') would serialize a UUID primary key into its compact hex representation.
class AlbumSerializer(serializers.ModelSerializer):
tracks = serializers.PrimaryKeyRelatedField(many=True, read_only=True)
class Meta:
model = Album
fields = ('album_name', 'artist', 'tracks')
{
'album_name': 'Undun',
'artist': 'The Roots',
'tracks': [
89,
90,
91,
...
]
}
3. SlugRelatedField
选取关系对象中任意一个字段(唯一标识)表示关系
参数:
- slug_field - The field on the target that should be used to represent it. This should be a field that uniquely identifies any given instance. For example, username. required
- queryset - The queryset used for model instance lookups when validating the field input. Relationships must either set a queryset explicitly, or set read_only=True.
- many - If applied to a to-many relationship, you should set this argument to True.
- allow_null - If set to True, the field will accept values of None or the empty string for nullable relationships. Defaults to False.
class AlbumSerializer(serializers.ModelSerializer):
tracks = serializers.SlugRelatedField(
many=True,
read_only=True,
slug_field='title'
)
class Meta:
model = Album
fields = ('album_name', 'artist', 'tracks')
{
'album_name': 'Dear John',
'artist': 'Loney Dear',
'tracks': [
'Airport Surroundings',
'Everything Turns to You',
'I Was Only Going Out',
...
]
}
4. Nested relationships
嵌套定义
- 只读serializer:
class TrackSerializer(serializers.ModelSerializer):
class Meta:
model = Track
fields = ('order', 'title', 'duration')
class AlbumSerializer(serializers.ModelSerializer):
tracks = TrackSerializer(many=True, read_only=True)
class Meta:
model = Album
fields = ('album_name', 'artist', 'tracks')
{
'album_name': 'The Grey Album',
'artist': 'Danger Mouse',
'tracks': [
{'order': 1, 'title': 'Public Service Announcement', 'duration': 245},
{'order': 2, 'title': 'What More Can I Say', 'duration': 264},
{'order': 3, 'title': 'Encore', 'duration': 159},
...
],
}
- 可写Serializer:
在写子对象时,父对象不一定存在,涉及父对象的创建。创建父对象+创建子对象+创建关系。
class TrackSerializer(serializers.ModelSerializer):
class Meta:
model = Track
fields = ('order', 'title', 'duration')
class AlbumSerializer(serializers.ModelSerializer):
tracks = TrackSerializer(many=True)
class Meta:
model = Album
fields = ('album_name', 'artist', 'tracks')
def create(self, validated_data):
tracks_data = validated_data.pop('tracks')
album = Album.objects.create(**validated_data)
for track_data in tracks_data:
Track.objects.create(album=album, **track_data)
return album
>>> data = {
'album_name': 'The Grey Album',
'artist': 'Danger Mouse',
'tracks': [
{'order': 1, 'title': 'Public Service Announcement', 'duration': 245},
{'order': 2, 'title': 'What More Can I Say', 'duration': 264},
{'order': 3, 'title': 'Encore', 'duration': 159},
],
}
>>> serializer = AlbumSerializer(data=data)
>>> serializer.is_valid()
True
>>> serializer.save()
5. 用户自定义字段
在写子对象时,父对象已存在,不涉及父对象的创建,需要做:创建或更新子对象+创建或更新关系
class ModField(serializers.RelatedField):
def to_representation(self, value):
"""
output to read
"""
return value.name
def to_internal_value(self, value):
"""
input to write, value = org, model name
"""
targetOrg = Org.objects.get(name=value['org'])
return AssetModel.objects.filter(org=targetOrg).get(name=value['mod'])
class DataitemSerializer(serializers.ModelSerializer):
asset_model = ModField(queryset=AssetModel.objects.all())
class Meta:
model = Dataitem
fields = ('asset_model', 'name', 'data_type', 'max', 'min', 'step', 'storage', 'update_interval',
'retention_history', 'retention_period', 'writeable', 'description', 'instance_table')
类view和函数view
Django函数view装饰器
@require_http_methods(["GET", "POST"])
Django REST函数view装饰器,@api_view
@api_view(['GET', 'POST'], exclude_from_schema=True)
def hello_world(request):
if request.method == 'POST':
return Response({"message": "Got some data!", "data": request.data})
return Response({"message": "Hello, world!"})
Django REST APIView是Django class view的子类
参考
Django DOC
Django REST DOC