Django入门到放弃之ORM多表操作

1.多表操作之模型创建

1 图书表:book,作者表:author,作者详情表:authordetail,出版社表:publish,(第三张中间表)
2 作者跟作者详情:是一对一,关联字段写在哪一方都可以
3 图书跟出版社:是一对多,一对多关系一旦确立,关联字段写在多的一方
4 图书和作者:是多对多,多对多的关系需要建立第三张表(可以自动生成)

5 models.py中把关系建立出来
from django.db import models
### django:  1.11.1     2.0.7
# Create your models here.
class Publish(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32)
    addr = models.CharField(max_length=64)
    phone = models.CharField(max_length=64)
    email = models.EmailField()


class Book(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=6, decimal_places=2)
    publish_date = models.DateTimeField(auto_now_add=True)

    # to='Publish'跟Publish表做关联(ForeignKey,一对多)
    # to_field='id'跟哪个字段做关联
    # publish=models.CharField(max_length=32)
    # publish=models.ForeignKey(to='Publish',to_field='id')
    # publish = models.ForeignKey(to='Publish')  # 不写,默认跟主键做关联
    publish = models.ForeignKey(to=Publish)  # 不写,默认跟主键做关联

    # 自动创建出第三张表(这句话会自动创建第三章表)
    # authors在数据库中不存在该字段,没有to_field
    # 默认情况:第三张表有id字段,当前Book表的id和Author表的id字段
    authors=models.ManyToManyField(to='Author') 
    
    #db_constraint=False 如果使用两个表之间存在关联,首先db_constraint=False 把关联切断,但保留链表查询的功能,其次要设置null=True, blank=True,注意on_delete=models.SET_NULL 一定要置空,这样删了不会影响其他关联的表


class Author(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32)
    age = models.SmallIntegerField()
    # 一对一的本质是  ForeignKey+unique
    author_detail=models.OneToOneField(to='AuthorDetail',to_field='id')
    # author_detail=models.ForeignKey(to='AuthorDetail',to_field='id',unique=True)


class AuthorDetail(models.Model):
    id = models.AutoField(primary_key=True)
    sex = models.SmallIntegerField()
    addr = models.CharField(max_length=64)
    phone = models.BigIntegerField()
    
 
6 同步到mysql数据库
	-配置文件
    -pymysql.install_as_mysqldb()
		-公司可以用过的mysqlclient
    -两条命令
    
7 2.x版本的django
	-外键字段必须加  参数:on_delete
    -1.x版本不需要,默认就是级联删除
    -假设,
    	删除出版社,该出版社出版的所有图书也都删除,on_delete=models.CASCADE
        删除出版社,该出版社出版的图书不删除,设置为空on_delete=models.SET_NULL,null=True
        删除出版社,该出版社出版的图书不删除,设置为默认on_delete=models.SET_DEFAULT,default=0

2.增

一对一增加

 #1.1 一对一增加
    # new_author_detail = models.AuthorDetail.objects.create(
    #     birthday='1979-08-08',
    #     telephone='138383838',
    #     addr='黑龙江哈尔滨'
    # )
    # obj = models.AuthorDetail.objects.filter(addr='山西临汾').first()

    #方式1
    # models.Author.objects.create(
    #     name='王涛',
    #     age='40',
    #     authorDetail=new_author_detail,
    # )
    # 方式2  常用
    # models.Author.objects.create(
    #     name='王涛',
    #     age='40',
    #     authorDetail_id=obj.id,
    # )

一对多

    #方式1
    # obj = models.Publish.objects.get(id=2)
    # models.Book.objects.create(
    #     title = '李帅的床头故事',
    #     publishDate='2019-07-22',
    #     price=3,
    #     # publishs=models.Publish.objects.get(id=1),
    #     publishs=obj,
    #
    # )
    # 方式2 常用
    # models.Book.objects.create(
    #     title='李帅的床头故事2',
    #     publishDate='2019-07-21',
    #     price=3.5,
    #     # publishs=models.Publish.objects.get(id=1),
    #     publishs_id=obj.id
    #
    # )


# 总结:
	1 email可以不传email,本质就是varchar(admin中会判断)
    2 新增图书:
    	-publish=publish
        -publish_id=publish.id
    3 写在表模型中的publish字段,到数据库中会变成publish_id(ForeignKey)
    4 查到book对象以后
    	-book.publish     对象
    	-book.publish_id  id号,数字

