Django面试题

目录

1 列举Http请求中常见的请求方式

2 谈谈你对HTTP协议的认识

3 简述MVC模式和MVT模式

4 简述Django请求生命周期

5 简述什么是FBV和CBV

6 谈一谈你对ORM的理解

7 rest_framework 认证组件的流程

8 什么是中间件并简述其作用

9 django 中间件生命周期

10 django中怎么写原生SQL

11 如何使用django orm批量创建数据

12 命令makemigrations和migrate的差别

13 视图函数中,接收的请求对象常用方法和属性有哪些

14 常用视图响应的方式是什么?

15 HTTP响应常见状态码分类

16 路由匹配原则是什么?

17 缓存系统类型有哪些

18 解决跨域的常用方式是什么?

19 信号的作用是什么?

20 Django的Model的继承有几种形式,分别是什么

21 Django中查询queryset时什么情况下用Q

22 Django中想验证表单提交是否格式正确需要用到Form中的哪个函数

23 orm如何取消级联

24 Django中如何读取和保存session,整个session的运行机制是什么

25 简述Django对http请求的执行流程

25 Django中当用户登录到A服务器进入登陆状态,下次被nginx代理到B服务器会出现什么影响

26 跨域请求Django是如何处理的

27 查询集的两大特性?什么是惰性执行

28 查询集返回的列表过滤器有哪些

29 django路由系统中include是干嘛用的?

30 urlpatterns中的name与namespace有什么作用?你是如何使用的?

31 如何根据urlpatterns中的name反向生成url,这样反向生成url的方式有几种?

32 如何给一个字段设置一个主键?

33 如何设置一个带有枚举值的字典?

34 DateTimeField类型中的auto_now与auto_now_add有什么区别

35 selected_related与prefetch_related有什么区别?

36 class Meta中的元信息字段有哪些

37 django的M2M关系,如何手动生成第三张表?

38 在Django中,服务端给客户端响应信息有几种方式?分别是什么?

39 web框架的本质是什么?

40 创建Django工程、Django app、以及运行的命令

41 django中csrf的实现机制

42 Django App的目录结构

43 什么是Cookie、如何获取、设置Cookie

44 什么是session,与cookie的对比、设置、获取、清空session

45 什么是CSRF,及防范方式

46 get请求和post请求的区别

47 如何使用django加密

48 解释blank和null

49 QueryDict和dict区别

50 谈谈你对restful规范的认识?

51 Django 本身提供了 runserver,为什么不能用来部署?  

52 Tornado 的核是什么? 

53  Django重定向你是如何实现的?用的什么状态码?  

54 Django中如何加载初始化数据  

55 简述Django下的(内建)缓存机制 


1 列举Http请求中常见的请求方式

HTTP请求的方法:

HTTP/1.1协议中共定义了八种方法(有时也叫“动作”),来表明Request-URL指定的资源不同的操作方式

注意:

  1. 方法名称是区分大小写的,当某个请求所针对的资源不支持对应的请求方法的时候,服务器应当返回状态码405(Mothod Not Allowed);当服务器不认识或者不支持对应的请求方法时,应返回状态码501(Not Implemented)。

  2. HTTP服务器至少应该实现GET和HEAD/POST方法,其他方法都是可选的,此外除上述方法,特定的HTTP服务器支持扩展自定义的方法。

GET

向特定的路径资源发出请求

注意:GET方法不应当被用于产生“副作用”的操作中,例如在WebApplication中,其中一个原因是GET可能会被网络蜘蛛等随意访问。Loadrunner中对应get请求函数:web_link和web_url

POST

向指定路径资源提交数据进行处理请求(一般用于提交表单或者上传文件)

数据被包含在请求体中,POST请求可能会导致新的资源的建立和/或已有资源的修改。Loadrunner中对应POST请求函数:web_submit_data,web_submit_form

OPTIONS

返回服务器针对特定资源所支持的HTTP请求方法

允许客户端查看服务器的性能,也可以利用向web服务器发送‘*’的请求来测试服务器的功能性

HEAD

向服务器索与GET请求相一致的响应,只不过响应体将不会被返回

这一方法可以再不必传输整个响应内容的情况下,就可以获取包含在响应小消息头中的元信息。

