文章列表
 
2011年08月22日 20:25
 
2011年07月22日 15:39

为每个用户分配各个数据表的读、写、删除权限,其实不单单是企业开发需要,一般系统同样需要。但是在企业应用中我们还需要根据,即监督那些白名单中的用户行为。比如,有删除权限的用户,删除了某条销售记录,但是我想知道是谁干的...

下面,我就谈谈目前我采取的方法,

1/方法一 txt格式的log文件  
记录格式
2011-07-21 15:54:22,020 INFO views.customer_add Line:116>>User,ghiewa -Action,Add -Table,vendor_customer
2011-07-21 15:54:22,020 INFO views.customer_add Line:116>>User,ghiewa -Action,Add -Table,vendor_customer

 首先配置log,

若使用是Django1.3之前的版本需要配置 (在setting文件末尾添加)
root = logging.getLogger()
if len(root.handlers) == 0: pass #avoid conflict
level = logging.INFO
filename = os.path.join(PROJECT_ROOT,'log.log')
format = '%(asctime)s %(levelname)s %(module)s.%(funcName)s Line:%(lineno)d%(message)s'
hdlr = handlers.TimedRotatingFileHandler(filename,"midnight",1,90)
fmt = logging.Formatter(format)
hdlr.setFormatter(fmt)
root.addHandler(hdlr)
root.setLevel(level)

然后,

在views.py中
import logging
在具体model 操作语句后添加
logging.info('>>User,%s -Action,%s -Table,%s' %(request.user.username,'Add','vendor_contact'))

 --附--

若是1.3版本
import logging

# Get an instance of a logger
logger = logging.getLogger(__name__)

def my_view(request, arg1, arg):
    ...
    if bad_mojo:
        # Log an error message
        logger.error('Something went wrong!')

 

2/ 方法二、 使用simple_history APP (github.com上获取代码)
将改APP放置到python可视的目录下,比如我放置在当前工程的ext文件夹下
在Model定义文件中
from ext.simple_history.models import HistoricalRecords

class Test(models.Model):
     ...
     history = HistorialRecords()

如此即可

取点没有记录是谁  另会多出许多HistoryalXXX表


方法3,编写自己的代码 利用Django Admin的数据表
#core/history.py
from django.contrib.auth.models import User

from middleware import threadlocals
from django.contrib.contenttypes.models import ContentType
from django.contrib.admin.models import ADDITION
from django.contrib.admin.models import CHANGE
from django.contrib.admin.models import LogEntry
from django.db import models
from django.contrib.admin.models import DELETION
from django.db.models import signals
from django.db.models.base import ModelBase
import datetime

def prepare_fields(instance):
    output = {}
    class_fields = instance.__class__._meta.fields
    instance._history_fields = {}
    all = dict([(f.name, f) for f in class_fields])
    for field_name in instance._history['fields']:
        modelfield = all[field_name]
        value = getattr(instance, modelfield.attname)
        if value is None: value = ''
        output[field_name] = unicode(value)
    return output

def add_signals(cls):
    def post_delete(instance, **_kwargs):
        if instance._history.get('model', False):
            instance._create_log_entry(DELETION)

    def pre_save(instance, **_kwargs):
        if instance._history.get('fields', []):
            if instance.pk is None:
                instance._history_fields = {}
                for field_name in instance._history['fields']:
                    instance._history_fields[field_name] = ''
            else:
                try:
                    db_instance = instance.__class__.objects.get(pk=instance.pk)
                except instance.__class__.DoesNotExist:
                    db_instance = instance
                instance._history_fields = prepare_fields(db_instance)
        if instance._history.get('model', False):
            if instance.pk == None:
                instance._history_action = ADDITION
            else:
                instance._history_action = CHANGE
   
    def post_save(instance, **_kwargs):
        if instance._history.get('fields', []):
            pre_fields = instance._history_fields
            post_fields = prepare_fields(instance)
            for name, after in post_fields.iteritems():
                #print 'looking if', name, 'changed...'
                before = pre_fields[name]
                if before != after:
                    # field has been changed
                    #print 'changed', name, 'from', before, 'to', after
                    instance._create_field_log_entry(name, after)
            #print 'checking done.'
           
        if instance._history.get('model', False):
            instance._create_log_entry(instance._history_action)

    signals.pre_save.connect(pre_save, sender=cls, weak=False)
    signals.post_save.connect(post_save, sender=cls, weak=False)
    signals.post_delete.connect(post_delete, sender=cls, weak=False)

class ModelWithHistoryBase(ModelBase):
    def __new__(cls, name, bases, attrs):
        Model = ModelBase.__new__(cls, name, bases, attrs)
        history = getattr(Model, 'History', None)
        if history:
            history = history.__dict__
            if not 'model' in history:
                history['model'] = False
            if not 'fields' in history:
                history['fields'] = []
        else:
            #raise "Please add History subclass to your model"
            history = {
                'model': False,
                'fields': []
            }
        Model._history = history
        add_signals(Model)
        return Model