3.多对多添加记录,修改,删除

1 自动创建的表,表模型就拿不到,book.authors代指表模型


    # 多对多,作者和书
    # 给西游记这本书新增两个作者lqz和egon
    # 去到西游记这本书
    # book=models.Book.objects.get(name='西游记')
    # 代指中间表book.authors
    # lqz=models.Author.objects.get(id=2)
    # egon=models.Author.objects.get(id=3)
    # book.authors.add(2,3) # 新增作者,通过id新增
    # # book.authors.add(lqz,egon) # 新增作者,通过对象新增
    # book.authors.add(2,egon) # 新增作者,通过对象新增

    # 西游记删除一个作者
    # book = models.Book.objects.get(name='西游记')
    # book.authors.remove(2)
    # egon = models.Author.objects.get(id=3)
    # book.authors.remove(egon)

    # clear 清空所有作者
    book = models.Book.objects.get(name='西游记')
    # book.authors.add(2, 3)
    # book.authors.clear()

    # set 先清空,再add,前提是不存在的作者
    book.authors.set([4, ])
    
    # add ,remove,set clear

4.

一对一

  # 一对一  表一外键关联到表二,表一删除,不影响表2,表2删除会影响表1
  # models.AuthorDetail.objects.get(id=2).delete()
  # models.Author.objects.get(id=3).delete()

一对多

    # 一对多
    # models.Publish.objects.get(id=1).delete()
    # models.Book.objects.get(nid=1).delete()

多对多

    # book_obj = models.Book.objects.get(nid=6)
    # book_obj.authors.remove(6)
    # book_obj.authors.remove(*[5,6])
    # book_obj.authors.clear()
    # book_obj.authors.add(*[1,])
    # book_obj.authors.set('1')
    # book_obj.authors.set(['5','6']) #删除然后更新

多对对多其他api

add ,remove,set clear

5.改

一对一

    # 一对一
    # models.Author.objects.filter(id=5).update(
    #     name='崔老师',
    #     age=16,
    #     # authorDetail=models.AuthorDetail.objects.get(id=5),
    #     authorDetail_id=4,
    # )

一对多

    # models.Book.objects.filter(pk=4).update(
    #     title='B哥的往事2',
    #     # publishs=models.Publish.objects.get(id=3),
    #     publishs_id=3,
    # )
    
    models.Publish.objects.filter(pk=2).update(
    id=4, # 没有级联更新,报错!!
    )

6.查

基于对象的跨表查询(正向反向)

关系属性(字段)写在哪个类(表)里面,从当前类(表)的数据去查询它关联类(表)的数据叫做正向查询,反之叫做反向查询

  '''        正向查询:Authorobj.authorDetail,对象.关联属性名称
             Author----------------------------------->AuthorDetail
              <-----------------------------------
              反向查询:AuthorDetailobj.author  ,对象.小写类名
    '''

# 跨表查询有两种方式
	-基于对象的跨表查询:子查询
    -基于双下划线的跨表查询:关联查询,连表查询
    
  
# 基于对象的跨表查询
	-查询主键为1的书籍的出版社所在的城市
    
    # 基于对象的跨表查询(子查询)
    # 一对多
    # 查询主键为1的书籍的出版社所在的城市
    # book=models.Book.objects.get(id=1) # 第一次查询
    # # book=models.Book.objects.filter(id=1).first()
    # publish=book.publish  # 内部又执行了一次查询,根据publish_id查询publish
    # print(publish.addr)

    # 北京出版社出版的所有书籍
    # publish=models.Publish.objects.get(name='北京出版社')  # 第一次查询了出版社
    # books=publish.book_set.all()    # 表名小写_set     # 第二次,根据出版社id,查询所有书
    # print(books)

    # 正向查询:book表内有publish字段 直接对象.字段名
    # 反向查询:publish表内没有book字段,出版社对象.Book小写_set.all()


    ### 一对一
    # 查询所有住址在山东的作者的姓名
    # 反向查询:author_detail没有author字段,author_detail.表明小写
    # author_detail=models.AuthorDetail.objects.filter(addr__contains='山东').first()
    # # 反向
    # print(author_detail.author.name)

    # 查询egon作者的地址
    # 正向
    # author=models.Author.objects.get(name='egon')
    # print(author.author_detail.addr)


    # 多对多关系查询
    #金x梅所有作者的名字以及手机号
    # book=models.Book.objects.get(name='金x梅')
    # # 正向
    # authors=book.authors.all()
    # for author in authors:
    #     print(author.name)
    #     print(author.author_detail.phone)

    # 反向 查询egon出过的所有书籍的名字
    # egon=models.Author.objects.get(name='egon')
    # books=egon.book_set.all()
    # for book in books:
    #     print(book.name)

