Django应用的多个实例,Django支持吗

5 投票
3 回答
4078 浏览
提问于 2025-04-17 10:13

我用Django写了一个简单的反馈应用。这个应用其实不复杂,主要是让已经登录的用户可以写一条简短的消息,并填写一个主题,然后通过一个表单提交这条消息。接着,属于特定小组的人可以查看用户提交的反馈。将来我可能会增加更多功能,但现在这个应用已经能满足我的需求了。

我现在有个问题,我正在搭建的网站上有多个地方想使用这个反馈应用。比如,我有一个“你觉得这个网站怎么样?”的页面,地址是/dev/feedback/,还有一个是客户支持反馈的页面,地址是"/support/feedback/"。目前,我只是把mysite.apps.dev.feedback里的代码复制到了mysite.apps.support.feedback

问题是,这样做导致了两个相同代码的独立副本。尽管我刚写完这个应用,但这两个版本已经开始出现差异,这让我很烦恼。我的问题很简单,如何在Django网站中创建多个相同应用的实例,并且让它们有不同的数据库模型?

我找到了一些相关但不太有用的资源,比如https://docs.djangoproject.com/en/dev/topics/http/urls/在Django中反向命名空间URL:相同应用的多个实例。第一篇文章对这个问题没有提供太多帮助,第二篇则给出了一些看起来不太实用的解决方案,似乎既不相关又比实际操作更麻烦。有没有更好的方法来实现多个相同Django应用的实例?

3 个回答

1

感谢Yuji Tomita给出的详细回答,我的最终解决方案与他的建议非常相似,但还是有一些不同,所以我想把它作为另一个选项发布,以便其他遇到相同情况的人参考。

首先,在我的 mysite.apps.feedback.models 文件中,我添加了

class Feedback( models.Model ):
   subject = models.TextField( max_length=100 )
   body = models.TextField( max_length=100 )
   # Some other stuff here...
   # Finally I used the suggestion above and created a field which I 
   # use to label each entry as belonging to a specific instance of the app.
   instance_name = models.TextField( max_length=20 )

在我的 mysite.apps.feedback.views 文件中,我添加了

def save_message( request, instance_name ):
    if request.method == 'POST':
        form = FeedbackFrom( request.POST )
        if form.is_valid():
            form.instance.instance_name = instance_name
            form.save()
            return render("feedback/thanks.html")
         else:
             return render("feedback/submit.html", {'form':form })
     else:
         return render("feedback/submit.html",{'form':FeedbackForm()})

@user_passes_test( is_staff )
def all_messages( request, instance_name ):
    messages = Feedback.objects.filter( instance_name = instance_name )
    return render("feedback/view_all.html",{'feedback':messages} )

在我的 mysite.apps.dev.urls 文件中,我添加了

url(r'^feedback/', include('mysite.apps.feedback.urls'),
    {'instance_name':'dev'}),

在我的 mysite.apps.support.urls 文件中,我添加了

url(r'^feedback/', include('mysite.apps.feedback.urls'),
    {'instance_name':'support'}),

这样做可以根据应用实例来区分反馈信息。需要注意的是,我的实际代码要复杂一些,但这段代码应该足够让有类似问题的人快速找到解决方案。希望这对遇到相似情况的人有帮助。再次感谢Yuji Tomita提供的建议,这个解决方案正是基于这些建议的。

2

我该如何在Django网站中创建多个相同应用的实例,并且每个实例有不同的数据库模型呢?

其实你不需要这样做。

你只需要在其他两个应用中使用反馈应用的模型,方法很简单,只需在代码中写 from feedback.models import Feedback

这样,你的 support 应用就可以创建、获取、更新和删除反馈对象了。

同样,你的 dev 应用也可以创建、获取、更新和删除反馈对象,因为它也引入了这个模型。

其实就这么简单:只需要 import 一下。

3

单一模型方法

我个人建议把这个做成一个应用,并且设计一个可以处理来自多个地方提交的视图,同时给它们打上合适的标签。

正如S.Lott所说,这就是最佳选择。如果你对其他方法感兴趣,我会提供一些替代方案,帮助你在不同情况下保持代码集中管理。

比如,你可以在模型中添加一个category字段,设置一个单一的URL配置,接受URL中的参数,比如/(?P<category>\w+/feedback/$,然后让视图根据合适的类别给反馈打标签。

class MyForm(forms.ModelForm):
    class Meta:
        model = Feedback

def my_view(request, category):
    form = MyForm(request.POST or None)
    if request.method == 'POST':
        if form.is_valid():
            feedback = form.save(commit=False)
            feedback.category = category
            feedback.save()
            return http.HttpResponse("Thanks for posting!")
    return render(request, "mytemplate.html", {'form': form})

# urls.py
(r'^(?P<category>\w+)/feedback/$', 'my_view')

# user can visit dev/feedback or support/feedback and the feedback will be tagged appropriately

抽象基类

另一种解决方案是构建一个抽象基类,然后为你的不同表创建子类。这样可以解决代码不同步的问题。

你会有一个单一的抽象模型(没有对应的表),然后你的“真实”模型就可以基于这个抽象模型在不同的应用中创建。

动态生成视图

如果你必须有不同的模型,你可以考虑写一个动态构建的视图。

def view_generator(model_class):
    class MyForm(forms.ModelForm):
         class Meta:
              model = model_class

    def my_view(request):
        form = MyForm(request.POST or None)
        if request.method == 'POST':
            if form.is_valid():
                form.save()
                return http.HttpResponse("Thanks for posting!")
        return render(request, "mytemplate.html", {'form': form})
    return my_view


# urls.py
from foo import view_generator

(r'^my_first_feedback_form', view_generator(Model1))
(r'^my_second_feedback_form', view_generator(Model2l))

撰写回答