Django 进阶(装饰器,Mixin,信号,模式)

原创 2016年05月30日 19:47:49

Django中级用法

抽象models类

class BaseProfile(models.Model):
    USER_TYPES = (
        (0, 'Ordinary'),
        (1, 'SuperHero'),
    )

    user = models.OnToOneField(settings.AUTH_USER_MODEL, primary_key=True)
    user_type = models.IntegerField(max_length=1, null=True,    choices=USER_TYPES)
    bio = models.CharField(max_length=200, blank=True, null=True)

    def __str__(self):
        return "{}:{:.20}".format(self.user, self.bio or "")

    class Meta:
        abstract = True


class SuperHeroProfile(models.Model):
    origin = models.CharField(max_length=100, blank=True, null=True)

    class Meta:
        abstract = True


class OrdinaryProfile(models.Model):
    address = models.CharField(max_length=200, blank=True, null=True)

    class Meta:
        abstract = True


class Profile(SuperHeroProfile, OrdinaryProfile, BaseProfile):
    pass

扩展django内建User

定义(Profile.models)

# models.py
# 将primary_key赋值为True,以阻止类似PostgreSQL这样的数据库后端中的并发问题
class Profile(models.Model):
    user = models.OnToOneField(settings.AUTH_USER_MODEL, primary_key=True)

信号

# signals.py
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.conf import settings
from . import models


@receiver(post_save, sender=settings.AUTH_USER_MODEL)
def create_profile_handler(sender, instance, created, **kwargs):
    if not created:
        return
    # 仅在created是最新时才创建账户对象
    profile = models.Profile(user=instance)
    profile.save()

首先,为你的应用创建一个__init__.py包以引用应用的ProfileConfig:

# __init__.py
default_app_config = "profile.apps.ProfileConfig"

接下来是app.py中的子类ProfileConfig方法,可使用ready方法配置信号:

# apps.py
from django.apps import AppConfig

class ProfileConfig(AppConfig):
    name = "profiles"
    verbose_name = "User Profiles"

    def ready(self):
        from . import signals

为了操作方便,账户admin可以通过定义一个自定义的UserAdmin嵌入到默认的用户admin中:

# admin.py
from django.contrib import admin
from .models import Profile
from django.contrib.auth.models import User


class UserProfileInline(admin.StackedInline):
    model = Profile


class UserAdmin(admin.UserAdmin):
    inlines = [UserProfileInline]


admin.site.unregister(User)
admin.site.register(User, UserAdmin)

更新:

上下文Mixin

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")

服务模式

# service.py
API_URL = "http://api.herocheck.com/?q={0}"

class SuperHeroWebAPI:
    ...

    @staticmehtod
    def is_hero(username):
        url = API_URL.format(username)
        return webclient.get(url)

加上黑名单功能的服务

class SuperHeroWebAPI:
    ...

    @staticmethod
    def is_hero(username):
        blacklist = set(["syndrome", "kcka$$", "superfake"])
        ulr = API_URL.format(username)
        return username not in blacklist and webclient.get(url)

使用服务

from .services import SuperHeroWebAPI

def is_superhero(self):
    return SuperHeroWebAPI.is_superhero(self.user.username)

模型的方法作为属性

Python类可以使用property装饰器把函数当作一个属性来使用。这样,Django模型也可以较好地利用它。替换前面那个例子中的函数:

@property
def age(self):
    ...

现在我们可以用profile.age来访问用户的年龄。注意,函数的名称要尽可能的短。

缓存特性

很好理解,直接看代码:

from django.utils.function import cached_property
    #...
    @cached_property
    def full_name(self):
        # 代价高昂的操作,比如,外部服务调用
        return "{0} {1}".format(self.firstname, self.lastname)

定制模型管理器(Manager)

太简单了,直接看官网

Querysets 组合查询

from django.db.models import Q

# Union 交集
>>> User.objects.filter(Q(username__in["a", "b", "c"]) | Q(username__in=["c", "d"]))
[`<User: a>, <User: b>, <User: c>, <User: d>`]

# Intersection 并集
>>> User.objects.filter(Q(username__in["a", "b", "c"]) & Q(username__in=["c", "d"]))
[<User: c>]