基于双下划线的跨表查询

# 连表查询
   # 基于对象的跨表查询,先查对象,通过对象再去查另一个对象(正向:字段名,反向:表名小写/表名小写_set.all())


    # 地址为山东的作者写的所有书
    # author_detail=models.AuthorDetail.objects.get(addr='山东')
    # author=author_detail.author
    # books=author.book_set.all()
    # print(books[0].name)

    # (作业)地址为山东的作者写的所有书的出版社名字


    ### 基于双下划线的跨表查之  一对多
    # 正向:字段名
    # 反向:表名小写
    # filter,values,values_list(写 __ 跨表)
    # 练习:  查询北京出版社出版过的所有书籍的名字与价格(一对多)
    # SELECT `app01_book`.`name`, `app01_book`.`price` FROM `app01_publish` LEFT OUTER JOIN `app01_book` ON (`app01_publish`.`id` = `app01_book`.`publish_id`) WHERE `app01_publish`.`name` = '北京出版社' ;
    # res=models.Publish.objects.filter(name='北京出版社').values('book__name','book__price')
    # print(res)
    #SELECT `app01_book`.`name`, `app01_book`.`price` FROM `app01_book` INNER JOIN `app01_publish` ON (`app01_book`.`publish_id` = `app01_publish`.`id`) WHERE `app01_publish`.`name` = '北京出版社';

    # res=models.Book.objects.filter(publish__name='北京出版社').values('name','price')
    # print(res)


    ## 多对多
    # 练习: 查询egon出过的所有书籍的名字,价格(多对多)
    #反向
    # res=models.Author.objects.filter(name='egon').values('book__name','book__price')
    # print(res)

    # 正向
    # res=models.Book.objects.filter(authors__name='egon').values('name','price')
    # print(res)

    #查询egon的手机号
    # res=models.Author.objects.filter(name='egon').values('author_detail__phone')
    # print(res)
    # res=models.AuthorDetail.objects.filter(author__name='egon').values('phone')
    # print(res)

进阶连续跨表查询

    # 连续跨表
    #查询北京出版社出版过的所有书籍的名字以及作者的姓名
    # res=models.Publish.objects.filter(name='北京出版社').values('book__name','book__authors__name')
    # print(res)

    # res=models.Book.objects.filter(publish__name='北京出版社').values('name','authors__name')
    # print(res)

    # res=models.Author.objects.filter(book__publish__name='北京出版社').values('book__name','name')
    # print(res)

    # 手机号以189开头的作者出版过的所有  书籍名称  以及   出版社名称
    # res=models.AuthorDetail.objects.filter(phone__startswith='189').values('author__book__name','author__book__publish__name')
    # print(res)

    # SELECT `app01_book`.`name`, `app01_publish`.`name` FROM `app01_author` INNER JOIN `app01_authordetail` ON (`app01_author`.`author_detail_id` = `app01_authordetail`.`id`) LEFT OUTER JOIN `app01_book_authors` ON (`app01_author`.`id` = `app01_book_authors`.`author_id`) LEFT OUTER JOIN `app01_book` ON (`app01_book_authors`.`book_id` = `app01_book`.`id`) LEFT OUTER JOIN `app01_publish` ON (`app01_book`.`publish_id` = `app01_publish`.`id`) WHERE `app01_authordetail`.`phone` LIKE  '189%' ;
    res=models.Author.objects.filter(author_detail__phone__startswith='189').values('book__name','book__publish__name')
    print(res)

聚合查询

###########1 聚合查询(聚合函数:最大,最小,和,平均,总个数)
from django.db.models import Avg,Max,Min,Count,Sum
#1 计算所有图书的平均价格
# aggregate结束,已经不是queryset对象了
# book=models.Book.objects.all().aggregate(Avg('price'))
# 起别名
# book=models.Book.objects.all().aggregate(avg=Avg('price'))
#2 计算总图书数
# book = models.Book.objects.all().aggregate(count=Count('id'))
# 3 计算最低价格的图书
# book = models.Book.objects.all().aggregate(min=Min('price'))
# 4 计算最大价格图书
# book = models.Book.objects.all().aggregate(max=Max('price'))
# print(book)

