【问题标题】:How do you specify a default for a Django ForeignKey Model or AdminModel field?如何为 Django ForeignKey Model 或 AdminModel 字段指定默认值?
【发布时间】:2010-10-30 14:12:53
【问题描述】:

如何在 django 模型或 AdminModel 中的 ForeignKey 字段上设置默认值?

类似的东西(但当然这不起作用)......

created_by = models.ForeignKey(User, default=request.user)

我知道我可以在视图中“欺骗”它,但就 AdminModel 而言,这似乎是不可能的。

【问题讨论】:

  • Django 在 2009 年有 AdminModel 吗?我不认为它会today。你的意思是ModelAdmin

标签: python django-models django-admin


【解决方案1】:
class Foo(models.Model):
    a = models.CharField(max_length=42)

class Bar(models.Model):
    b = models.CharField(max_length=42)
    a = models.ForeignKey(Foo, default=lambda: Foo.objects.get(id=1) )

【讨论】:

  • 你和这篇文章是同一个人吗?如果没有,请考虑添加链接。 djangodays.com/2009/05/11/…
  • 在模型中使用符号名称作为默认值是很常见的用法。我不记得该网站,但将 sn-p 更改为更短的模式。
  • 从 Django 1.7 开始,如果您使用 Django 的迁移,此解决方案将不再有效,因为 Django 无法序列化 lambda。 docs.djangoproject.com/en/1.7/topics/migrations/…
  • @EricRessler 如何让它在 Django 1.10 中工作?
  • @MadPhysicist 这种方法适用于更现代的 Django 版本:stackoverflow.com/a/7081062/996114
【解决方案2】:

对于 django 1.7 或更高版本,

只需创建一个 ForeignKey 对象并保存它。 “default”值可以是默认链接的对象的id。

例如,

created_by = models.ForeignKey(User, default=1)