# Difference 补集
>>> User.objects.filter(Q(username__in=["a", "b", "c"]) & ~Q(username__in=["c", "d"]))
[<User: a>, <User: b>]

Querysets链接

这是一个很天真的做法,开销很大:

>>> recent = list(posts)+list(comments)
>>> sorted(recent, key=lambda e: e.modified, reverse=True)[:3]
[<Post: user: Post1>, <Comment: user: Comment1>, <Post: user: Post0>]

一个更好的解决方案是使用迭代器减少内存消耗。如下,使用itertools.chain方法合并多个QuerySets:

>>> from itertools import chain
>>> recent = chain(posts, comments)
>>> sorted(recent, key=lambda e: e.modified, reverse=True)[:3]

以上:2016年05月31日14:51:32

装饰器

第一种

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

2 通过对基于函数视图或者基于类视图使用一个装饰器实现控制:

@login_required(MyView.as_view())

3 通过覆盖mixin的类视图的dispatch方法实现控制:

class LoginRequiredMixin:
    @method_decorator(login_required)
    def dispatch(self, request, *args, **kwargs):
        return super().dispatch(request, *args, **kwargs)

每个模板都要包含下列代码:

{% include "_navbar.html" with active_link='link2' %}

然后

{# _navbar.html #}
<ul class="nav nav-pills">
  <li{% if active_link == "link1" %} class="active"{% endif %}><a
href="{% url 'link1' %}">Link 1</a></li>
  <li{% if active_link == "link2" %} class="active"{% endif %}><a
href="{% url 'link2' %}">Link 2</a></li>
  <li{% if active_link == "link3" %} class="active"{% endif %}><a
href="{% url 'link3' %}">Link 3</a></li>
</ul>

之前我都是从view传一个current_page变量来判断的,好蠢

Template tag

# app/templatetags/nav.py
from django.core.urlresolvers import resolve
from django.template import Library

register = Library()

@register.simple_tag
def active_nav(request, url):
   url_name = resolve(request.path).url_name
   if url_name == url:
       return "active"
   return ""

使用:

{# base.html #}
{% load nav %}
<ul class="nav nav-pills">
  <li class={% active_nav request 'active1' %}><a href="{% url
'active1' %}">Active 1</a></li>
  <li class={% active_nav request 'active2' %}><a href="{% url
'active2' %}">Active 2</a></li>
  <li class={% active_nav request 'active3' %}><a href="{% url
'active3' %}">Active 3</a></li>
</ul>

表单

动态表单

# forms.py
class PersonDetailsForm(forms.Form):
    name = forms.CharField(max_length=100)
    age = forms.IntegerField()
    def __init__(self, *args, **kwargs):
       upgrade = kwargs.pop("upgrade", False)
       super().__init__(*args, **kwargs)
       # Show first class option? 显示头等舱选项?
       if upgrade:
            self.fields["first_class"] = forms.BooleanField(label="Fly First Class?")
# views.py
class PersonDetailsEdit(generic.FormView):
    ...
    def get_form_kwargs(self):
        kwargs = super().get_form_kwargs()
        kwargs["upgrade"] = True
        return kwargs

用户表单(表单需要根据已经登录的用户来进行定制)

需要django-braces

from braces.forms import UserKwargModelFormMixin

class PersonDetailsForm(UserKwargModelFormMixin, forms.Form):
    ...
    def __init__(self, *args, **kwargs):
       super().__init__(*args, **kwargs)
       # Are you a member of the VIP group?
       if self.user.groups.filter(name="VIP").exists():
           self.fields["first_class"] = forms.BooleanField(label="Fly First Class?")

然后再确认只有登录用户才能看到此视图

class VIPCheckFormView(LoginRequiredMixin, UserFormKwargsMixin,
generic.FormView):
   form_class = PersonDetailsForm
   ...

一个视图的多个表单行为

crispy表单订阅器修改不同的按钮

# forms.py
class SubscribeForm(forms.Form):
    email = forms.EmailField()

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.helper = FormHelper(self)
        self.helper.layout.append(Submit('subscribe_butn', 'Subscribe'))