分组查询

#  annotate() 内写聚合函数
#  values在前表示group by的字段
#  values在后表示取某几个字段
#  filter在前表示where
#  filter在后表示having



 ####2  分组查询
    '''
       查询每一个部门名称以及对应的员工数
       book:
       id  name   price      publish
        1   金品   11.2        1
        2   西游   14.2        2
        3   东游   16.2        2
        4   北邮   19.2        3
        
    '''
    # 示例一:查询每一个出版社id,以及出书平均价格
    # select publish_id,avg(price) from app01_book group by publish_id;
    # annotate

    # from django.db.models import Avg, Count, Max, Min
    # ret=models.Book.objects.values('publish_id').annotate(avg=Avg('price')).values('publish_id','avg')
    # print(ret)

    # 查询出版社id大于1的出版社id,以及出书平均价格
    #select publish_id,avg(price) from app01_book where publish_id>1 group by publish_id;

    # ret=models.Book.objects.values('publish_id').filter(publish_id__gt=1).annotate(avg=Avg('price')).values('publish_id','avg')
    # print(ret)

    # 查询出版社id大于1的出版社id,以及出书平均价格大于30的
    # select publish_id,avg(price)as aaa from app01_book where publish_id>1 group by publish_id HAVING aaa>30;
    # ret = models.Book.objects.values('publish_id').filter(publish_id__gt=1).annotate(avg=Avg('price')).filter(avg__gt=30).values(
    #     'publish_id', 'avg')
    # print(ret)


    ## 查询每一个出版社出版的书籍个数
    # pk 代指主键

    # ret=models.Book.objects.get(pk=1)
    # print(ret.name)
    # ret=models.Publish.objects.values('pk').annotate(count=Count('book__id')).values('name','count')
    # print(ret)
    # 如果没有指定group by的字段,默认就用基表(Publish)主键字段作为group by的字段
    # ret=models.Publish.objects.annotate(count=Count('book__id')).values('name','count')
    # print(ret)

    # 另一种方式实现
    # ret=models.Book.objects.values('publish').annotate(count=Count('id')).values('publish__name','count')
    # print(ret)


    #查询每个作者的名字,以及出版过书籍的最高价格(建议使用分组的表作为基表)
    # 如果不用分组的表作为基表,数据不完整可能会出现问题
    # ret=models.Author.objects.values('pk').annotate(max=Max('book__price')).values('name','max')

    # ret = models.Author.objects.annotate(max=Max('book__price')).values('name', 'max')

    # ret= models.Book.objects.values('authors__id').annotate(max=Max('price')).values('authors__name','max')
    # print(ret)

    #查询每一个书籍的名称,以及对应的作者个数

    # ret=models.Book.objects.values('pk').annotate(count=Count('authors__id')).values('name','count')
    # ret=models.Book.objects.annotate(count=Count('authors__id')).values('name','count')

    # ret=models.Author.objects.values('book__id').annotate(count=Count('id')).values('book__name','count')
    #
    # print(ret)

    #统计不止一个作者的图书
    # ret=models.Book.objects.values('pk').annotate(count=Count('authors__id')).filter(count__gt=1).values('name','count')
    # ret = models.Author.objects.values('book__id').annotate(count=Count('id')).filter(count__gt=1).values('book__name', 'count')
    # print(ret)

    # 统计价格数大于10元,作者的图书
    ret = models.Book.objects.values('pk').filter(price__gt=10).annotate(count=Count('authors__id')).values('name',
                                                                                                           'count')
    print(ret)

    #统计价格数大于10元,作者个数大于1的图书
    ret = models.Book.objects.values('pk').filter(price__gt=10).annotate(count=Count('authors__id')).filter(count__gt=1).values('name',                                                                                                    'count')
    print(ret)

F和Q查询

 # F查询:取出数据库的某个字段的值

    # 把read_num都加1
    from django.db.models import F
    ret=models.Book.objects.all().update(read_num=F('read_num')+1)
    print(ret)


    #查询评论数大于阅读数的书籍
    ret=models.Book.objects.all().filter(commit_num__gt=F('read_num'))
    for i in ret:
        print(i.name)

    ## 查询评论数大于阅读数2倍的书籍
    ret=models.Book.objects.filter(commit_num__gt=F('read_num')*2)
    print(ret)
    
    
