Django 模型操作

额外包

mysqlclient :mysql需求
pymysql :mysql需求
pillow :图片文件需求
class FileLibrary(models.Model):
    # 文件名
    name = models.CharField(max_length=100)
    

修改模型后的操作 

python manage.py makemigrations 【app名称】,migrations中创建或修改模型对应文件
python manage.py migrate ,将这些改变更新到数据库中。

字段类型

AutoField自增字段,通常不用自己设置
Booleanfield布尔字段,值为True或False
NullBooleanField布尔字段,包含空值:Null、True、False
CharField字符串,必须有max_length表示最大字符个数
TextField大文本字段,一般超过4000个字符时使用

JSONField

以JSON格式存储
URLField存储URL的字符串,默认长度200;verify_exists(True),检查URL可用性
SlugField只能包含字母,数字,下划线和连字符的字符串,通常被用于URLs表示
CommaSeparatedIntegerField以逗号间隔的整数序列,必须有max_length
IntegerField整数[-2147483648,2147483647 ]

PositiveIntegerField

正整数[0 ,2147483647]
PositiveSmallIntegerField正短整数[0 ,32767]
SmallIntegerField小整数[-32768 ,32767]
BigIntegerField64位的整型数值 (-2^63) – (2^63-1)
BinaryField存储原始的2进制数据,功能有限,仅支持字节分配
Decimalfield十进制浮点数 , 参数maxdigits表示总位数, 参数decimalplaces表示小数位数
FloatField浮点数
DateField日期, 参数auto_now表示每次保存对象时,自动设置该字段为当前时间,默认为False; 参数auto_now_add表示当对象第一次被创建时自动设置当前时间,默认为False; 参数auto_now_add和auto_now是相互排斥的,组合将会发生错误
TimeField时间,参数同date
DateTimeField日期时间,参数同date
EmailField带有email合法性检测的一个CharField
IPAddressField点分十进制表示的IP地址,如10.0.0.1
GenericIPAddressFieldip v4和ip v6地址表示,ipv6遵循RFC 4291section 2.2
FileField有一个必须参数upload_to,用于保存文件的本地文件系统
FilePathField

一个CharField,用来选择文件系统下某个目录里面的某些文件,它有三个专有参数,只有path是必须的。path是一个目录的绝对路径,match是一个正则表达式字符串,用来过滤文件名称;recursive为bool,指定是否包含path下的子目录。