PUT

从客户端向服务器传送的数据取代指定的文档的内容

DELETE

请求服务器删除指定的页面

TRACE

回回显服务器收到的请求,主要用于测试或诊断

CONNECT

HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务


2 谈谈你对HTTP协议的认识

HTTP是一个属于应用层面向对象的协议,HTTP协议工作于客户端-服务端架构之上。

浏览器作为HTTP客户端通过URL向HTTP服务端即WEB服务器发送所有请求。Web服务器根据接收到的请求后,向客户端发送响应信息。

  • 基于TCP/IP

双方建立通信的顺序,以及Web页面显示需要处理的步骤,等等。像这样把与互联网相关联的协议集合起来总称为TCP/IP。而http协议是基于TCP/IP协议之上的应用层协议。

  • 基于请求-响应模式

HTTP协议规定,请求从客户端发出,最后服务器端响应该请求并返回

  • 无状态保存

HTTP是一种不保存状态,即无状态(stateless)协议。HTTP协议自身不对请求和响应之间的通信状态进行保存。也就是说在HTTP这个级别,协议对于发送过的请求或响应都不做持久化处理。

使用HTTP协议,每当有新的请求发送时,就会有对应的新响应产生。协议本身并不保留之前一切的请求或响应报文的信息。这是为了更快地处理大量事务,确保协议的可伸缩性,而特意把HTTP协议设计成如此简单的。可是,随着Web的不断发展,因无状态而导致业务处理变得棘手的情况增多了。比如,用户登录到一家购物网站,即使他跳转到该站的其他页面后,也需要能继续保持登录状态。针对这个实例,网站为了能够掌握是谁送出的请求,需要保存用户的状态。HTTP/1.1虽然是无状态协议,但为了实现期望的保持状态功能,于是引入了Cookie技术。有了Cookie再用HTTP协议通信,就可以管理状态了。


3 简述MVC模式和MVT模式

所谓MVC就是把Web应用分为模型(M),控制器(C)和视图(V)三层,他们之间以一种插件式的、松耦合的方式连接在一起,模型负责业务对象与数据库的映射(ORM),视图负责与用户的交互(页面),控制器接受用户的输入调用模型和视图完成用户的请求

Django面试题_第1张图片

Django的MTV模式本质上和MVC是一样的,也是为了各组件间保持松耦合关系,只是定义上有些许不同,Django的MTV分别是值:

  1. M 代表模型(Model):负责业务对象和数据库的关系映射(ORM)。
  2. T 代表模板(Template):负责如何把页面展示给用户(html)。
  3. V 代表视图(View):负责业务逻辑,并在适当时候调用Model和Template。
  4. 除了以上三层之外,还需要一个URL分发器,它的作用是将一个个URL的页面请求分发给不同的View处理,View再调用相应的Model和Template,MTV的响应模式如下所示:

Django面试题_第2张图片

一般是用户通过浏览器向我们的服务器发起一个请求(request),这个请求回去访问视图函数,(如果不涉及到数据调用,那么这个时候视图函数返回一个模板也就是一个网页给用户),视图函数调用模型,模型去数据库查找数据,然后逐级返回,视图函数把返回的数据填充到模板中空格中,最后返回网页给用户。


4 简述Django请求生命周期

一般是用户通过浏览器向我们的服务器发起一个请求(request),这个请求回去访问视图函数,(如果不涉及到数据调用,那么这个时候视图函数返回一个模板也就是一个网页给用户),视图函数调用模型,模型去数据库查找数据,然后逐级返回,视图函数把返回的数据填充到模板中空格中,最后返回网页给用户。

  1. wsgi,请求封装后交给web框架(Flask、Django)

  2. 请求中间件,对请求进行校验或在请求对象中添加其他相关数据,例如:csrf、request.session -

  3. 路由匹配,根据浏览器发送的不同url去匹配不同的视图函数

  4. 视图函数,在视图函数中进行业务逻辑的处理,可能涉及到:orm、templates => 渲染 - 

  5. 响应中间件,对响应的数据进行处理。

  6. wsgi,将响应的内容发送给浏览器。

Django面试题_第3张图片


5 简述什么是FBV和CBV

FBV(function base views)就是在视图函面使用函数处理请求