# Q查询:制造  与或非的条件
	Q()   &  |  ~  与或非

    # Q查询:制造  与或非的条件
    # 查询名字叫egon或者价格大于100的书
    from django.db.models import Q
    # ret=models.Book.objects.filter(Q(name='egon') | Q(price__gt=100))
    # 查询名字叫egon并且价格大于100的书
    # ret=models.Book.objects.filter(Q(name='egon') & Q(price__gt=100))
    # ret=models.Book.objects.filter(name='egon',price__gt=100)


    # 查询名字不为egon的书
    # ret = models.Book.objects.filter(~Q(name='egon'))
    # print(ret)

    # Q可以嵌套
    ret = models.Book.objects.filter((Q(name='egon') & Q(price__lt=100)) | Q(id__lt=3))
    print(ret)

7.ORM使用原生sql

    # 原生sql(有些sql用orm写不出来)
    # 两种方案
    # 第一种:用的比较少

    # from django.db import connection
    #
    # cursor = connection.cursor()
    #
    # cursor.execute("""SELECT * from app01_book where id = %s""", [1])
    #
    # # row = cursor.fetchone()
    # row = cursor.fetchall()
    # print(row)

    # 第二种,用的多
    # books=models.Book.objects.raw('select * from app01_book where id >3')
    # print(books)#RawQuerySet对象
    # for book in books:
    #     print(book.name)

    # books=models.Book.objects.raw('select * from app01_publish')
    # for book in books:
    #     print(book.__dict__)
        # print(book.name)
        # print(book.addr)
        # print(book.email)
        # print(book.price)

    # authors = models.Author.objects.raw('SELECT app01_author.id,app01_author. NAME,app01_authordetail.sex FROM app01_author JOIN app01_authordetail ON app01_author.author_detail_id = app01_authordetail.id WHERE app01_authordetail.sex = 1')
    # 
    # for author in authors:
    #     print(author.name)
    #     print(author.__dict__)

8.defer和only

    # defer和only(查询优化相关)
    # only保持是book对象,但是只能使用only指定的字段
    # books = models.Book.objects.all().only('name')
    # print(books[0].name)
    # print(books[0].price)  # 能出来,

    # books = models.Book.objects.all().only('name')
    #
    # print(books[0].__dict__)
    books = models.Book.objects.all().defer('name','price')
    print(books[0].__dict__)

9.事务(请求,装饰器,局部)

# 事物:ACID,事物的隔离级别(搜),锁, 行级锁,表级锁

    # djanog orm中使用事物:原子性操作,要么都成功,要么都失败

    # 新增一个作者详情,新增一个作者

    # 事物的三个粒度
    # 1 局部使用
    from django.db import transaction
    with transaction.atomic(): # 都在事物中,要么都成功,要么都失败
        author_detail=models.AuthorDetail.objects.create(addr='xxx',phone='123',sex=1)
        # raise Exception('抛了异常')
        author=models.Author.objects.create(name='llqz',age=19,author_detail=author_detail)
    # 2 视图函数装饰器,这一个视图函数都在一个事物中
    # @transaction.atomic
    # def index(request):
    #     return HttpResponse('ok')


    # 3 整个http请求,在事物中,在setting.py中配置
    '''
    DATABASES = {
        'default': {
            ...
            'PORT': 3306,
            'ATOMIC_REQUEST': True,
       
        }
    }

    'ATOMIC_REQUEST': True,
设置为True统一个http请求对应的所有sql都放在一个事务中执行(要么所有都成功,要么所有都失败)。
    
    '''

10.多表创建的三种方式

ManyToManyField

class Book(models.Model):
    title = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=8,decimal_places=2)
    authors = models.ManyToManyField(to='Author')  #与Author表自动创建多对多关联关系

class Author(models.Model):
    name = models.CharField(max_length=32)


优点:可以使用ORM提供的快捷方法: add() clear() set()  remove() all()  
缺点:第三张表自动创建,无法扩展第三张表的字段

手动创建第三张表

class Book(models.Model):
    title = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=8,decimal_places=2)

class Author(models.Model):
    name = models.CharField(max_length=32)
                
                
