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
定義(Profile.models)html
# 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
:python
# __init__.py default_app_config = "profile.apps.ProfileConfig"
接下來是app.py
中的子類ProfileConfig
方法,可以使用ready方法配置信號:web
# 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)
更新:django
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模型也能夠較好地利用它。替換前面那個例子中的函數:api
@property def age(self): ...
很好理解,直接看代碼:緩存
from django.utils.function import cached_property #... @cached_property def full_name(self): # 代價高昂的操做,好比,外部服務調用 return "{0} {1}".format(self.firstname, self.lastname)
太簡單了,直接看官網併發
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>]
這是一個很天真的作法,開銷很大:app
>>> 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()
@login_required(MyView.as_view())
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
變量來判斷的,好蠢
# 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)
這裏我感受登陸和註冊兩個表單能夠用這個方法