Django 进阶(装饰器,Mixin,信号,模式)
来源:互联网 发布:unity3d 性能测试工具 编辑:程序博客网 时间:2024/05/16 15:03
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 = Trueclass SuperHeroProfile(models.Model): origin = models.CharField(max_length=100, blank=True, null=True) class Meta: abstract = Trueclass OrdinaryProfile(models.Model): address = models.CharField(max_length=200, blank=True, null=True) class Meta: abstract = Trueclass 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.pyfrom django.db.models.signals import post_savefrom django.dispatch import receiverfrom django.conf import settingsfrom . 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__.pydefault_app_config = "profile.apps.ProfileConfig"
接下来是app.py
中的子类ProfileConfig
方法,可使用ready方法配置信号:
# apps.pyfrom django.apps import AppConfigclass ProfileConfig(AppConfig): name = "profiles" verbose_name = "User Profiles" def ready(self): from . import signals
为了操作方便,账户admin
可以通过定义一个自定义的UserAdmin
嵌入到默认的用户admin
中:
# admin.pyfrom django.contrib import adminfrom .models import Profilefrom django.contrib.auth.models import Userclass UserProfileInline(admin.StackedInline): model = Profileclass 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.pyAPI_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 SuperHeroWebAPIdef is_superhero(self): return SuperHeroWebAPI.is_superhero(self.user.username)
模型的方法作为属性
Python类可以使用property
装饰器把函数当作一个属性来使用。这样,Django模型也可以较好地利用它。替换前面那个例子中的函数:
@propertydef 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_requireddef 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)
nav active的问题
每个模板都要包含下列代码:
{% include "_navbar.html" with active_link='link2' %}
然后
{# _navbar.html #}<ul class="nav nav-pills"> <li{% if active_link == "link1" %} class="active"{% endif %}><ahref="{% url 'link1' %}">Link 1</a></li> <li{% if active_link == "link2" %} class="active"{% endif %}><ahref="{% url 'link2' %}">Link 2</a></li> <li{% if active_link == "link3" %} class="active"{% endif %}><ahref="{% url 'link3' %}">Link 3</a></li></ul>
之前我都是从view传一个current_page
变量来判断的,好蠢
Template tag
# app/templatetags/nav.pyfrom django.core.urlresolvers import resolvefrom django.template import Libraryregister = Library()@register.simple_tagdef 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.pyclass 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.pyclass PersonDetailsEdit(generic.FormView): ... def get_form_kwargs(self): kwargs = super().get_form_kwargs() kwargs["upgrade"] = True return kwargs
用户表单(表单需要根据已经登录的用户来进行定制)
需要django-braces
库
from braces.forms import UserKwargModelFormMixinclass 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.pyclass 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.pyfrom .forms import SubscribeForm, UnSubscribeFormclass 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)
这里我感觉登录和注册两个表单可以用这个方法
可以偷懒的第三方包^_^
1 0
- Django 进阶(装饰器,Mixin,信号,模式)
- Java进阶笔记(装饰者模式)
- Sass进阶-(数据类型,变量运算,mixin)
- JS设计模式(一)Mixin classes
- Django自定义装饰器
- 装饰器-Django登录
- Python进阶-装饰器
- 设计模式--Mixin模式
- 设计模式--Mixin模式
- Django类视图与Mixin
- python mixin到底是什么 django
- 【Python学习日记】【设计模式】装饰器(装饰模式)
- CDI进阶第六步 CDI装饰模式
- Decorator(装饰器模式)
- 装饰器模式(Decorator)
- Session_Decorator(装饰器模式)
- 装饰器模式(Decorator )
- Decorator(装饰器)模式
- hibernate进阶之路之一对一映射(二)
- AppStore审核被拒--后台定位
- Easy-题目7:100. Same Tree
- [JavaScript] 8.JS BOM对象
- IOS 关于取消延迟执行函数的种种。performSelector与cancelPreviousPerformRequestsWithTarget
- Django 进阶(装饰器,Mixin,信号,模式)
- Android APP的字体设置
- android 6.0sd卡内部存储 & 外部存储
- tomcat+websocket实现
- PID2 / 开心的金明
- leetcode 11
- 出题&题解
- ViewPager+Fragment+RadioGroup实现页面联动\点击切换
- 手写一个SqlHelper