CBV(class base views)就是在视图里面使用类处理请求


6 谈一谈你对ORM的理解

ORM是“对象-关系-映射”的简称。

MVC或者MVC框架中包括一个重要的部分,就是ORM,它实现了数据模型与数据库的解耦,即数据模型的设计不需要依赖于特定的数据库,通过简单的配置就可以轻松更换数据库,这极大的减轻了开发人员的工作量,不需要面对因数据库变更而导致的无效劳动


7 rest_framework 认证组件的流程

rest_framework框架是基于CBV基础开发的(VPIView(View)),所以基本流程与CBV流程相似

当我们的请求发来后,会走as_views,执行view里面的方法,最开始都要执行dispatch方法


8 什么是中间件并简述其作用

中间件是一个用来处理Django的请求和响应的框架级别的钩子。它是一个轻量、低级别的插件系统,用于在全局范围内改变Django的输入和输出。每个中间件组件都负责做一些特定的功能。

中间件是介于request与response处理之间的一道处理过程,相对比较轻量级,并且在全局上改变django的输入与输出。


9 django 中间件生命周期

Django面试题_第4张图片

请求过来,中间件拦截一部分请求;比如验证session,没有登录的请求一些页面,跳转至登录页;(图片为中间件的请求过程.)再到urls,分发请求到views视图,通过CBV(dispatch反射)和FBV的get请求讲template页面渲染返回给用户;渲染之前可以从数据库拿出数据,放到render的参数里面传递过去,locals()表示把所有参数传递还可以实例化其他form类,并渲染给前端


10 django中怎么写原生SQL

列举django orm中三种能写sql语句的方法

  • 使用extra:

查询人民邮电出版社出版并且价格大于50元的书籍

Book.objects.filter(publisher__name='人民邮电出版社').extra(where=['price>50'])
  • 使用raw

books=Book.objects.raw('select * from hello_book')
for book in books:
    print book
  • 自定义sql

from django.db import connection

cursor = connection.cursor()
cursor.execute("insert into hello_author(name) VALUES ('郭敬明')")
cursor.execute("update hello_author set name='韩寒' WHERE name='郭敬明'")
cursor.execute("delete from hello_author where name='韩寒'")
cursor.execute("select * from hello_author")
cursor.fetchone()
cursor.fetchall() 

11 如何使用django orm批量创建数据

使用django.db.models.query.QuerySet.bulk_create()批量创建对象,减少SQL查询次数。改进如下:

querysetlist=[]
for i in resultlist:
    querysetlist.append(Account(name=i))
Account.objects.bulk_create(querysetlist)

12 命令makemigrations和migrate的差别

执行迁移

python manage.py makemigrations

生成迁移文件

python manage.py migrate

13 视图函数中,接收的请求对象常用方法和属性有哪些

  • path属性,获取请求页面的全路径,不包括域名
  • method属性,获取请求中使用的HTTP方式的字符串表示。全大写表示
  • GET属性,获取HTTP GET方式请求传参,的参数(字典类型)
  • POST属性,获取表单类型的请求体数据
  • body属性获取最原始的请求体数据,自己按照请求体格式(JSON、XML等)进行解析。request.body返回bytes类型。
  • META属性获取请求头headers中的数据,request.META为字典类型

14 常用视图响应的方式是什么?

视图的响应返回使用HttpResponse

HttpResponse(content=响应体, content_type=响应体数据类型, status=状态码) 

一般不用这种方式,我习惯使用:  

response = HttpResponse('language python') 
response.status_code = 400 
response['languaget'] = 'Python'
return response

返回json数据,可以使用JsonResponse来构造响应对象

设置响应头Content-Type为 application/json,例子:

from django.http import JsonResponse 

def demo_view(request): 
    return JsonResponse({'city': 'beijing', 'subject': 'python'})

redirect重定向

我们也可以将返回的结果重定向到另一个页面或接口, 例子:

from django.shortcuts import redirect 

def demo_view(request): 
    return redirect('/index.html')

15 HTTP响应常见状态码分类

Django面试题_第5张图片


16 路由匹配原则是什么?