【讨论】:

    【解决方案3】:

    这是一个适用于 Django 1.7 的解决方案。 与其在字段定义中提供默认值,不如将其设置为可空,但覆盖“保存”函数以在第一次填充它(当它为空时):

    class Foo(models.Model):
        a = models.CharField(max_length=42)
    
    class Bar(models.Model):
        b = models.CharField(max_length=42)
        a = models.ForeignKey(Foo, null=True)
    
        def save(self, *args, **kwargs):
            if self.a is None:  # Set default reference
                self.a = Foo.objects.get(id=1)
            super(Bar, self).save(*args, **kwargs)
    

    【讨论】:

    • 您真的需要使该字段可以为空吗?我认为,该对象尚未保存,即。它还没有 id,除非你在 super(..save.. .
    • @MilanoSlesarik 你可能是对的。我首先把它放在那里的原因是因为它是我添加到现有模型(具有现有记录行)中的一个新字段,所以我不得不允许它为空。
    • @o_c 不是一个好主意,因为 save(..) 不会从批量更新 QuerySets 中调用。除非您显式遍历每个返回的项目并调用 save,否则会破坏使用批处理的目的首先更新(开发人员往往会忘记)。
    【解决方案4】:

    我的做法与@o_c 类似,但我宁愿使用get_or_create 而不是简单的pk

    class UserSettings(models.Model):
        name = models.CharField(max_length=64, unique=True)
        # ... some other fields 
    
        @staticmethod
        def get_default_user_settings():
            user_settings, created = UserSettings.objects.get_or_create(
                name = 'Default settings'
            )
            return user_settings
    
    class SiteUser(...):
        # ... some other fields
    
        user_settings = models.ForeignKey(
            to=UserSettings, 
            on_delete=models.SET_NULL, 
            null=True
        )
    
        def save(self, *args, **kwargs):
            if self.user_settings is None:
                self.user_settings = UserSettings.get_default_params()
            super(SiteUser, self).save(*args, **kwargs)
    

    【讨论】:

    • 这个答案应该更高,因为它简单而聪明。
    【解决方案5】:

    如果你使用的是开发版的Django,你可以在你的AdminModel上实现formfield_for_foreignkey()方法来设置一个默认值。

    【讨论】:

      【解决方案6】:

      对于我来说,对于 Django 1.7 它的工作,只是 pk:

      category = models.ForeignKey(Category, editable=False, default=1)

      但请记住,迁移看起来像

      migrations.AlterField(
                  model_name='item',
                  name='category',
                  field=models.ForeignKey(default=1, editable=False, to='item.Category'),
                  preserve_default=True,
              ),
      

      所以,我不认为它与动态用户 pk 一起工作。

      【讨论】:

        【解决方案7】:
        def get_user_default_id():
            return 1
        
        created_by = models.ForeignKey(User, default=get_user_default_id)
        

        【讨论】:

        • 也添加一些描述。
        【解决方案8】:

        这是对o_c 的答案的轻微修改。它应该可以为您节省一击数据库。请注意,在保存方法中,我使用 self.a_id = 1 而不是 self.a = Foo.objects.get(id=1)。不用查询 Foo 也有同样的效果。

        class Foo(models.Model):
            a = models.CharField(max_length=42)
        
        class Bar(models.Model):
            b = models.CharField(max_length=42)
            a = models.ForeignKey(Foo, null=True)
        
            def save(self, *args, **kwargs):
                if self.a is None:  # Set default reference
                    self.a_id = 1
                super(Bar, self).save(*args, **kwargs)
        

        【讨论】:

          【解决方案9】:

          对于 Django >= 1.7,您可以通过两种不同的方式设置 ForeignKey 字段的默认值:

          1) 直接作为整数

          DEFAULT_CREATED_BY_USER = 42
          
          class MyModel(Model):
              created_by = models.ForeignKey(User, default=DEFAULT_CREATED_BY_USER)
          

          2) 作为返回整数的非 lambda 可调用对象

          您还可以使用可解析为完整模块路径的可调用对象。这意味着 lambdas 不起作用。但这会:

          def default_created_by_user():
              return 42
          
          class MyModel(Model):
              created_by = models.ForeignKey(User, default=default_created_by_user)
          

          参考资料:

          【讨论】:

            【解决方案10】:

            使用偏函数代替 lambda 函数。 Lambda 函数不是序列化,因此会在迁移中出错。

            class Foo(models.Model):
                a = models.CharField(max_length=42)
            
            class Bar(models.Model):
                b = models.CharField(max_length=42)
                a = models.ForeignKey(Foo, default=partial(Foo.objects.get, id=1 ))
            

            【讨论】:

              【解决方案11】:

              您应该在 settings.py 文件中有与 setting.AUTH_USER_MODEL 相关的设置。

              您可以查看以下文档:

              https://docs.djangoproject.com/en/1.10/topics/auth/customizing/#substituting-a-custom-user-model

              【讨论】:

                【解决方案12】:

                您可以覆盖模型管理员的get_form 方法。

                admin.py

                class YourModelAdmin(admin.ModelAdmin):
                    def get_form(self, request, obj=None, **kwargs):
                        form = super(YourModelAdmin, self).get_form(request, obj, **kwargs)
                        form.base_fields['created_by'].initial = request.user
                    return form
                
                admin.site.register(YourModel, YourModelAdmin)
                

                【讨论】:

                  【解决方案13】:

                  在寻找更好解决方案的所有迭代中,我发现创建一个小函数将大大解决任务的复杂性。因为一些解决方案已经过时或在较新的 Django 版本中不再受支持。

                  def get_request_user():
                      # or any complex query result to set default value in ForeignKey
                      return request.user.id
                  

                  然后您可以将上述函数作为参数传递给 ForeignKey。

                  created_by = models.ForeignKey(User, default=get_request_user)
                  

                  【讨论】:

                  • Unresolved reference "request"。你将如何在这里传递请求? ;)
                  【解决方案14】:
                  class table1(models.Model):
                      id = models.AutoField(primary_key=True)
                      agentname = models.CharField(max_length=20)
                  
                  class table1(models.Model):
                      id = models.AutoField(primary_key=True)
                      lastname = models.CharField(max_length=20)
                      table1 = models.ForeignKey(Property)
                  

                  【讨论】:

                  • 请在代码中添加一些解释,为什么会回答这个问题?
                  猜你喜欢
                  • 1970-01-01
                  • 2015-09-10
                  • 1970-01-01
                  • 2011-05-25
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2015-05-18
                  • 2022-11-12
                  相关资源
                  最近更新 更多