【问题标题】:Django modelform with extra field, permissions per object as manytomanyfield - am I doing it right?带有额外字段的 Django modelform,每个对象的权限与 manytomanyfield 一样 - 我做得对吗?
【发布时间】:2014-02-16 13:39:46
【问题描述】:

不确定是否应该将其拆分为单独的帖子,我基本上必须将整个代码复制粘贴到每个问题中。我希望这很好。

  1. 我的应用中有频道。每个用户可以对每个频道具有不同的访问级别。我需要能够查询用户可以阅读的每个频道的条目。我已经实现为ManyToManyField,有没有更好的解决方案?

  2. 在我的权限模型中,我有 ForeignKey(User, blank=True, null=True)unique_together = ("channel", "user")。我使用具有空用户字段的权限对象来存储未指定用户的默认访问级别。这会给我带来麻烦吗? (null!=null 在数据库级别)

  3. 我想在 ChannelCreateForm 中设置默认访问级别,因此我添加了额外的字段并覆盖了相关视图的 form_valid 方法。有没有更合适的方法来做到这一点?

  4. 我在这里有点即兴发挥。请指出您在我的代码中发现的任何丑陋之处。这里是:

    class Channel(models.Model):    
        name = models.CharField(max_length=30, unique=True)
        title = models.CharField(max_length=70, blank=True, null=True)
        description = models.TextField(blank=True, null=True)    
        owner = models.ForeignKey(User)
        permission = models.ManyToManyField(User, through='ChannelPermission', related_name="permission")            
    
    
    class ChannelPermission(models.Model):
        PERM_CHOICES = (
                (0, 'none'),
                (1, 'read'),
                (2, 'post'),                                
                (3, 'edit'),
                (4, 'lock'),
                (5, 'manage'),
            )
        channel = models.ForeignKey(Channel)
        user = models.ForeignKey(User, blank=True, null=True)
        access = models.IntegerField( choices=PERM_CHOICES, default=0) 
    
        class Meta:
            unique_together = ("channel", "user")
    
    
    class ChannelCreateForm(forms.ModelForm):
        access = forms.ChoiceField(label = 'Default access', 
                                   choices = (
                                       (0, 'none'),
                                       (1, 'read'),
                                       (2, 'post'),                                
                                       (3, 'edit'),                                  
                                   ) 
        )
    
        class Meta:
            model = Channel
            fields = ['name', 'title', 'access', 'description']
    
    
    class ChannelCreate(CreateView):
        form_class = ChannelCreateForm
        template_name = 'index_form.html' 
    
        def form_valid(self, form):
            obj = form.save(commit=False)
            obj.owner = self.request.user
            obj.save()
            perm = ChannelPermission(user=None, channel=obj, access=form.cleaned_data['access'])
            perm.save()
            return HttpResponseRedirect(reverse('some_name'))
    

【问题讨论】:

    标签: python django permissions many-to-many


    【解决方案1】:
    1. 是的,我也会这样做。
    2. 我可能会将 0、1、2 等键更改为短字符串,以确保 0 永远不会造成任何麻烦。此外,最好在数据库中有有意义的记录,而不是 0、1、2 等。default='none' 那样看起来会更好。除此之外,它听起来不错。
    3. 可能更好的解决方案是不在视图中显示。我会在Channel 模型的save 方法中创建ChannelPermission。另外,最好的办法是将默认 ChannelPermission 创建的逻辑移到模型管理器中。
    4. 怎么样

      class Channel(models.Model):
          name = models.CharField(max_length=30, unique=True)
          title = models.CharField(max_length=70, blank=True, null=True)
          description = models.TextField(blank=True, null=True)
          owner = models.ForeignKey(User)
          permission = models.ManyToManyField(User, through='ChannelPermission', related_name="permission")
      
      
      class ChannelPermission(models.Model):
          PERM_CHOICES = (
                  ('none', 'None'),
                  ('read', 'Read Only'),
                  ('post', 'Post'),
                  ('edit', 'Edit'),
                  ('lock', 'Lock'),
                  ('manage', 'Manage'),
              )
          channel = models.ForeignKey(Channel)
          user = models.ForeignKey(User, blank=True, null=True)
          access = models.IntegerField(choices=PERM_CHOICES, default='none')
      
          class Meta:
              unique_together = ("channel", "user")
      
      
      class ChannelCreateForm(forms.ModelForm):
          access = forms.ChoiceField(label = 'Default access',
                                     choices = (
                                         ('none', 'None'),
                                         ('read', 'Read Only'),
                                         ('post', 'Post'),
                                         ('edit', 'Edit'),
      
                                     )
          )
      
          class Meta:
              model = Channel
              fields = ['name', 'title', 'access', 'description']
      
          def save(self, commit=True):
              instance = super(ChannelCreateForm, self).save(commit)
              perm = ChannelPermission(user=None, channel=self.instance, access=self.cleaned_data['access'])
              perm.save()
              return instance
      
      
      class ChannelCreate(CreateView):
          form_class = ChannelCreateForm
          template_name = 'index_form.html'
      
          def form_valid(self, form):
              self.object = form.save(commit=False)
              self.object.owner = self.request.user
              self.object.save()
              return super(ModelFormMixin, self).form_valid(form)
      

    【讨论】:

    • 2.我最担心的是 unique_together “不工作”与空值。 3. 你说的是模型,但你的代码说的是形式。 ;] 是的,将它放在表单代码中更有意义。谢谢。
    • 在这种情况下,您可能应该从 ChannelPermission 中为用户删除 null=True, blank=True 并在 Channel 模型中创建另一个名为 default_permission 的字段
    猜你喜欢
    • 2018-07-13
    • 1970-01-01
    • 2013-06-05
    • 2011-01-14
    • 2015-12-16
    • 2014-06-21
    • 1970-01-01
    • 2016-10-18
    • 2015-12-14
    相关资源
    最近更新 更多