关于正则匹配优先级(由上而下

在url匹配列表中,如果第一条和第二条同时满足匹配规则,则优先匹配第一条。


17 缓存系统类型有哪些

  • 全站缓存

MIDDLEWARE_CLASSES = (
    'django.middleware.cache.UpdateCacheMiddleware',  # 第一
    'django.middleware.common.CommonMiddleware',
    'django.middleware.cache.FetchFromCacheMiddleware',  # 最后
)
  • 视图缓存

from django.views.decorators.cache import cache_page
import time

@cache_page(15) #超时时间为15秒
def index(request):
    t=time.time() #获取当前时间
    return render(request,"index.html",locals())

  • 模板缓存

{% load cache %}
    

不缓存:-----{{ t }}

{% cache 2 'name' %} # 存的key

缓存:-----:{{ t }}

{% endcache %}

18 解决跨域的常用方式是什么?

跨域是指一个域下的文档或脚本试图去请求另一个域下的资源,这里跨域是广义的。

广义的跨域:

  1. 资源跳转:A链接、重定向、表单提交

  2. 资源嵌入:link script img frame等dom标签,还有样式中background:url()、@font-face()等文件外链

  3. 脚本请求:js发起的ajax请求、dom和js对象的跨域操作等

同源策略/SOP(Same origin policy)是一种约定,由Netscape公司1995年引入浏览器,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,浏览器很容易受到XSS、CSFR等攻击。所谓同源是指"协议+域名+端口"三者相同,即便两个不同的域名指向同一个ip地址,也非同源。

同源策略限制以下几种行为:

  1. Cookie、LocalStorage 和 IndexDB 无法读取

  2. DOM 和 Js对象无法获得

  3. AJAX 请求不能发送


19 信号的作用是什么?

Django中如何在Model保存前做一定的固定操作,比如写一句日志?

关键词:信号

利用Django的Model的Signal Dispatcher, 通过django.db.models.signals.pre_save() 方法,在事件发生前,触发信号,这一切都被调度中的receiver方法深藏功与名的保存了。

信号的处理一般都写在Model中,举个例子:

import logging
from django.db import models
from django.db.models.signals import pre_save
from django.dispatch import receiver
 
class Order(models.Model):
    # ...
 
 
logger = logging.getLogger(__name__)
 
@receiver(pre_save, sender=Order)
def pre_save_handler(sender, **kwargs):
    
    # 我们可以在Order这个Model保存之前尽情调戏了:)
    logger.debug("{}".format(sender, **kwargs))
    print 'fuck universe'

这样应该就实现了题中的要求,类似的方法还有比如 pre_init 是在Model实例之前会触发, post_init 在实例之后触发,同理就是 pre_save 和 post_save 了。 


20 Django的Model的继承有几种形式,分别是什么

抽象继承

表示你的父类仅仅是包含了多个子类的相同的字段,是为了重用,不会建表,我们只需要在抽象父类的Meta中设置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)

 Student模型将会有name,age,home_group三个字段。如果在抽象父类和子类中出现相同的字段名字,django会引发异常。

对于内联的Meta类的继承,一般的,父类的Meta类的属性会继承给子类,子类也可以在自己的Meta中重写或者拓展父类的Meta,拓展的话主要是继承父类的Meta:

class CommonInfo(models.Model):
    ...
    class Meta:
        abstract = True
        ordering = ['name']
 
class Student(CommonInfo):
    ...
    class Meta(CommonInfo.Meta):
        db_table = 'student_info'

这个时候,父类Meta中的abstract=True是不会传递给子类的,django会将子类的abstract设置为False

除了abstract之外,父类Meta中的db_table也不会继承给子类

在抽象类中使用关系(如外键,多对多关系,一对一关系)时候,肯定会设置related_name,但是子类继承抽象父类的时候,由于父类中的字段会继承给子类,则具有related_name的字段会被多个子类共享的。这样每一个子类的related_name就都一样了,其他模型通过related_name就不能找到正确的子类。

所以要正确设置related_name,related_name中必须包含%(app_label)s 和 %(class)s。如

%(app_label)s表示小写形式的,当前模型所在的,并且已经安装的app的名字

%(class)s表示小写形式的,当前子类的类名字。

在common/models.py,有