class ModelWithHistory(models.Model):
    __metaclass__ = ModelWithHistoryBase
    class Meta:
        abstract = True
       
    def _create_log_entry(self, action):
        if threadlocals.get_current_user().is_anonymous():
            user = User.objects.get(pk=0)
        else:
            user = threadlocals.get_current_user()
        history = LogEntry(user=user, object_id = self.pk, action_flag = action,
                            content_type = ContentType.objects.get_for_model(self))
        try:
            history.object_repr = repr(self)
        except Exception:
            history.object_repr = "(unknown)"
        history.save()

    def _create_field_log_entry(self, name, value):
        if threadlocals.get_current_user().is_anonymous():
            user = User.objects.get(pk=0)
        else:
            user = threadlocals.get_current_user()
        from core.models import AttributeLogEntry
        history = AttributeLogEntry(user=user, object_id = self.pk, field_name=name, field_value = value,
                            content_type = ContentType.objects.get_for_model(self))
        try:
            history.object_repr = repr(self)
        except Exception:
            history.object_repr = "(unknown)"
        history.save()

    def get_history(self):
        content_type = ContentType.objects.get_for_model(self)
        return LogEntry.objects.filter(object_id=self.pk, content_type=content_type)

    def has_history(self):
        return bool(self.__class__._history.get('model', False))
       
    def last_edited_at(self):
        history = list(self.get_history()[:1])
        if not history:
            return datetime.datetime(2000, 1, 1, 0, 0, 0)
        else:
            return history[0].action_time
       
    def last_edited_by(self):
        history = list(self.get_history()[:1])
        if not history:
            return User.objects.get(pk=1)
        else:
            return history[0].user

#core/models.py
from django.db import models
from django.contrib.auth.models import User
from django.contrib.contenttypes.models import ContentType
from django.utils.safestring import mark_safe
from django.contrib.admin.util import quote
from django.utils.encoding import smart_unicode
from django.utils.translation import ugettext_lazy as _
from django.utils.datetime_safe import strftime
import datetime

#almost dupe of LogEntry model
class AttributeLogEntry(models.Model):
    class Meta:
        verbose_name = _('attribute log entry')
        verbose_name_plural = _('attribute log entries')
        db_table = 'django_attribute_log'
        ordering = ('-action_time',)

    action_time = models.DateTimeField(_('action time'), auto_now=True)
    user = models.ForeignKey(User)
    content_type = models.ForeignKey(ContentType, blank=True, null=True)
    object_id = models.IntegerField(_('object id'), blank=True, null=True)
    field_name = models.CharField(_('field name'), max_length=200, blank=True, null=True)
    field_value = models.TextField(_('field value'), null=True, blank=True)
   
    def __repr__(self):
        return smart_unicode(self.action_time)

    @staticmethod
    def get_history(obj, field):
        content_type = ContentType.objects.get_for_model(obj)
        return AttributeLogEntry.objects.filter(object_id=obj.pk, field_name=field, content_type=content_type)

    def get_edited_object(self):
        "Returns the edited object represented by this log entry"
        return self.content_type.get_object_for_this_type(pk=self.object_id)

    def get_admin_url(self):
        """
        Returns the admin URL to edit the object represented by this log entry.
        This is relative to the Django admin index page.
        """
        return mark_safe(u"%s/%s/%s/" % (self.content_type.app_label, self.content_type.model, quote(self.object_id)))

    @staticmethod
    def last_edited_at(obj, field):
        history = list(AttributeLogEntry.get_history(obj, field)[:1])
        if not history:
            return None
        else:
            return strftime(history[0].action_time, "%Y-%m-%d %H:%M")
       
    @staticmethod
    def last_edited_by(obj, field):
        history = list(AttributeLogEntry.get_history(obj, field)[:1])
        if not history:
            return None
        else:
            return history[0].user


使用方法

class MyModel(ModelWithHistory):
    class History:
        model = True # save model changes into admin's LogEntry table
        fields = ('f1', 'f2') # save these fields history to AttributeLogEntry table
    f1 = CharField(max_length=100)
    f2 = IntegerField()

总结,

 比较后,你会发现方法二和方法三是用了类似的思路即自动记录,并讲结果记录在Database中。但是显然方法二的代码工作量更少,与本身系统的耦合度非常的低,是推荐方法。但是缺陷不能告诉我们是谁的动作

 

2011.08.28 15:43修改

 
2011年07月18日 21:06
男人和女人的大脑构造真的不一样,这一点从广告的关注重点都可以看出,不信的话请往下看这份报告:
这是H&M 的网页,虽然男人和女人都很注重模特儿的脸,但是男人明显比较不注意品牌及文字讯息(越红表示越注意)
下图显示男人第一眼先看脸,女人第一眼先看胸(是在偷偷和自己比较吗?)
和女人相比,男人目光停留在模特儿脸上的时间长了40%,腿上的时间却短了20% (结果是女生更爱看美腿),身体部分则是差不多
第二个实验是Reebok 的球鞋广告,不是我在说,男人几乎完全没有注意到产品嘛
结果男人看脸的时间再次比女人长了40%,看臀部的时间更是多了50%,但就是不怎么看鞋子(时间短36% )
最后这个SAAB 汽车广告没有美女,但也再次证明男人真的不是那么关心文字讯息
天生爱车的男人,看车的时间也比女人多了85%,但是看品牌logo的时间短了50%

