Django应用的多个实例,Django支持吗
我用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 个回答
感谢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提供的建议,这个解决方案正是基于这些建议的。
我该如何在Django网站中创建多个相同应用的实例,并且每个实例有不同的数据库模型呢?
其实你不需要这样做。
你只需要在其他两个应用中使用反馈应用的模型,方法很简单,只需在代码中写 from feedback.models import Feedback
。
这样,你的 support
应用就可以创建、获取、更新和删除反馈对象了。
同样,你的 dev
应用也可以创建、获取、更新和删除反馈对象,因为它也引入了这个模型。
其实就这么简单:只需要 import
一下。
单一模型方法
我个人建议把这个做成一个应用,并且设计一个可以处理来自多个地方提交的视图,同时给它们打上合适的标签。
正如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))