【问题标题】:Resize fields in Django Admin在 Django Admin 中调整字段大小
【发布时间】:2010-10-28 22:51:10
【问题描述】:

Django 在管理员添加或编辑条目时往往会填满水平空间,但在某些情况下,当编辑一个 8 个字符宽的日期字段或一个 CharField 时,确实会浪费空间6 或 8 个字符宽,然后编辑框增加到 15 或 20 个字符。

我如何告诉管理员一个文本框应该有多宽,或者一个 TextField 编辑框的高度?

【问题讨论】:

  • 显然,在这种情况下您忘记了这样做。两年多之后。 =)
  • 项目被抛弃了,我有一段时间没看代码了。下个月我可能会开始一个新项目,所以也许我会再做一次:D

标签: python django django-models django-admin


【解决方案1】:

你应该使用ModelAdmin.formfield_overrides

这很容易 - 在admin.py 中定义:

from django.forms import TextInput, Textarea
from django.db import models

class YourModelAdmin(admin.ModelAdmin):
    formfield_overrides = {
        models.CharField: {'widget': TextInput(attrs={'size':'20'})},
        models.TextField: {'widget': Textarea(attrs={'rows':4, 'cols':40})},
    }

admin.site.register(YourModel, YourModelAdmin)

【讨论】:

  • 这正是我正在寻找的,而无需进行一些荒谬的模板自定义。谢谢!
  • 请注意,如果为 YourModelAdmin 中的相应字段设置了filter_horizontalfilter_vertical,这将不起作用。我花了一些时间来解决这个问题。
  • 表格里有什么不好的吗?我没有找到为所有 Textareas 设置 attrs 属性的方法。
  • 我只使用了models.TextField: {'widget': Textarea(attrs={'rows':4})},但宽度也变小了。
  • 显然很难让它们的尺寸相同。
【解决方案2】:

您可以使用其"attrs" property 在小部件上设置任意 HTML 属性。

您可以在 Django 管理员中使用 formfield_for_dbfield 执行此操作:

class MyModelAdmin(admin.ModelAdmin):
  def formfield_for_dbfield(self, db_field, **kwargs):
    field = super(ContentAdmin, self).formfield_for_dbfield(db_field, **kwargs)
    if db_field.name == 'somefield':
      field.widget.attrs['class'] = 'someclass ' + field.widget.attrs.get('class', '')
    return field

或使用自定义 Widget 子类和 formfield_overrides dictionary:

class DifferentlySizedTextarea(forms.Textarea):
  def __init__(self, *args, **kwargs):
    attrs = kwargs.setdefault('attrs', {})
    attrs.setdefault('cols', 80)
    attrs.setdefault('rows', 5)
    super(DifferentlySizedTextarea, self).__init__(*args, **kwargs)

class MyModelAdmin(admin.ModelAdmin):
  formfield_overrides = { models.TextField: {'widget': DifferentlySizedTextarea}}