不知道要做什么结论,所以这个研究是告诉我们,男人是视觉的动物,而且非常在意女生的脸正不正吗XD

(消息来源:Business Insider

 
2011年07月18日 21:00

名片我们都知道,有创意的名片我们也看过很多,关于QR码应 该也有人了解过,但是如果把他们结合在一起你是否看过。这样的创意是对传统名片的一种挑战!QR码现在也在很多地方被人们不变运用,因为每一个二维码都可 以传递一些信息。现在的智能手机和各种搭载摄像头都可以扫描出这样二维码的搭载的信息,所以你可以被快速的添加到联系人中,甚至可以引导他们去指定的网 站,更加的快捷方便。下面是30个这样的创意QR码名片设计。如果你有兴趣就赶快来设计一款属于自己的QR码名片吧!
谢尔比Montross QR码凸版

此卡是一个QR码凸版印刷。它完全符合经典的造型和设计。

茄科实验室

我们很喜欢这个原卡,因为它采用的QR码公司的标志。

万达数码

卡的背面白色,灰色的背景下QR码匹配的标识的配色方案看起来很棒引导。

Reblis

这里的QR码是艺术本身。很简单,但非常艺术。

大发媒体

此卡是超厚,提供了优质的外观和触摸的棉花。令人惊叹。

冲孔名片

我们很喜欢水瓶座俱乐部的这些卡,每张卡有meCard QR码进行扫描,并直接上传到一个电话地址簿的人准备信息。

培培于卡

我们爱于培培并不仅仅是QR码本身,但内置和箱纸板立场!创意和乐趣。



Fridgehead

切出QR码,它仍然扫描… …!

汤尼尔电影

我们真的很喜欢旁边的代码,在此卡上的简单消息。卡圆边还匹配的QR码在中心的圆边。

Digibrand

Beauftiful卡。QR码坐在很好地切出标志。此卡上详细的重视实在是鼓舞人心的。

索伦Ragsdale说

这些卡是真的很干净,没有颜色的简单。然而,他们脱颖而出!

第23和第5

想过没有。红色QR码匹配完美的第23和5ths标志。

德鲁Hornebin

德鲁包括这种设计上的QR码,表明了一个真正的创意优势。

Kayma

多科敢于使用QR码,将用户定向到自己的位置上。

凯西普顿

我们真的很喜欢这些卡上老skool设计。

赤脚媒体

赤脚媒体自豪地使用QR码作为其大胆的设计的一部分。

猴西蒙

猴子西蒙让你想扫描它知道它是什么… …!

斯蒂芬妮Obodda

这些极简卡是一种美的真实的东西。再次QR码是这块设计中心,并以惊人的效果。

Tatadbb

这些卡很简单,但QR码一起极其鲜艳的色彩组​​合真的画的眼睛。

B型设计

这些QR码卡的设计。看起来很棒。

Metaform

马克Stokoe的设计作品完美与后面的代码。如果你仔细看,你也可以看到非常QR码中心的“M”标志的。

社会Bendodson

这些卡酷塞尔达只是因为他们是…

灵魂视觉

这些卡放在旁边的代码到印刷的详细联系方式。在线和离线pefectly照顾!

NightOwl工艺品

这些名片是真的很可爱。QR码旁边的文字鼓励你拍照和访问他们的网站。

耿高

明亮鲜艳的色彩和QR码让你想挑一个…

Lanec技术

这些圆边Lanec科技名片,包括为每一位员工的联系信息的代码。

马克希特利

马克用了很多这些名片上的QR码的空间,但是,它macthes的设计和字体,完全有很大的影响。

大胆馆员

这些可能是我们最喜爱的卡(不只是因为它们是MOO卡),他们有这么多的个性,你已经注意到了这一点。

 
2011年07月16日 20:20

True Basic

Quick Basic

Visual Basic

RealBasic (非MS系)

Basic.Net

Small Basic

 

估计一般人陌生的是RealBasic 和 Small Basic。 前者是第三方开发的Basic 和一般我们认识的MS Basic系最大区别是 跨平台 事件驱动的设计不同;

Small Basic还是来自MS,似乎设计目的是针对少儿,简单易用,扩展性强,风格类似早年的Logo语言,可以运算,可以绘画,可以开发智能小软件,适合应用在小学中学的编程教学中。(VB.Net适用于比较专业的编程工作人员)

 

 
   
 
 
文章存档
 
     
 
最新文章评论
  

很及时,谢谢!
 

回复leader20:没有
 

这个跟django版本有关系吗?
 

装了n回,才找到这个
 

你爱的我也爱
   
帮助中心 | 空间客服 | 投诉中心 | 空间协议
©2012 Baidu