class Base(models.Model):
    m2m = models.ManyToManyField(OtherModel, related_name="%(app_label)s_%(class)s_related")
 
    class Meta:
        abstract = True
 
class ChildA(Base):
    pass
 
class ChildB(Base):
    pass

在rare/models.py,有

from common.models import Base
 
class ChildB(Base):
    pass

 所以,上面的related_name就是 common_childa_related和 common_childb_related

 多表继承

父类也是一个django模型,并且也会创建一个数据表,多表继承是django中隐式的一对一关系。例如:

class Place(models.Model):
    name = models.CharField(max_length=50)
    address = models.CharField(max_length=80)
 
class Restaurant(Place):
    serves_hot_dogs = models.BooleanField()
    serves_pizza = models.BooleanField()

其中虽然name和address存储在模型Place的表中,但是name和address对于Restaurant也是有效字段 

>>> Place.objects.filter(name="Bob's Cafe")
>>> Restaurant.objects.filter(name="Bob's Cafe")

Restaurant和Place的关系,可以这么说:一个Restaurant一定是一个Place,而一个Place不一定是Restaurant 

多表继承中,一般,父类的Meta属性不会继承到子类中,但是,ordering和 get_latest_by是继承的,如果子类不想继承父类的ordering的Meta,则可以手动显式的指定ordering=[]或者任何自己想要的值

多表继承的时候,是隐式的在父类和子类之间建立一个一对一关系,所以有时候,父类与其他类的关系会从父类下移到子类中。如果有多个子类,且子类不在关系中显式地指定related_name字段,django会引发验证错误

class Supplier(Place):
    # Must specify related_name on all relations.
    customers = models.ManyToManyField(Restaurant, related_name='provider')

所以,继承父类,一旦子类中有关系,就加上related_name吧

django自动在子类和非抽象父类之间创建一个一对一关系,如果你想控制由子类连接回父类的属性的名字,你可以创建一个一对一关系,然后设置parent_link=True 

proxy model(代理模型)

在多表继承中,子类模型会创建一个数据表来存储不在父类模型中的额外字段,但是,如果我们只想改变某个模型的行为方法,而不是添加额外的字段,我们就可以使用

proxy model。代理model(proxy model)会继承父类的属性,并且只是添加一些对属性的操作的自定义方法而已。

class MyPerson(Person):
    class Meta:
        proxy = True
 
    def do_something(self):
        ...zh

这里,MyPerson没有多创建数据表,MyPerson也是对Person的数据表进行操作,一般的,我们可以把MyPerson当做Person来使用,只是在do_something这个方法略有不同,比如

>>> p = Person.objects.create(first_name="foobar")
>>> MyPerson.objects.get(first_name="foobar")

 代理模型和原模型的区别如下面:

class OrderedPerson(Person):
    class Meta:
        ordering = ["last_name"]
        proxy = True

这里,OrderedPerson并不是创建了一个表,而是代理排序方法。也就是说,使用Person的检索方法并不会按last_name排序,而使用OrderedPerson检索出来的结果是按last_name排序的。OrderedPerson使用与Person类一样的检索方法。

OrderPerson返回的queryset自然是Person的,这是当然的。我们不能要求django返回OrderedPerson类的queryset,因为OrderedPerson只是代理而已,又不是真实的数据库表类。

注意的是,proxy model不能继承于抽象类,这是因为代理model是操作连接数据库的,也不能多重继承~因为你多重继承了,代理model就不知道去哪个父类找属性了

如果不指定代理model的manage,则代理model会自动继承父类的manage。我们也可以手动设置代理model的manage,这样,代理模型和父类模型的manage就分开了

为代理模型添加manage有两种方法:

一是直接在代理模型中直接指定manage 

class NewManager(models.Manager):
    ...
 
class MyPerson(Person):
    objects = NewManager()
 
    class Meta:
        proxy = True

另外一种是当你不想覆盖父类模型中的manage但又想添加额外的manage,我们可以新建一个抽象模型,然后定义其manage,之后继承该抽象模型,如:

# Create an abstract class for the new manager.
class ExtraManagers(models.Model):
    secondary = NewManager()
 
    class Meta:
        abstract = True
 
class MyPerson(Person, ExtraManagers):
    class Meta:
        proxy = True

21 Django中查询queryset时什么情况下用Q