【讨论】:

    【解决方案3】:

    更改特定字段的宽度。

    通过ModelAdmin.get_form制作:

    class YourModelAdmin(admin.ModelAdmin):
        def get_form(self, request, obj=None, **kwargs):
            form = super(YourModelAdmin, self).get_form(request, obj, **kwargs)
            form.base_fields['myfield'].widget.attrs['style'] = 'width: 45em;'
            return form
    

    【讨论】:

    • 在我看来这是最好的答案,因为它允许更改单个字段而无需创建新表单。
    【解决方案4】:

    一个快速而肮脏的选择是简单地为有问题的模型提供一个自定义模板。

    如果您创建一个名为 admin/<app label>/<class name>/change_form.html 的模板,那么管理员将使用该模板而不是默认模板。也就是说,如果您在名为 people 的应用程序中有一个名为 Person 的模型,您将创建一个名为 admin/people/person/change_form.html 的模板。

    所有管理模板都有一个 extrahead 块,您可以覆盖以将内容放在 <head> 中,而最后的难题是每个字段的 HTML id 都是 id_<field-name>

    因此,您可以在模板中添加如下内容:

    {% extends "admin/change_form.html" %}
    
    {% block extrahead %}
      {{ block.super }}
      <style type="text/css">
        #id_my_field { width: 100px; }
      </style>
    {% endblock %}
    

    【讨论】:

    • 谢谢!这和 alanjds 的回答对于基于每个字段而不是每个字段类型更改管理界面中的布局非常有帮助。
    【解决方案5】:

    如果您想更改每个字段实例的属性,可以将“attrs”属性直接添加到表单条目中。

    例如:

    class BlogPostForm(forms.ModelForm):
        title = forms.CharField(label='Title:', max_length=128)
        body = forms.CharField(label='Post:', max_length=2000, 
            widget=forms.Textarea(attrs={'rows':'5', 'cols': '5'}))
    
        class Meta:
            model = BlogPost
            fields = ('title', 'body')
    

    “attrs”属性基本上会传递将调整表单字段的 HTML 标记。每个条目都是您要覆盖的属性和要覆盖它的值的元组。只要用逗号分隔每个元组,就可以输入任意数量的属性。

    【讨论】:

    • IMO 是一次只修改单个字段而不是所有 TextInput-widgets 的最佳方法(就像接受的答案一样)
    【解决方案6】:

    我发现最好的方法是这样的:

    class NotificationForm(forms.ModelForm):
        def __init__(self, *args, **kwargs): 
            super(NotificationForm, self).__init__(*args, **kwargs)
            self.fields['content'].widget.attrs['cols'] = 80
            self.fields['content'].widget.attrs['rows'] = 15
            self.fields['title'].widget.attrs['size'] = 50
        class Meta:
            model = Notification
    

    它对于 ModelForm 比使用不同的小部件覆盖字段要好得多,因为它保留了 namehelp_text 属性以及模型字段的默认值,因此您不必将它们复制到您的表单中。

    【讨论】:

      【解决方案7】:

      您始终可以在自定义样式表中设置字段大小,并告诉 Django 将其用于您的 ModelAdmin 类:

      class MyModelAdmin(ModelAdmin):
          class Media:
              css = {"all": ("my_stylesheet.css",)}
      

      【讨论】:

      • 最佳答案!无需摆弄表单字段和属性(以及可能的副作用),只需一个 css 文件即可 - 使用 django 管理表单中现有的 ids/classes - 轻松地仅针对某些字段,甚至所有字段。加油!
      【解决方案8】:

      TextField 也有类似的问题。我正在使用 Django 1.0.2 并想更改关联文本区域中“行”的默认值。此版本中不存在 formfield_overrides。覆盖 formfield_for_dbfield 有效,但我必须为我的每个 ModelAdmin 子类都这样做,否则会导致递归错误。最终,我发现将下面的代码添加到 models.py 中是可行的:

      from django.forms import Textarea
      
      class MyTextField(models.TextField):
      #A more reasonably sized textarea                                                                                                            
          def formfield(self, **kwargs):
               kwargs.update(
                  {"widget": Textarea(attrs={'rows':2, 'cols':80})}
               )
               return super(MyTextField, self).formfield(**kwargs)
      

      然后在定义模型时使用 MyTextField 而不是 TextField。我将它从 this answer 改编为类似的问题。

      【讨论】:

        【解决方案9】:

        Django FAQ中有很好的描述:

        问:如何更改模型中某个字段上小部件的属性?

        答:覆盖 ModelAdmin/StackedInline/TabularInline 类中的 formfield_for_dbfield

        class MyOtherModelInline(admin.StackedInline):
            model = MyOtherModel
            extra = 1
        
            def formfield_for_dbfield(self, db_field, **kwargs):
                # This method will turn all TextFields into giant TextFields
                if isinstance(db_field, models.TextField):
                    return forms.CharField(widget=forms.Textarea(attrs={'cols': 130, 'rows':30, 'class': 'docx'}))
                return super(MyOtherModelInline, self).formfield_for_dbfield(db_field, **kwargs)
        

        【讨论】:

        • 当我使用这种技术时,帮助文本不会出现,如果它是 TabularInline,列标题变为“无”。
        • 这不是一个好方法,因为您正在清除 CharField 中的所有其他设置。例如,默认情况下,它会智能地检测表单字段是否应该是必需的,但是这段代码破坏了它。您应该将小部件设置为您的 super() 调用返回的值。
        【解决方案10】:

        对于 1.6,使用表单我必须在 charfield 内指定 textarea 的属性:

        test1 = forms.CharField(max_length=400, widget=forms.Textarea( attrs={'rows':'2', 'cols': '10'}),  initial='', help_text=helptexts.helptxt['test'])
        

        【讨论】:

          【解决方案11】:

          这是一个简单而灵活的解决方案。使用自定义表单覆盖一些小部件。

          # models.py
          class Elephant(models.Model):
              name = models.CharField(max_length=25)
              age = models.IntegerField()
          
          # forms.py
          class ElephantForm(forms.ModelForm):
          
              class Meta:
                  widgets = {
                      'age': forms.TextInput(attrs={'size': 3}),
                  }
          
          # admin.py
          @admin.register(Elephant)
          class ElephantAdmin(admin.ModelAdmin):
              form = ElephantForm
          

          ElephantForm 中给出的小部件将替换默认小部件。键是字段的字符串表示形式。表单中未指定的字段将使用默认小部件。

          请注意,虽然ageIntegerField,但我们可以使用TextInput 小部件,因为与NumberInput 不同,TextInput 接受size 属性。

          此解决方案描述为in this article

          【讨论】:

            【解决方案12】:

            与 msdin 的答案相同,但使用 TextInput 而不是 TextArea:

            from django.forms import TextInput
            
            class ShortTextField(models.TextField):
                def formfield(self, **kwargs):
                     kwargs.update(
                        {"widget": TextInput(attrs={'size': 10})}
                     )
                     return super(ShortTextField, self).formfield(**kwargs)
            

            【讨论】:

              【解决方案13】:

              如果您正在使用涉及选项/选项/下拉菜单的 ForeignKey 字段,您可以在 Admin 实例中覆盖 formfield_for_foreignkey

              class YourNewAdmin(admin.ModelAdmin):
                  ...
              
                  def formfield_for_foreignkey(self, db_field, request, **kwargs):
                      if db_field.name == 'your_fk_field':
                          """ For your FK field of choice, override the dropdown style """
                          kwargs["widget"] = django.forms.widgets.Select(attrs={
                              'style': 'width: 250px;'
                          })
              
                      return super().formfield_for_foreignkey(db_field, request, **kwargs)
              

              有关此模式herehere 的更多信息。

              【讨论】:

                【解决方案14】:

                还有一个例子:

                class SecenekInline(admin.TabularInline):
                   model = Secenek
                   # classes = ['collapse']
                   def formfield_for_dbfield(self, db_field, **kwargs):
                       field = super(SecenekInline, self).formfield_for_dbfield(db_field, **kwargs)
                       if db_field.name == 'harf':
                           field.widget = TextInput(attrs={'size':2})
                       return field
                   formfield_overrides = {
                       models.TextField: {'widget': Textarea(attrs={'rows':2})},
                   }
                   extra = 2
                

                如果您只想编辑特定的字段大小,可以使用它。

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2015-05-13
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多