相关文章推荐
谈谈 django 应用实践

谈谈 django 应用实践

python 的 web 框架非常多,比较出名的有 django, flask, tornado。django 作为一个老牌框架,无论是文档还是代码质量都非常高,另外他自带的 admin 后台和一些有用的 app,如果你的需求是做 cms 之类的 web 应用的话,基本上不用开发多少代码就能出一个成品。不过很多新手可能一开始不太适应他的设计模式,遇到问题后基本就懵了,所以这里我按照自己用 django 的经验,写一下 django 的一些应用实践,可能写的比较零散,大家见谅。


整体流程

首先我们得了解下 django 这个框架整体的处理流程,假设我们采用 nginx + uwsgi + django 的 web server 模式

1. 一个请求过来后,首先经过 nginx 做反向代理,将请求转发到 uwsgi (python 用 wsgi 这种协议来解析 http 请求,uwsgi 是一个 解析 wsgi 的应用),uwsgi 再将解析过的数据传到 django。

2. django 收到请求后,首先会经过一组全局的中间件 (middleware),调用 process_request 作为预处理,比如解析用户状态,检验 csrf_token (post 请求),如果有问题,则直接返回 response,不再调用 view 函数。否则,调用 process_view ,如果没问题进入 view 函数。

3. 进入 view 函数后开发者可以写自己的逻辑,比如操作数据库,更新缓存,最后返回一个 response。

4. 接下来 跳出 view 函数,重新进入 middleware,调用 process_response,对 response 做些最后的修饰,返回给用户。


views 模块

1. view 不仅可以用函数,也可以用通用视图类(generic_view),好处是:代码更加清晰,可以复用继承,并且结合 mixin 能够开发更加灵活的 view 模块

def hello_fn(request, name="World"):
        return HttpResponse("Hellp {}!".format(name))
class FeedMixin(object):
        def get_context_data(self, **kwargs):
            context = super().get_context_data(**kwargs)
            context["feed"] = models.Post.objects.viewable_posts(self.request.user)
            return context
class MyFeed(FeedMixin, generic.CreateView):
        model = models.Post
        template_name = "myfeed.html"
        success_url = reverse_lazy("my_feed")


2. python 的装饰器很好用,也可以用于 views 函数, 比如下面的装饰器用于登录用户的检测


@login_required
def simple_view(request):
       return HttpResponse()


urls 模块

1. urls.py 这个文件将访问的 url 跟 view 模块对应起来,按从上到下的顺序匹配

2. 采用 include 函数可以包含其他 app 的 urls,namespace 参数定义后可以在模板中直接调用,比如

{% url 'articles'%} 
url(r'^articles/$', include(articles.urls), namespace="articles"),


models 模块

1. model 是具有处理数据库的一种面向对象的方法的类,能够让不熟悉数据库语句的程序员也能快速操作数据库


2. 采用面向对象的方式创建类,加上 abstract = True 则为抽象类


class Postable(models.Model):
    created = models.DateTimeField(auto_now_add=True)
    modified = modified.DateTimeField(auto_now=True)
    message = models.TextField(max_length=500)
    class Meta:
        abstract = True
class Post(Postable):
class Comment(Postable):
   ···


3. django 表对应关系有一对一(OneToOneField),一对多 (ForeignKey),多对多 (ManyToManyField),其中 多对多的模式通过创建一个中间表来实现。

class Book(models.Model):
    place = models.OneToOneField(Place, primary_key=True)
    pub=models.ForeignKey(Publisher)
    authors=models.ManyToManyField(Author)

上面的例子中间表包括 author_id 和 book_id


4. django 的 signal 实现 hook 数据库写行为,比如,pre_save, post_save,pre_delete, post_delete,你也可以自定义 signal, hook 其他行为。

@receiver(post_save, sender=TransactionDetail, dispatch_uid="update_stock_count")
def update_stock(sender, instance, **kwargs):
     instance.product.stock -= instance.amount
     instance.product.save()


5. Person.objects.all(), 这里面的 objects 其实是个 manager, 实现了 all, filter 等函数,可以自定义。

class Person(models.Model):
    object = models.Manager()


6. django 的 queryset 是惰性的,只有在真正用的时候才会去数据库查询,并且查询一次后,会有缓存,当再次遍历这个 queryset 的时候,不会再去查询。

person_set = Person.objects.filter(first_name="Dave")


7. 数据库第一次创建后,会有再次更新字段的需求。django 在 1.4 版本前并没有这个功能,得用第三方库 south 来更新,后来的版本 django 自带了 migration 功能,能够将最新的 model 版本和数据库的字段作对比,自动生成 migration 文件

  python manage.py makemigrations # 生成 migration 文件
   python manage.py migrate # 将更改应用到数据库


8. orm 不能直接看到 raw sql 语句,可以通过如下语句查看 sql

from django.db import connection
connection.queries


9. 可以使用 django-debug-toolbar 插件查看慢查询,也能对对哪些页面载入较慢有个大致的了解。


10. 在 orm 中使用 select_related() 减少查询数据库次数:,select_related() 会自动扩展外键关系

class Province(models.Model):
    name = models.CharField(max_length=10)
class City(models.Model):
    name = models.CharField(max_length=5)
    province = models.ForeignKey(Province)
citys = City.objects.select_related().all()


不过对于高并发的应用来说外键不是很推荐。


forms 模块

1. 前端传上来一个表单的值,但是没法确认这些值是不是为空,是不是类型正确,这个时候当然可以自己一个个值判断,也可以采用 forms 模块去做验证,用过 django-rest-framework 的同学会知道和里面的 serializers 是同一个概念

class PersonDetailsForm(forms.Form):
       name = forms.CharField(max_length=100)
       age = forms.IntegerField()


2. 如果你用的是模板渲染的方式,那么展示的时候更简单,表单能自动生成 html 的表单。

>>> f = PersonDetailsForm()
>>> print(f.as_p())
<p><label for="id_name">Name:</label> <input id="id_name" maxlength="100"
name="name" type="text" /></p>
<p><label for="id_age">Age:</label> <input id="id_age" name="age"
type="number" /></p>


admin 模块

1. admin 基本上开箱即用,如果需要定制的话,也能做一些组件的定制,不过这些东西得看文档去详细了解了。


commands 模块

1. django 提供了后台脚本模块,可以自己集成 BaseCommand 类去自定义脚本

python mannage.py -h

这个命令就能看到所有的 commands 命令


2. 如果不想用他的模块,又想引入 django 项目的一些模块,可以采用下面的方法解决

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "myproject.settings")
django.setup()


settings 模块

1. 所有的 settings 默认值都在这里面能找到, github.com/django/djang

2. 上线的时候记得把 DEBUG 改成 False, 然后加上 ALLOWED_HOSTS

3. MEDIA_ROOT, MEDIA_URL, STATIC_ROOT, STATIC_URL 这几个之前经常搞混,其实可以分为两类,MEDIA_ROOT 指的是上传文件的目录,MEDIA_URL 指的是前缀名, http://example.com/media/, 其中的media 就是 MEDIA_URL, 同样,STATIC_ROOT 指的是静态文件的目录,一般放 css, js 之类,STATIC_URL 值得是前缀名, http://example.com/static/。

4. 一般部署上线的时候,用 nginx 直接渲染静态文件

   location /media  {
 
推荐文章