imageField继承于FileField,对上传的 内容进⾏行行校验,确保是有效的图⽚片(必须要安装Pillow才可以使用(pip install Pillow)
ForeignKey外键,参数一链接的模型,参数二on_delte,级联删除,一般为

on_delete=models.CASCADE

ManyToManyField

多对多 add()添加 remove()移除

参数

null如果为True,表示允许为空,默认值是False
blank如果为True,则该字段允许为空白,默认值是False
db_column字段的名称,如果未指定,则使用属性的名称
db_index若值为True, 则在表中会为此字段创建索引,默认值是False
default默认
primary_key若为True,则该字段会成为模型的主键字段,默认值是False,一般作为AutoField
unique如果为True, 这个字段在表中必须有唯一值,默认值是False

模型方法 

class HighRatingManager(models.Manager):
    def get_queryset(self):
        return super().get_queryset().filter(rating=1)

# CHOICES选项
class Rating(models.IntegerChoices):
    VERYGOOD = 1, 'Very Good'
    GOOD = 2, 'Good'
    BAD = 3, 'Bad'

class Product(models.Model):
    # 数据表字段
    name = models.CharField('name', max_length=30)
    rating = models.IntegerField(max_length=1, choices=Rating.choices)
 
    # MANAGERS方法
    objects = models.Manager()
    high_rating_products =HighRatingManager()
 
    # META类选项
    class Meta:
        abstract=True            # 指定该模型为抽象模型,不会在数据库里创建数据表
        proxy=True               # 指定该模型为代理模型,即克隆一个与模型A相同的模型B
        verbose_name = 'product' # 为模型设置便于人类阅读的别名
        verbose_name_plural = 'products'  # 为模型设置便于人类阅读的别名
        db_table= xxx            # 自定义数据表名,属性为字符串
        odering=['-pub-date']    # 自定义按哪个字段排序,-代表逆序
        permissions=[]           # 为模型自定义权限
        managed=False            # 默认为True,如果为False,Django不会为这个模型生成数据表,即是否支持数据迁移命令
        indexes=[]               # 为数据表设置索引,对于频繁查询的字段,建议设置索引
        constraints=             # 给数据库中的数据表增加约束。
        
    # __str__方法
    def __str__(self):
        return self.name
 
    # 重写save方法
    def save(self, *args, **kwargs):
        do_something()
        super().save(*args, **kwargs) 
        do_something_else()
 
    # 定义单个对象绝对路径
    def get_absolute_url(self):
        return reverse('product_details', kwargs={'pk': self.id})
 
    # 其它自定义方法
    def do_something(self):

示例

class UserInfo(models.Model):
    # 邮箱
    uname = models.EmailField()
    # 密码经加密后长度会变长
    pwd = models.CharField(max_length=60)


    class Meta:
        ordering = ('id',)

class CartItem(models.Model):
    goodsid = models.PositiveIntegerField()  
    colorid = models.PositiveIntegerField() 
    sizeid = models.PositiveIntegerField() 
    count = models.PositiveIntegerField() 
    isdelete = models.BooleanField( default=False)
    user = models.ForeignKey(UserInfo,on_delete=models.CASCADE)  #外键

增加

_obj = {
    'goodsid':goodsid,
    'colorid':colorid,
    'sizeid':sizeid,
    'count':count,
    'user':user
}
CartItem.objects.create(**_boj)

    批量增加 

a = [1,2,3]
arr = []
for i in a:
    arr.append(User(cid=i))
User.objects.bulk_create(arr)

删除

user=User.object.get(id=1)
user.delete()
users=User.objects.all()
users.delete()

 更新

update只适用于filter查询结果

user.cartitem_set.filter(
    goodsid=goodsid,
    colorid=colorid,
    sizeid=sizeid
).update(count=count,isdelete=False)

单个结果用save 

config.json = "hoge"
config.save()

更新或新增

book.objects.update_or_create(defaults={'name':'安尔达'},id=5)
# defaults中的内容为查询内容,后面的是需要更新的内容。

批量更新

querys = User.objects.all()
arr = []
for i in querys:
	if i.state == 3:
		o = User(id=i.id,type=3,sum_fans=0)
	if i.start == 4:
		o = User(id=i.id,type=4,sum_fans=2)
	else:
		o = User(id=i.id,type=5,sum_fans=5)
    arr.append(o)
User.objects.bulk_update(arr, ['type', 'sum_fans'])

查询

userList = UserInfo.objects.filter(uname=uname,pwd=pwd)
user = userList[0]

cart = user.cartitem_set.filter(goodsid=goodsid,colorid=colorid,sizeid=sizeid)
cart.count()  #查到的数量

# order_by('id') 按id升序 / order_by('-id') 按id降序
user.cartitem_set.order_by('id').filter(isdelete=False).all()

#根据goodsid,sizeid,colorid获取CartItem对象
user.cartitem_set.get(goodsid=goodsid,sizeid=sizeid,colorid=colorid)

    get的参数只能是model中定义的哪些字段,只支持严格匹配
    filter的参数可以是字段也可以是扩展的where查询关键字,如in,like
    get返回值是一个定义的model对象
    filter返回值是一个新的QuerySet对象,然后可以对QuerySet在进行查询返回新的QuerySet对象,支持链式操作,QuerySet一个集合对象,可使用迭代或者遍历,切片等,但是不等于list类型(是一个object对象集合)

    get只有一条记录返回的时候才正常,也就是说明get查询字段必须是主键或者唯一约束的字段。当返回多条记录或者没有找到记录的时候都会抛出异常

    get方法是从数据库的取得一个匹配的结果,返回一个对象,如果记录不存在的话,它会报错,有多条记录也会报错。

    filter有没有匹配的记录都可以

    filter方法是从数据库的取得匹配的结果,返回一个对象列表,如果记录不存在的话,它会返回[]。

    另外,从别的资料里看到filter好像有缓存数据的功能,第一次查询数据库并生成缓存,下次再调用filter方法的话,直接取得缓存的数据,会get方法每次执行都是直接查询数据库的,不知道这个是不是正确,看看就好。

模糊查询

1.查询某个字符串是否在指定的字段中

article1 = models.Article.objects.filter(id__contains=1)  # 区分大小写
article2 = models.Article.objects.filter(id__icontains = 1)  #不区分大小写 

2.指定某个字段的是否在某个集合中

articles = models.Article.objects.filter(id__in=[1,2,3])
for article in articles:
    print(article)

 3.大于、大于等于、小于、小于等于

gt、gte、lt、lte

articles = models.Article.objects.filter(id__gt=2)


# 在 ... 之间,左闭右闭区间,= 号后面为两个元素的列表
articles = models.Article.objects.filter(id__range=[10,20])

 4.某个值开始、以某个值结束

字段以指定字符开头与结尾

articles = Article.objects.filter(title__startwith="hello")
articles = Article.objects.filter(title__endswith="hello")
articles = Article.objects.filter(title__istartswith="hello")  # 不区分大小写
articles = Article.objects.filter(title__iendswith="hello")


import datetime
from django.utils.timezone import make_aware

start_time = make_aware(datetime(year=2018,month=11,day=2,hour=16,minute=0,second=0))
end_time = make_aware(datetime(year=2018,month=11,day=2,hour=17,minute=0,second=0))
articles = models.Article.objects.filter(create_time__range=(start_time,end_time))
print(articles)
print(articles.query)

 5.date

articles = models.Article.objects.filter(create_time__date = datetime(year=2018,month=11,day=2))
print(articles.query)
print(articles)

 然后添加映射,然后我们发现并没有查找出结果出来,但是我们是刚才添加的信息,时间也是设置为刚才的,为什么没有信息呢。
原因是因为MySQL默认是没有储存时区相关的信息,但是在执行sql语句时我们发现对时区进行了装换,所以时不会得到我们想要的结果的。因此我们需要下载一些时区表的文件,然后添加到mysql的配置路径中。

windows中
在http://dev.mysql.com/downloads/timezones.html下载timezone_2018d_posix.zip - POSIX standard。然后将下载下来的所有文件拷贝到C:\ProgramData\MySQL\MySQL Server 5.7\Data\mysql中,如果提示文件名重复,那么选择覆盖即可。

linux或者mac系统
在命令行中执行以下命令:mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -D mysql -u root -p,然后输入密码,从系统中加载时区文件更新到mysql中。

然后对上面的代码不需要进行改动,也能执行成功了

 6.year/month/day:根据年/月/日进行查找

articles = models.Article.objects.filter(create_time__year=2018)
articles = models.Article.objects.filter(pub_date__year__gte=2017)

7.week_day: 根据星期来进行查找

1表示星期天,7表示星期六,2-6代表的是星期一到星期五。比如要查找星期三的所有文章,那么可以通过以下代码来实现:

articles = models.Article.objects.filter(create_time__week_day=4)

8.time: 根据时间进行查找

如果要具体到秒,一般比较难匹配到,因为数据库中秒后面还有小数。可以使用区间的方式来进行查找。区间使用range条件。比如想要获取17时/10分/27-28秒之间的文章,那么可以通过以下代码来实现:

from datetime import datetime,time

start_time = time(hour=17,minute=10,second=27)
end_time = time(hour=17,minute=10,second=28)
articles = models.Article.objects.filter(create_time__time__range=(start_time,end_time))

更多的关于时间的过滤,请参考Django官方文档:QuerySet API reference | Django documentation | Djangohttps://docs.djangoproject.com/en/2.1/ref/models/querysets/#range

 9.isnull:根据值是否为空进行查找

# 查询title为空的
articles = models.Article.objects.filter(create_time__isnull=True)
# 查询title不为空的
articles = models.Article.objects.filter(create_time__isnull=False)

 10.regex:正则表达式

articles = models.Article.objects.filter(title__regex=r"^三国")
articles = models.Article.objects.filter(title__iregex=r"^三国")  # 不区分大小写

 11.查找字段最大值

from django.db.models import Max

max = User_company.objects.aggregate(Max('nid'),Max('id'))
# {'nid__max': 9, 'id__max': 70}

查询集合并

qs1 = Pathway.objects.filter(label__name='x')
qs2 = Pathway.objects.filter(reaction__name='A + B >> C')
qs3 = Pathway.objects.filter(inputer__name='WeizhongTu')
 
# 合并到一起
qs = qs1 | qs2 | qs3

查询方法 

all()查询所有内容
get()查询符合条件的返回模型类的对象符合条件的对象只能为一个,如果符合筛选条件的对象超过了一个或者没有一个都会抛出错误
filter()查询符合条件的数据
exclude()查询不符合条件的数据
order_by()对查询结果进行排序
reverse()对查询结果进行反转
count()

查询数据的数量返回的数据是整数

输入参数,则为统计该列非空数量。

first()返回第一条数据,返回的数据是模型类的对象也可以用索引下标
last()返回最后一条数据返回的数据是模型类的对象不能用索引下标 [-1],ORM 没有逆序索引
exists()判断查询的结果 QuerySet 列表里是否有数据
values()

查询部分字段的数据

返回的是 QuerySet 类型数据,类似于 list,里面不是模型类的对象,而是一个可迭代的字典序列,字典里的键是字段,值是数据。

values_list()

查询部分字段的数据

返回的是 QuerySet 类型数据,类似于 list,里面不是模型类的对象,而是一个个元组,元组里放的是查询字段对应的数据。

distinct()对数据进行去重
select_related()

Goods.object.select_related('User').get(id=0)

同时查询外键,以减少多外键时的查询交数

only()

 Blog.objects.filter(category='django').only('author','title')

仅查询指定列,提高查询速度

defer()仅查询指定字段以外的列,提高查询速度

其他 

模型类转字典

__dict__

>>> Group.objects.get(id=1).__dict__
{'id': 1, 'name': 'GroupA', '_state': <django.db.models.base.ModelState object at 0x7f68612daef0>}
# 有缺陷 多个没用的_state字段,外键字段有问题

model_to_dict

>>> model_to_dict(Group.objects.get(id=1))
{'name': 'GroupA', 'id': 1}
>>> 
>>> model_to_dict(User.objects.get(id=2))
{'leader': 1, 'is_active': True, 'username': 'ops-coffee@163.com', 'fullname': '运维咖啡吧', 'group': [<Group: GroupA>, <Group: GroupC>, <Group: GroupE>], 'id': 2}

这种方法能满足大部分的需求,且输出也较为合理,同时还有两个参数fieldsexclude来配置输出的字段,例如:

>>> from django.forms import model_to_dict
>>> model_to_dict(User.objects.get(id=2), fields=['fullname','is_active'])
{'is_active': True, 'fullname': '运维咖啡吧'}
>>> 
>>> model_to_dict(User.objects.get(id=2), exclude=['group','leader','id'])
{'fullname': '运维咖啡吧', 'is_active': True, 'username': 'ops-coffee@163.com'}

模型类转JSON字符串

from django.core.serializers import serialize

jsondata = serialize('json',data)

模板

 模板中 字典key为变量

from django.template.defaulttags import register

@register.filter
def get_item(dictionary,key):
    return dictionary.get(key)
{% for item in pageObj %}
    <h7>{{ nameDict|get_item:item.cid }}</h7>
{% endfor %}

数据回滚

一、整体回滚

所有的数据库更新操作都会在一个事务中执行,如果事务中任何一个环节出现错误,都会回滚整个事务。

from django.db import transaction, DatabaseError

# open a transaction
@transaction.atomic                #装饰器格式
def func_views(request):
    do_something()    
    a = A()              #实例化数据库模型
    try:
        a.save()
    except DatabaseError:
        pass

此方案整个view都会在事务之中,所有对数据库的操作都是原子性的。

from django.db import transaction, DatabaseError
 
def func_views(request):
    try:
        with transaction.atomic():      #上下文格式,可以在python代码的任何位置使用
            a = A()
            a.save()
            #raise DatabaseError     #测试用,检测是否能捕捉错误
    except DatabaseError:     # 自动回滚,不需要任何操作
            pass

此方案比较灵活,事务可以在代码中的任意地方开启,对于事务开启前的数据库操作是必定会执行的,事务开启后的数据库操作一旦出现错误就会回滚。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值