F:对数据本身的不同字段进行操作 如:比较和更新,对数据进行加减操作

Q:用于构造复杂的查询条件 如:& |操作


22 Django中想验证表单提交是否格式正确需要用到Form中的哪个函数

form.is_valid():返回布尔值


23 orm如何取消级联

在设置外键时,需要通过on_delete选项指明主表删除数据时,对于外键引用表数据如何处理,在django.db.models中包含了可选常量:

  • CASCADE 级联,删除主表数据时连通一起删除外键表中数据

  • PROTECT 保护,通过抛出ProtectedError异常,来阻止删除主表中被外键应用的数据

  • SET_NULL 设置为NULL,仅在该字段null=True允许为null时可用

  • SET_DEFAULT 设置为默认值,仅在该字段设置了默认值时可用

  • SET() 设置为特定值或者调用特定方法


24 Django中如何读取和保存session,整个session的运行机制是什么

更新

    在django—session表中创建一条记录:

    session-key                            session-data

    ltv8zy1kh5lxj1if1fcs2pqwodumr45t        更新数据

else:

    生成随机字符串    ltv8zy1kh5lxj1if1fcs2pqwodumr45t

    response.set_cookie("sessionid",ltv8zy1kh5lxj1if1fcs2pqwodumr45t)

    在django—session表中创建一条记录:

    session-key                            session-data

    ltv8zy1kh5lxj1if1fcs2pqwodumr45t        {"is_login":True,"username":"yuan"}

25 简述Django对http请求的执行流程

在接受一个Http请求之前的准备,启动一个支持WSGI网关协议的服务器监听端口等待外界的Http请求,比如Django自带的开发者服务器或者uWSGI服务器。  

服务器根据WSGI协议指定相应的Handler来处理Http请求,并且初始化该Handler,在Django框架中由框架自身负责实现这一个Handler。 此时服务器已处于监听状态,可以接受外界的Http请求 当一个http请求到达服务器的时候   

服务器根据WSGI协议从Http请求中提取出必要的参数组成一个字典(environ)并传入Handler中进行处理。  

在Handler中对已经符合WSGI协议标准规定的http请求进行分析,比如加载Django提供的中间件,路由分配,调用路由匹配的视图等。 返回一个可以被浏览器解析的符合Http协议的HttpResponse。


25 Django中当用户登录到A服务器进入登陆状态,下次被nginx代理到B服务器会出现什么影响

如果用户在A应用服务器登陆的session数据没有共享到B应用服务器,那么之前的登录状态就没有了。


26 跨域请求Django是如何处理的

  • 启用中间件
  • post请求
  • 验证码
  • 表单中添加{% csrf_token %}标签

27 查询集的两大特性?什么是惰性执行

  • 惰性执行、缓存 。  
  • 创建查询集不会访问数据库,直到调用数据时,才会访问数据库,调用数据的情况包括迭代、序列化、与if合用

28 查询集返回的列表过滤器有哪些

  • all():返回所有数据  
  • filter():返回满足条件的数据 
  • exclude():返回满足条件之外的数据,相当于sql语句中where部分的not关键字  
  • order_by():排序

29 django路由系统中include是干嘛用的?

include路由转发

通常,我们会在每个app里,各自创建一个urls.py路由模块,然后从根路由出发,将app所属的url请求,全部转发到相应的urls.py模块中。


30 urlpatterns中的name与namespace有什么作用?你是如何使用的?

别名,给路由起一个别名

名称空间,防止多个应用之间的路由重复


31 如何根据urlpatterns中的name反向生成url,这样反向生成url的方式有几种?

使用HttpResponseRedirect redirect和reverse 状态码:302,301


32 如何给一个字段设置一个主键?

primary_key


33 如何设置一个带有枚举值的字典?

Django面试题_第6张图片


34 DateTimeField类型中的auto_now与auto_now_add有什么区别

  • DateTimeField.auto_now

这个参数的默认值为false,设置为true时,能够在保存该字段时,将其值设置为当前时间,并且每次修改model,都会自动更新。因此这个参数在需要存储“最后修改时间”的场景下,十分方便。需要注意的是,设置该参数为true时,并不简单地意味着字段的默认值为当前时间,而是指字段会被“强制”更新到当前时间,你无法程序中手动为字段赋值;如果使用django再带的admin管理器,那么该字段在admin中是只读的。

  • DateTimeField.auto_now_add