class Book2Author(models.Model):
    book = models.ForeignKey(to='Book')
    author = models.ForeignKey(to='Author')
    create_time = models.DateField(auto_now_add=True)

优点:可以自己扩展第三章关系表的字段
缺点:不能使用ORM提供的快捷方法(查询麻烦,需要跨三张表)

中介模式(在ManyToManyField中通过through和through_fields指定表名和字段)

class Book(models.Model):
    title = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=8,decimal_places=2)
     # 当前在哪个表中,元组中的第一个参数就是 表名_id或表对象
    authors = models.ManyToManyField(to='Author',through='Book2Author',through_fields=('book','author'))
    # through 告诉django orm 书籍表和作者表的多对多关系是通过Book2Author来记录的
    # through_fields 告诉django orm记录关系时用过Book2Author表中的book字段和author字段来记录的
    # through_fields 中的第一个字段必须为当前表的字段,参考Author表中ManyToManyField的写法,两个表只需要写一个
    """
    多对多字段的
    add
    set
    remove
    clear不支持
    """
                             
class Author(models.Model):
    name = models.CharField(max_length=32)
    # books = models.ManyToManyField(to='Book', through='Book2Author', through_fields=('author', 'book'))

#手动创建的第三张表
class Book2Author(models.Model):
    book = models.ForeignKey(to='Book')
    author = models.ForeignKey(to='Author')
    create_time = models.DateField(auto_now_add=True)
    
 # setting 中 指定扩写Book表
 AUTH_USER_MODEL = 'blog.Book'    

优点:   
  可以使用ORM提供的查询快捷方法,clear() all() 可以使用也可以使用
  不用自己创建第三张表了,也可以任意扩展字段
缺点:多对多字段的add() remove() set() 无法使用

11.ORM语句和SQL语句的优化

设置数据库持久连接
合理创建索引
    提示:索引会占用磁盘空间,创建不必要的索引只会形成浪费。主键、外键、唯一键已经建立索引
    1.频繁出现在where条件子句的字段 get()  filter()
    2.经常被用来分组(group by)或排序(order by)的字段
    3.用于联接的列(主健/外健)上建立索引
    4.在经常存取的多个列上建立复合索引,但要注意复合索引的建立顺序要按照使用的频度来确定
减少SQL语句执行的次数(select_related  prefetch_related)
仅获取需要的字段
使用批量创建、更新、删除,不随意对结果排序

  

posted @ 2022-08-27 22:53  百衲本  阅读(106)  评论(0编辑  收藏  举报
cnblogs_post_body { color: black; font: 0.875em/1.5em "微软雅黑" , "PTSans" , "Arial" ,sans-serif; font-size: 15px; } cnblogs_post_body h1 { text-align:center; background: #333366; border-radius: 6px 6px 6px 6px; box-shadow: 0 0 0 1px #5F5A4B, 1px 1px 6px 1px rgba(10, 10, 0, 0.5); color: #FFFFFF; font-family: "微软雅黑" , "宋体" , "黑体" ,Arial; font-size: 23px; font-weight: bold; height: 25px; line-height: 25px; margin: 18px 0 !important; padding: 8px 0 5px 5px; text-shadow: 2px 2px 3px #222222; } cnblogs_post_body h2 { text-align:center; background: #006699; border-radius: 6px 6px 6px 6px; box-shadow: 0 0 0 1px #5F5A4B, 1px 1px 6px 1px rgba(10, 10, 0, 0.5); color: #FFFFFF; font-family: "微软雅黑" , "宋体" , "黑体" ,Arial; font-size: 20px; font-weight: bold; height: 25px; line-height: 25px; margin: 18px 0 !important; padding: 8px 0 5px 5px; text-shadow: 2px 2px 3px #222222; } cnblogs_post_body h3 { background: #2B6695; border-radius: 6px 6px 6px 6px; box-shadow: 0 0 0 1px #5F5A4B, 1px 1px 6px 1px rgba(10, 10, 0, 0.5); color: #FFFFFF; font-family: "微软雅黑" , "宋体" , "黑体" ,Arial; font-size: 18px; font-weight: bold; height: 25px; line-height: 25px; margin: 18px 0 !important; padding: 8px 0 5px 5px; text-shadow: 2px 2px 3px #222222; } 回到顶部 博客侧边栏 回到顶部 页首代码 回到顶部 页脚代码