2012-08-21 2 views
0

에서 사용하는 그 같은 일부 모델이 있습니다 장고 : 모델에 현재 사용자 설정하기 InlineModelAdmin

class BaseModel(models.Model): 
    created_by = models.ForeignKey(User, related_name="%(app_label)s_%(class)s_created") 
    created_date = models.DateTimeField(_('Added date'), auto_now_add=True) 
    last_updated_by = models.ForeignKey(User, related_name="%(app_label)s_%(class)s_updated") 
    last_updated_date = models.DateTimeField(_('Last update date'), auto_now=True) 

    class Meta: 
     abstract = True 

class Image(BaseModel): 
    content_type = models.ForeignKey(ContentType) 
    object_id = models.PositiveIntegerField() 
    content_object = generic.GenericForeignKey('content_type', 'object_id') 

    name = models.CharField(_('Item name'), max_length=200, blank=True) 
    image = models.ImageField(_('Image'), upload_to=get_upload_path) 

    def save(self, *args, **kwargs): 
     if self.image and not GALLERY_ORIGINAL_IMAGESIZE == 0: 
      width, height = GALLERY_ORIGINAL_IMAGESIZE.split('x') 
      super(Image, self).save(*args, **kwargs) 

      filename = os.path.join(settings.MEDIA_ROOT, self.image.name) 
      image = PILImage.open(filename) 

      image.thumbnail((int(width), int(height)), PILImage.ANTIALIAS) 
      image.save(filename) 

     super(Image, self).save(*args, **kwargs) 

class Album(BaseModel): 
    name = models.CharField(_('Album Name'), max_length=200) 
    description = models.TextField(_('Description'), blank=True) 
    slug = models.SlugField(_('Slug'), max_length=200, blank=True) 
    status = models.SmallIntegerField(_('Status'),choices=ALBUM_STATUSES) 

    images = generic.GenericRelation(Image) 

내가 저장하고 업데이트 로그를 추적하기 위해 내 모든 모델 BASEMODEL 추상 모델을 사용합니다. ModelAdmin 클래스를 사용하여 자동으로 사용자 필드를 설정할 수 있습니다.

class BaseAdmin(admin.ModelAdmin): 
    def save_model(self, request, obj, form, change): 
     if not change: 
      obj.created_by = request.user 

     obj.last_updated_by = request.user 
     obj.save() 


class AlbumAdmin(BaseAdmin): 
    prepopulated_fields = {"slug": ("name",)} 
    list_display = ('id','name') 
    ordering = ('id',) 

그게 효과가 있습니다. 모든 BaseAdmin 필드는 자동으로 채워집니다. 하지만 인라인으로 앨범에 이미지를 추가하고 싶습니다. 그래서, 난 그렇게 내 admin.py을 변경

from django.contrib.contenttypes import generic 

class ImageInline(generic.GenericTabularInline): 
    model = Image 
    extra = 1 

class AlbumAdmin(BaseAdmin): 
    prepopulated_fields = {"slug": ("name",)} 
    list_display = ('id','name') 
    ordering = ('id',) 

    inlines = [ImageInline,] 

내가 페이지를 저장할 때 오류가 발생합니다 : gallery_image.created_by_id may not be NULL를 저장 방법 이미지 모델의 첫 super(Image, self).save(*args, **kwargs) 행에. GenericTabularInline 클래스에는 재정의 할 save_model 메서드가 없기 때문입니다.

InlineModelAdmin 클래스에서 현재 사용자를 저장하고 메서드를 재정의하려면 어떻게해야합니까?

내가 또 다른 질문에 대한 해결책 발견
+0

는 GenericTabularInline는 InlineModelAdmin HTTP에서 상속 : // 문서. nullpobug.com/django/trunk/django.contrib.contenttypes.generic.GenericTabularInline-class.html InlineModelAdmin에서 사용되는 양식을 지정할 수 있습니다. https://docs.djangoproject.com/en/dev/ref/ contrib/admin/# django.contrib.admin.InlineModelAdmin.form 아마 기본값으로 사용하는 ModelForm을 무시하고 초기 값을 추가 할 수 있습니까? http://stackoverflow.com/questions/2988548/overriding-initial-value-in-modelform –

답변

1

: 그래서 https://stackoverflow.com/a/3569038/198062

을, 나는 그런 내 BaseAdmin 모델 클래스를 변경하고, 마치 마법처럼 일 :

from models import BaseModel 

class BaseAdmin(admin.ModelAdmin): 
    def save_model(self, request, obj, form, change): 
     if not change: 
      obj.created_by = request.user 

     obj.last_updated_by = request.user 
     obj.save() 

    def save_formset(self, request, form, formset, change): 
     instances = formset.save(commit=False) 

     for instance in instances: 
      if isinstance(instance, BaseModel): #Check if it is the correct type of inline 
       if not instance.created_by_id: 
        instance.created_by = request.user 

       instance.last_updated_by = request.user    
       instance.save() 

것은 당신이 같은 확장해야한다는 이 솔루션을 사용하는 인라인이 포함 된 ModelAdmin의 추상 클래스입니다. 또는 해당 save_formset 메소드를 인라인이 포함 된 ModelAdmin에 추가 할 수 있습니다.

1

어디서/어떻게 조작되었는지에 관계없이 모든 모델에 사용자를 설정하기를 원했습니다. 그것을 알아 내기 위해 나를 영원히했다, 그러나 여기 미들웨어를 사용하는 모델을 설정하는 방법은 다음과 같습니다

mindlace의 대답에 추가
"""Add user created_by and modified_by foreign key refs to any model automatically. 
    Almost entirely taken from https://github.com/Atomidata/django-audit-log/blob/master/audit_log/middleware.py""" 
from django.db.models import signals 
from django.utils.functional import curry 

class WhodidMiddleware(object): 
    def process_request(self, request): 
     if not request.method in ('GET', 'HEAD', 'OPTIONS', 'TRACE'): 
      if hasattr(request, 'user') and request.user.is_authenticated(): 
       user = request.user 
      else: 
       user = None 

      mark_whodid = curry(self.mark_whodid, user) 
      signals.pre_save.connect(mark_whodid, dispatch_uid = (self.__class__, request,), weak = False) 

    def process_response(self, request, response): 
     signals.pre_save.disconnect(dispatch_uid = (self.__class__, request,)) 
     return response 

    def mark_whodid(self, user, sender, instance, **kwargs): 
     if instance.has_attr('created_by') and not instance.created_by: 
      instance.created_by = user 
     if instance.has_attr('modified_by'): 
      instance.modified_by = user 
+0

나는 그것을 시도하고 나는 그것을 아주 좋아했다. 고맙습니다. –

+0

여러 요청을 병렬로 처리하면 서로 다른 사용자와 함께'mark_whodid'가 두 번 호출되는 경쟁 조건이 발생할 수 있습니다. 신호가 현재 스레드에서 다시 호출된다고 가정하면이 경쟁 조건은 스레드 로컬에 요청을 저장하고이를 리스너 ('mark_whodid')에게 보내어 제거 할 수 있습니다. –

1

; created_by 필드에 null=True이 있으면 not instance.created_by에 오류가 발생합니다. 이 문제를 방지하려면 instance.created_by_id is None을 사용합니다.

은 (차라리 대답에 주석으로이 게시 싶지만 허용하지 않습니다 내 현재의 명성을 ...)이 문서에서

관련 문제