Python 如何在django中扩展站点模型?
在django中扩展站点模型的最佳方法是什么?创建一个新模型并对站点进行外键,还是有其他方法允许我对站点模型进行子类化Python 如何在django中扩展站点模型?,python,django,django-models,Python,Django,Django Models,在django中扩展站点模型的最佳方法是什么?创建一个新模型并对站点进行外键,还是有其他方法允许我对站点模型进行子类化 我更喜欢子类化,因为从关系上来说我更舒服,但我担心它对内置管理员的影响。我只是使用了我自己的站点子类,并为它创建了一个自定义管理员 基本上,当您在django中对一个模型进行子类化时,它会创建指向父模型的FK,并允许透明地访问父模型的字段,就像您在pyhon中访问父类属性一样。 内置的管理程序不会受到任何影响,但是你必须登记网站MODAdmin并登记你自己的ModelAdmin
我更喜欢子类化,因为从关系上来说我更舒服,但我担心它对内置管理员的影响。我只是使用了我自己的站点子类,并为它创建了一个自定义管理员 基本上,当您在django中对一个模型进行子类化时,它会创建指向父模型的FK,并允许透明地访问父模型的字段,就像您在pyhon中访问父类属性一样。
内置的管理程序不会受到任何影响,但是你必须登记网站MODAdmin并登记你自己的ModelAdmin。 < P>如果你只想改变对象的行为,但是不添加任何新字段,你应该考虑使用“代理模型”(Django 1.1中的新)。您可以向现有模型添加额外的Python方法,以及更多: 这就是代理模型继承的目的:为原始模型创建代理。您可以创建、删除和更新代理模型的实例,所有数据都将像使用原始(非代理)模型一样保存。不同之处在于,您可以更改代理中的默认模型排序或默认管理器之类的内容,而无需更改原始模型
阅读更多信息。您可以使用另一个模型,如
SiteProfile
,它与Site
有一个OneToOne关系 从Django 2.2开始,对于用户
,仍然没有简单的直接方法来扩展站点
。现在最好的方法是创建新实体并将参数放在那个里。如果你想利用,这是唯一的方法
类站点配置文件(models.Model):
title=models.TextField()
站点=models.OneToOneField(站点,on_delete=models.CASCADE)
您必须为
SiteProfile
创建管理员。然后添加一些带有链接的站点的站点档案
记录。现在,您可以使用site.siteprofile.title
从模型中访问当前站点的任何位置。这个问题已经问了很久了,但我认为(Django 3.1)还没有一个像创建自定义用户模型那样简单的解决方案。在这种情况下,创建一个从django.contrib.auth.models.AbstractUser模型继承的自定义用户模型并将auth_user_模型(在设置中)更改为新创建的自定义用户模型可以解决此问题
但是,对于站点模型,也可以使用下面列出的长解决方案来实现:
解决方案
假设您有一个名为core的应用程序。将该应用程序用于以下所有代码,设置文件除外
创建一个站点配置文件模型,其中站点字段与站点模型具有OneToOne关系。我也改变了它的应用程序标签元,所以它将在网站应用程序的管理下看到
在管理员中注册模型。(在core.admin中)
如果您只想创建一个站点概要文件模型,那么到目前为止我们所做的已经足够好了。但是,您希望在迁移之后立即创建第一个概要文件。因为创建了第一个站点,但没有创建与其相关的第一个概要文件。如果你不想手工创建,你需要第三步
在core.apps.py中编写以下代码:
函数(创建默认站点配置文件)将使用迁移后信号自动创建与迁移后第一个站点相关的第一个配置文件。但是,您需要另一个信号(post_save),即上述代码的最后一行
如果执行此步骤,则SiteProfile模型将与站点模型建立完全连接。创建/更新任何站点对象时,将自动创建/更新SiteProfile对象。该信号通过最后一行从apps.py调用
您想在模板上使用它吗?例如
{{site.name}}
然后你需要第五步和第六步
在settings.py>TEMPLATES>OPTIONS>context\u处理器中添加以下代码
'core.context\u processors.site\u processor'
使用以下代码在core应用程序中创建context_processors.py文件。
需要一个try-catch挡块(捕捉部分)使其更安全。如果从数据库中删除所有站点,则在管理和前端页面上都会出现错误。错误是站点匹配查询不存在。
因此,如果catch块为空,它将创建一个
如果您有第二个站点并且该站点已被删除,则此解决方案可能不是完全合格的。此解决方案仅创建id为1的站点
现在,您可以在模板中使用站点名称、域、元名称、长名称或添加的任何字段
# e.g.
{{ site.name }}
{{ site.profiles.long_name }}
它通常会添加两个DB查询,一个用于File.objects,另一个用于FileProfile.objects。但是,正如文件中提到的,
Django非常聪明,可以在第一次请求时缓存当前站点,并在后续调用时提供缓存数据。
显然,您还可以在添加到已安装的应用程序的文件夹中创建models.py文件,其中包含以下内容:
从django.contrib.sites.models导入站点作为DjangoSite,SiteManager
从django.core.exceptions导入配置不正确
从django.db导入模型
从django.http.request导入拆分域端口
#我们的网站模型
课堂现场(DjangoSite):
settings=models.JSONField(blank=True,default={})
port=models.PositiveIntegerField(null=True)
protocol=models.CharField(默认值='http',最大长度=5)
@财产
def url(自我):
如果self.port:
主机=f'{self.domain}:{self.port}'
其他:
主机=self.domain
返回f'{self.protocol}://{host}/'
#修补django.contrib.sites.models.Site.objects以使用我们的Site类
DjangoSite.objects.model=站点
#optionnal:覆盖get_current以自动创建sit
# in core.apps
...
from django.conf import settings
from django.db.models.signals import post_migrate
def create_default_site_profile(sender, **kwargs):
"""after migrations"""
from django.contrib.sites.models import Site
from core.models import SiteProfile
site = Site.objects.get(id=getattr(settings, 'SITE_ID', 1))
if not SiteProfile.objects.exists():
SiteProfile.objects.create(site=site)
class CoreConfig(AppConfig):
name = 'core'
def ready(self):
post_migrate.connect(create_default_site_profile, sender=self)
from .signals import (create_site_profile) # now create the second signal
# in core.signals
from django.contrib.sites.models import Site
from django.db.models.signals import post_save, post_migrate
from django.dispatch import receiver
from .models import SiteProfile
@receiver(post_save, sender=Site)
def create_site_profile(sender, instance, **kwargs):
"""This signal creates/updates a SiteProfile object
after creating/updating a Site object.
"""
siteprofile, created = SiteProfile.objects.update_or_create(
site=instance
)
if not created:
siteprofile.save()
# in settings.py
TEMPLATES = [
{
# ...
'OPTIONS': {
'context_processors': [
# ...
# custom processor for getting the current site
'core.context_processors.site_processor',
],
},
},
]
# in core.context_processors
from django.conf import settings
from django.contrib.sites.models import Site
def site_processor(request):
try:
return {
'site': Site.objects.get_current()
}
except:
Site.objects.create(
id=getattr(settings, 'SITE_ID', 1),
domain='example.com', name='example.com')
# e.g.
{{ site.name }}
{{ site.profiles.long_name }}