这个参数的默认值也为False,设置为True时,会在model对象第一次被创建时,将字段的值设置为创建时的时间,以后修改对象时,字段的值不会再更新。该属性通常被用在存储“创建时间”的场景下。与auto_now类似,auto_now_add也具有强制性,一旦被设置为True,就无法在程序中手动为字段赋值,在admin中字段也会成为只读的。


35 selected_related与prefetch_related有什么区别?

在Django中,所有的Queryset都是惰性的,意思是当创建一个查询集的时候,并没有跟数据库发生任何交互。因此我们可以对查询集进行级联的filter等操作,只有在访问Queryset的内容的时候,Django才会真正进行数据库的访问。而多频率、复杂的数据库查询往往是性能问题最大的根源。

不过我们实际开发中,往往需要访问到外键对象的其他属性。如果按照默认的查询方式去遍历取值,那么会造成多次的数据库查询,效率可想而知。

在查询对象集合的时候,把指定的外键对象也一并完整查询加载,避免后续的重复查询。

1,select_related适用于外键和多对一的关系查询;

2,prefetch_related适用于一对多或者多对多的查询。


36 class Meta中的元信息字段有哪些

通过一个内嵌类 "class Meta" 给你的 model 定义元数据, 类似下面这样:

class User(AbstractUser):
    """用户模型类"""
    mobile = models.CharField(max_length=11, unique=True, verbose_name='手机号')
    email_active = models.BooleanField(default=False, verbose_name='邮箱验证状态')
    default_address = models.ForeignKey('Address', related_name='users', null=True, blank=True,
                                        on_delete=models.SET_NULL, verbose_name='默认地址')

    class Meta:
        db_table = 'tb_users'
        verbose_name = '用户'
        verbose_name_plural = verbose_name

37 django的M2M关系,如何手动生成第三张表?

tags = models.ManyToManyField(
    to="Tag",
    through='Article2Tag',
    through_fields=('article', 'tag'),
)

38 在Django中,服务端给客户端响应信息有几种方式?分别是什么?

  • HTTPresponse
  • jsonresponse
  • redirect

39 web框架的本质是什么?

本质上其实就是一个socket服务端,用户的浏览器其实就是一个socket客户端。


40 创建Django工程、Django app、以及运行的命令

# 创建新的项目
django-admin.py startproject my_project

# 在Django项目(my_project)的根目录下执行
python3 manage.py startapp my_app

# 启动Django中的开发服务器
# run server
python3 manage.py runserver

41 django中csrf的实现机制

第一步:django第一次响应来自某个客户端的请求时,后端随机产生一个token值,把这个token保存在SESSION状态中;同时,后端把这个token放到cookie中交给前端页面;

第二步:下次前端需要发起请求(比如发帖)的时候把这个token值加入到请求数据或者头信息中,一起传给后端;Cookies:{csrftoken:xxxxx}

第三步:后端校验前端请求带过来的token和SESSION里的token是否一致;


42 Django App的目录结构

Django面试题_第7张图片


43 什么是Cookie、如何获取、设置Cookie

会话跟踪技术,保留用户

Cookie是由服务器创建,然后通过响应发送给客户端的一个键值对。

具体一个浏览器针对一个服务器存储的key-value

response.set_cookie("is_login",True)
request.COOKIES.get("is_login")

44 什么是session,与cookie的对比、设置、获取、清空session

Session是服务器端技术,利用这个技术,服务器在运行时可以 为每一个用户的浏览器创建一个其独享的session对象,由于 session为用户浏览器独享,所以用户在访问服务器的web资源时 ,可以把各自的数据放在各自的session中,当用户再去访问该服务器中的其它web资源时,其它web资源再从用户各自的session中 取出数据为用户服务。 

request.session["is_login"] = True
is_login = request.session.get("is_login")
request.session.flush()

45 什么是CSRF,及防范方式

  • 启用中间件
  • post请求
  • 验证码
  • 表单中添加{%csrf_token%}标签

