【问题标题】:Add functionality to Django FlatPages without changing the original Django App在不更改原始 Django App 的情况下向 Django FlatPages 添加功能
【发布时间】:2010-11-04 12:33:12
【问题描述】:

我想在 Django FlatPage 数据库模型中添加一个字段,但我真的不知道如何在不编辑原始应用程序的情况下扩展它。

我想做的是将以下字段添加到模型中:


from django.db import models
from django.contrib.flatpages.models import FlatPage as FlatPageOld

class FlatPage(FlatPageOld):
    order = models.PositiveIntegerField(unique=True)

如何将它添加到 FlatPage 模型中?

提前致谢

【问题讨论】:

    标签: django django-models monkeypatching


    【解决方案1】:
    1. 在您的settings.py change the location of the migrations folder 中将django.contrib.flatpages 应用程序移至默认文件夹以外的另一个文件夹。例如:

    settings.py:

    MIGRATION_MODULES = {'flatpages': 'yourproject.flatpages.migrations'}
    

    请记住,您必须在文件夹 yourprojectflatpagesmigrations 中创建空的 __init__.py 文件,以使 Python 将这些字典视为包。 p>

    1. 执行makemigrations 管理命令将初始迁移填充到您的MIGRATION_MODULES 文件夹。它应该类似于default one

    2. 在您的一个应用程序(最好是使用平面页面功能的应用程序)的 apps.py 中添加 oggy 的 class_prepared 解决方案:

    apps.py:

    from django.apps import AppConfig
    from django.db.models.signals import class_prepared
    from django.db import models
    
    
    def alter_flatpages(sender, **kwargs):
        if sender.__module__ == 'django.contrib.flatpages.models' and sender.__name__ == 'FlatPage':
            meta_description = models.CharField(max_length=255, blank=True, null=True)
            meta_description.contribute_to_class(sender, 'meta_description')
    
    
    class TexteConfig(AppConfig):
        name = 'marlene.texte'
    
        def __init__(self, app_name, app_module):
            super().__init__(app_name, app_module)
            class_prepared.connect(alter_flatpages)
    
    1. 通过再次执行 makemigrations 添加另一个迁移。这次您已将CharField meta_description 添加到模型中。 migrate 将更改应用到数据库。

    2. 修改FlatPageAdmin:

    admin.py:

    from django.contrib.flatpages.admin import FlatPageAdmin
    from django.contrib.flatpages.models import FlatPage
    
    class MarleneFlatPageAdmin(FlatPageAdmin):
        fieldsets = (
            (None, {'fields': ('url', 'title', 'content', 'meta_description', 'sites')}),
            (_('Advanced options'), {
                'classes': ('collapse',),
                'fields': ('registration_required', 'template_name'),
            }),
        )
    
    
    admin.site.unregister(FlatPage)
    admin.site.register(FlatPage, MarleneFlatPageAdmin)
    

    此解决方案的最大缺点是,如果 Django 将来向平面应用程序添加新的迁移,您将负责管理它们。我建议大家不要使用平面应用程序,无论它是否适合您当前的情况。

    【讨论】:

      【解决方案2】:

      您的方法很好 - 您只是看不到结果,因为旧的平面模型已在管理员中注册,而新的模型没有。以下是您可以在新应用的 admin.py 中执行的操作(使用的命名比上面的更清晰):

      from django.contrib import admin
      from django.contrib.flatpages.admin import FlatPageAdmin
      from django.contrib.flatpages.forms import FlatpageForm
      from django.contrib.flatpages.models import FlatPage
      
      from models import ExtendedFlatPage
      
      class ExtendedFlatPageForm(FlatpageForm):
          class Meta:
              model = ExtendedFlatPage
      
      class ExtendedFlatPageAdmin(FlatPageAdmin):
          form = ExtendedFlatPageForm
          fieldsets = (
              (None, {'fields': ('url', 'title', 'content', 'sites', 'order')}),
          )     
      
      admin.site.unregister(FlatPage)
      admin.site.register(ExtendedFlatPage, ExtendedFlatPageAdmin)
      

      显然这里发生了一些事情,但最重要的是,FlatPage 模型正在取消注册,而 ExtendedFlatPage 模型正在其位置上注册。

      【讨论】:

      • 非常感谢!我想这就是我想要的。
      • 请记住,这种方法不适用于默认的 FlatpageFallbackMiddleware - 它会返回原始 Flatpage 模型的实例,而不是您的扩展。因此,您必须编写自己的版本,或使用自己的 URL/视图。此外,您现在有两个表,实际上只需要一个,这导致查询效率较低。总而言之,我建议您从头开始编写您自己的平面应用程序,或者使用 class_prepared 方法对字段进行monkeypatch,而不是使用继承。
      【解决方案3】:

      您帖子中的方法不起作用,因为...?

      如果出于某种原因你真的需要摆弄内置的 FlatPage 类并动态编辑它,你可以挂钩到 class_prepared 信号:

      http://docs.djangoproject.com/en/dev/ref/signals/#class-prepared

      编辑

      下面是使用 class_prepared 的方法:

      from django.db.models.signals import class_prepared
      from django.db import models
      
      def alter_flatpages(sender, **kwargs):
          if sender.__module__ == 'django.contrib.flatpages.models' and sender.__name__ == 'FlatPage':
              order = models.IntegerField()
              order.contribute_to_class(sender, 'order')
      
      class_prepared.connect(alter_flatpages)
      

      把它放在和你的settings.py相同的目录下,比如说'signals.py',然后将'signals'添加到顶部(这很重要,以确保信号处理程序INSTALLED_APPS 列表的及时安装)。

      但是,这仍然不会在 Admin 中显示该字段,因为 FlatPages 有一个自定义 ModelAdmin 类,它明确列出了这些字段。因此,在它在 flatpages 应用程序中注册后,您需要在某处取消注册 (admin.site.unregister) 并注册您自己的 ModelAdmin。

      【讨论】:

      • 该字段未显示在管理员中?我不明白为什么。这就是问题
      • 好吧,它没有理由显示在内置 Django 类的管理员中 - 你还没有修改它!如果您在单独的应用程序中创建自己的 FlatPage,则需要向管理员注册您的新课程。如果您不想这样做,可以采用 class_prepared 方式,但这需要您对 Python 有一定的了解。
      • 嗯,好吧,我想我可以对原始的 FlatPage 类进行猴子补丁,因此它实际上会显示在管理员中,而无需创建新的应用程序(和模型)。可以举个class_prepared方式的例子吗?
      • 我添加了一个应该可以解决这个问题的答案
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-10-07
      • 2012-01-27
      • 1970-01-01
      • 2013-07-15
      相关资源
      最近更新 更多