UnSubscribeForm以完全相同的方式来定义,除了按钮不同

# views.py
from .forms import SubscribeForm, UnSubscribeForm

class NewsletterView(generic.TemplateView):
   subcribe_form_class = SubscribeForm
   unsubcribe_form_class = UnSubscribeForm
   template_name = "newsletter.html"

   def get(self, request, *args, **kwargs):
       kwargs.setdefault("subscribe_form", self.subcribe_form_class())
       kwargs.setdefault("unsubscribe_form", self.unsubcribe_form_class())
       return super().get(request, *args, **kwargs)

单独来看post方法

    def post(self, request, *args, **kwargs):
       form_args = {
           'data': self.request.POST,
           'files': self.request.FILES,
       }

       if "subscribe_butn" in request.POST:
           form = self.subcribe_form_class(**form_args)
           if not form.is_valid():
               return self.get(request,
                                  subscribe_form=form)
           return redirect("success_form1")
       elif "unsubscribe_butn" in request.POST:
           form = self.unsubcribe_form_class(**form_args)
           if not form.is_valid():
               return self.get(request,
                                  unsubscribe_form=form)
           return redirect("success_form2")
       return super().get(request)

这里我感觉登录和注册两个表单可以用这个方法


可以偷懒的第三方包^_^

package desc
django-braces 通用视图扩展(Mixin) StaticContextMixin
django-crispy-forms form前端标签扩展 {% crispy_form %}
zebra stripes are neat $1
版权声明:本文为博主原创文章,未经博主允许不得转载。 举报

相关文章推荐

Django外键查询及@property在model中的妙用

上篇文章中聊了聊@property的用法,这篇文章则聊聊@property在数据库model中的一些小技巧,同时也会涉及些Django在数据库建模的过程中,外键查询和反向查询方面的内容。

django 信号机制

翻译自:django 1.6官方文档。水平有限,如有错误,还望

精选:深入理解 Docker 内部原理及网络配置

网络绝对是任何系统的核心,对于容器而言也是如此。Docker 作为目前最火的轻量级容器技术,有很多令人称道的功能,如 Docker 的镜像管理。然而,Docker的网络一直以来都比较薄弱,所以我们有必要深入了解Docker的网络知识,以满足更高的网络需求。

Django类视图与Mixin

在上一篇Django处理http请求流程剖析中,笔者详细地说明了Django框架是如何根据WSGI协议处理一个Http请求的。其中,处理开发者自行定义的View的代码如下:# django.core....

基于 Django1.10 文档的深入学习(18)—— Using the Django authentication system 之 LoginRequiredMixin

Using the Django authentication system使用Django认证系统本文档介绍了Django身份验证系统的默认配置。 这种配置已经演变为满足最常见的项目需求,处理相当广...

Django模板系统(非常详细)

转载:http://www.czug.org/python/django/04.html 翻译www.djangobook.com之第四章:Django模板系统 The Django...

Django自定义用于Views的装饰器

Django自定义用于Views的装饰器不带参数的装饰器from functools import wraps def object_does_not_exist(func): @wra...

[python] Mixin 扫盲班

Mixin 扫盲班赖勇浩(http://blog.csdn.net/lanphaday) 声明:本文适合初中级Python程序员阅读,另外本文措词可能会导致阅读者不适,敬请PG。 引子嗯,为什么要谈M...

【Python基础】Python面向对象 - 7 - Mixin & MRO

转自:http://xiaocong.github.io/blog/2012/06/13/python-mixin-and-mro/ 什么是 mixin ? In obje...

设计模式--Mixin模式

Adapter模式:把一个接口转换为另一个接口。 Decorator模式:给一个对象动态增加功能。比如Java的 new BufferedOutputStream(new FileOutputS...
  • xuhx
  • xuhx
  • 2011-09-09 15:27
  • 5736

React入门笔记(四) — 组件的复合与mixin

复合 本质上是对组件的一种组织、管理方式,实现代码的封装 Mixin(混入):就是将抽离出组件相同逻辑处理部分混入到组件中,实现代码的复用 一、组件嵌套   想要在父组件中嵌套子组件,和引用...
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)