46 get请求和post请求的区别

  • GET提交的数据会放在URL之后,以?分割URL和传输数据,参数之间以&相连,如EditBook?name=test1&id=123456。POST方法是把提交的数据放在HTTP包的Body中。
  • GET提交的数据大小有限制(因为浏览器对URL的长度有限制),而POST方法提交的数据没有限制。
  • GET与POST请求在服务端获取请求数据方式不同。
  • GET方式提交数据,会带来安全问题,比如一个登录页面,通过GET方式提交数据时,用户名和密码将出现在URL上,如果页面可以被缓存或者其他人可以访问这台机器,就可以从历史记录获得该用户的账号和密码。

47 如何使用django加密

Django 内置的User类提供了用户密码的存储、验证、修改等功能,默认使用pbkdf2_sha256方式来存储和管理用的密码。

django通过setting.py文件中的PASSWORD_HASHERS来设置选择要使用的算法,列表的第一个元素 (即settings.PASSWORD_HASHERS[0]) 会用于储存密码, 所有其它元素都是用于验证的哈希值,它们可以用于检查现有的密码。意思是如果你打算使用不同的算法,你需要修改PASSWORD_HASHERS,来将你最喜欢的算法在列表中放在首位。

一个settings中的Password_hashers看起来是这样的:

PASSWORD_HASHERS = ( 
    'django.contrib.auth.hashers.PBKDF2PasswordHasher',
    'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher',
    'django.contrib.auth.hashers.BCryptSHA256PasswordHasher',
    'django.contrib.auth.hashers.BCryptPasswordHasher',
    'django.contrib.auth.hashers.SHA1PasswordHasher',
    'django.contrib.auth.hashers.MD5PasswordHasher',
    'django.contrib.auth.hashers.CryptPasswordHasher',
)

具体的密码生成以及验证实现

from django.contrib.auth.hashers import make_password,check_password

pwd='4562154'
mpwd=make_password(pwd,None,'pbkdf2_sha256')  # 创建django密码,第三个参数为加密算法
pwd_bool=check_password(pwd,mpwd)  # 返回的是一个bool类型的值,验证密码正确与否

Django之密码加密

通过django自带的类库,来加密解密很方便,下面来简单介绍下;

导入包:

from django.contrib.auth.hashers import make_password, check_password

从名字就可以看出来他们的作用了。

一个是生成密码,一个是核对密码。

例如:

make_password("123456")

得到结果:

u'pbkdf2_sha25615000MAjic3nDGFoi$qbclz+peplspCbRF6uoPZZ42aJIIkMpGt6lQ+Iq8nfQ='

另外也可以通过参数来生成密码:

>>> make_password("123456", None, 'pbkdf2_sha256')

校验:

校验就是通过check_password(原始值, 生成的密文)来校验密码的。

>>> check_password("123456","pbkdf2_sha25615000MAjic3nDGFoi$qbclz+peplspCbRF6uoPZZ42aJIIkMpGt6lQ+Iq8nfQ=")
>>> True

48 解释blank和null

  • blank

设置为True时,字段可以为空。设置为False时,字段是必须填写的。字符型字段CharField和TextField是用空字符串来存储空值的。如果为True,字段允许为空,默认不允许。

  • null

设置为True时,django用Null来存储空值。日期型、时间型和数字型字段不接受空字符串。所以设置IntegerField,DateTimeField型字段可以为空时,需要将blank,null均设为True。

如果为True,空值将会被存储为NULL,默认为False。

如果想设置BooleanField为空时可以选用NullBooleanField型字段。

一句话概括

  • null 是针对数据库而言,如果 null=True, 表示数据库的该字段可以为空。NULL represents non-existent data.
  • blank 是针对表单的,如果 blank=True,表示你的表单填写该字段的时候可以不填。比如 admin 界面下增加 model 一条记录的时候。直观的看到就是该字段不是粗体

49 QueryDict和dict区别

在 HttpRequest 对象中,属性 GET 和 POST 得到的都是 django.http.QueryDict 所创建的实例。这是一个 django 自定义的类似字典的类,用来处理同一个键带多个值的情况。

在 python 原始的字典中,当一个键出现多个值的时候会发生冲突,只保留最后一个值。而在 HTML 表单中,通常会发生一个键有多个值的情况,例如