Aam*_*amu 12 django django-templates django-models django-views
我的应用程序有三种不同的型号.一切都按照我的预期运作.
class Tender(models.Model):
title = models.CharField(max_length=256)
description = models.TextField()
department = models.CharField(max_length=50)
address = models.CharField(max_length=50)
nature_of_work = models.CharField(choices=WORK_NATURE, max_length=1)
period_of_completion = models.DateField()
pubdat = models.DateTimeField(default=timezone.now)
class Job(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL)
title = models.CharField(max_length=256)
qualification = models.CharField(max_length=256)
interview_type = models.CharField(max_length=2, choices=INTERVIEW_TYPE)
type_of_job = models.CharField(max_length=1, choices=JOB_TYPE)
number_of_vacancies = models.IntegerField()
employer = models.CharField(max_length=50)
salary = models.IntegerField()
pubdat = models.DateTimeField(default=timezone.now)
class News(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL)
title = models.CharField(max_length=150)
body = models.TextField()
pubdat = models.DateTimeField(default=timezone.now)
Run Code Online (Sandbox Code Playgroud)
现在,我在每个模型的单独页面上显示每个模型(例如,在作业页面中,我只显示作业.).但现在在主页上,我想根据他们在同一页面上发布的日期显示这些内容.如何在同一页面上显示不同模型的不同对象?我是否制作单独的模型class Post,然后在创建新对象时使用信号创建新帖子Tender,或者Job,或者News?我真的希望有更好的方法来实现这一目标.或者我使用多表继承?请帮我.谢谢.
更新:
我不想在同一页面上单独显示每个模型对象.但就像Facebook或任何其他社交媒体的饲料.假设在fb中,任何帖子(无论是图像,状态,共享)都在主页中一起显示.同样在我的情况下,假设创建了一个新的Job对象,之后创建了一个新的News对象.然后,我想首先显示News对象,然后是Job对象,依此类推.
Mos*_*oye 11
以下应该需要你.但是为了提高性能,您可以type在每个模型中创建一个额外的字段,这样annotation就可以避免.
您的视图将如下所示:
from django.db.models import CharField
def home(request):
# annotate a type for each model to be used in the template
tenders = Tender.object.all().annotate(type=Value('tender', CharField()))
jobs = Job.object.all().annotate(type=Value('job', CharField()))
news = News.object.all().annotate(type=Value('news', CharField()))
all_items = list(tenders) + list(jobs) + list(news)
# all items sorted by publication date. Most recent first
all_items_feed = sorted(all_items, key=lambda obj: obj.pubdat)
return render(request, 'home.html', {'all_items_feed': all_items_feed})
Run Code Online (Sandbox Code Playgroud)
在您的模板中,项目按其排序顺序(按新近度)排序,您可以通过区分项目类型为每个项目应用适当的html和样式:
# home.html
{% for item in all_items_feed %}
{% if item.type == 'tender' %}
{% comment "html block for tender items" %}{% endcomment %}
{% elif item.type == 'news' %}
{% comment "html block for news items" %}{% endcomment %}
{% else %}
{% comment "html block for job items" %}{% endcomment %}
{% endif %}
{% endfor %}
Run Code Online (Sandbox Code Playgroud)
您可以annotation通过使用__class__模型对象的属性来区分并将它们放在适当的html块中来完全避免.
对于一个Tender对象,item.__class__将app_name.models.Tender其中app_name是包含模型Django的应用程序的名称.
因此,在home视图中不使用注释,您的模板将显示:
{% for item in all_items_feed %}
{% if item.__class__ == 'app_name.models.Tender' %}
{% elif item.__class__ == 'app_name.models.News' %}
...
{% endif %}
{% endfor %}
Run Code Online (Sandbox Code Playgroud)
这样,您可以在注释上节省额外的开销,或者不得不修改模型.
e4c*_*4c5 11
有两个工作解决方案另外两个答案.这两个都涉及三个查询.而你正在查询整个表格.all().这些查询的结果合并为一个列表.如果您的每个表都有大约10k的记录,这将对您的wsgi服务器和数据库造成巨大压力.即使每个表每个只有100个记录,您也会在视图中不必要地循环300次.总之反应迟钝.
如果您想要一个高效的解决方案,多表继承绝对是正确的方法.您的模型可能如下所示:
class Post(models.Model):
title = models.CharField(max_length=256)
description = models.TextField()
pubdat = models.DateTimeField(default=timezone.now, db_index = True)
class Tender(Post):
department = models.CharField(max_length=50)
address = models.CharField(max_length=50)
nature_of_work = models.CharField(choices=WORK_NATURE, max_length=1)
period_of_completion = models.DateField()
class Job(Post):
user = models.ForeignKey(settings.AUTH_USER_MODEL)
qualification = models.CharField(max_length=256)
interview_type = models.CharField(max_length=2, choices=INTERVIEW_TYPE)
type_of_job = models.CharField(max_length=1, choices=JOB_TYPE)
number_of_vacancies = models.IntegerField()
employer = models.CharField(max_length=50)
salary = models.IntegerField()
class News(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL)
def _get_body(self):
return self.description
body = property(_get_body)
Run Code Online (Sandbox Code Playgroud)
现在您的查询很简单
Post.objects.select_related(
'job','tender','news').all().order_by('-pubdat') # you really should slice
Run Code Online (Sandbox Code Playgroud)
该pubdat字段现已编入索引(请参阅我发布的新Post模型).这使得查询非常快.python中的所有记录都没有迭代.
你如何找出模板中的哪个?有这样的事情.
{% if post.tender %}
{% else %}
{% if post.news %}
{% else %}
{% else %}
Run Code Online (Sandbox Code Playgroud)
您的设计中有一些空间可以规范化数据库.例如,同一家公司可能会发布多个工作或招标.因此,这样的公司模式可能会有用.
没有多表继承或多个数据库查询的情况怎么样?如何解决一个甚至可以消除渲染每个项目的开销的解决方案?
这是由redis排序集的礼貌.每次您保存Post,Job或者News,对象,你将它添加到Redis的有序set.
from django.db.models.signals import pre_delete, post_save
from django.forms.models import model_to_dict
@receiver(post_save, sender=News)
@receiver(post_save, sender=Post)
@receiver(post_save, sender=Job)
def add_to_redis(sender, instance, **kwargs):
rdb = redis.Redis()
#instead of adding the instance, you can consider adding the
#rendered HTML, that ought to save you a few more CPU cycles.
rdb.zadd(key, instance.pubdat, model_to_dict(instance)
if (rdb.zcard > 100) : # choose a suitable number
rdb.zremrangebyrank(key, 0, 100)
Run Code Online (Sandbox Code Playgroud)
同样,您需要添加pre_delete以从redis中删除它们
这种方法的明显优势在于您根本不需要任何数据库查询,并且您的模型仍然非常简单+您可以在混合中使用.如果您在Twitter上,您的时间表可能是通过类似于此的机制生成的.
一个直接的方法是使用链与排序组合:
# your_app/views.py
from django.shortcuts import render
from itertools import chain
from models import Tender, Job, News
def feed(request):
object_list = sorted(chain(
Tender.objects.all(),
Job.objects.all(),
News.objects.all()
), key=lambda obj: obj.pubdat)
return render(request, 'feed.html', {'feed': object_list})
Run Code Online (Sandbox Code Playgroud)
请注意 - 上面提到的查询集.all()应该被理解为占位符.与许多条目一样,这可能是性能问题.示例代码将首先评估查询集,然后对它们进行排序.高达几百的记录很可能不会对性能(可衡量)的影响-但在数百万/十亿项的情况下它是值得看的.
要在排序之前进行切片,请使用以下内容:
Tender.objects.all()[:20]
Run Code Online (Sandbox Code Playgroud)
或者使用模型的自定义管理器卸载逻辑.
class JobManager(models.Manager):
def featured(self):
return self.get_query_set().filter(featured=True)
Run Code Online (Sandbox Code Playgroud)
然后你可以使用类似的东西:
Job.objects.featured()
Run Code Online (Sandbox Code Playgroud)
如果您需要依赖于对象类的其他逻辑,请创建一个简单的模板标记:
#templatetags/ctype_tags.py
from django import template
register = template.Library()
@register.filter
def ctype(value):
return value.__class__.__name__.lower()
Run Code Online (Sandbox Code Playgroud)
和
#templates/feed.html
{% load ctype_tags %}
<div>
{% for item in feed reversed %}
<p>{{ item|ctype }} - {{ item.title }} - {{ item.pubdat }}</p>
{% endfor %}
</div>
Run Code Online (Sandbox Code Playgroud)
有时可能需要使用现有/第三方模型创建这些类型的Feed.在这种情况下,对于要排序的所有模型,您没有相同的字段名称.
DATE_FIELD_MAPPING = {
Tender: 'pubdat',
Job: 'publish_date',
News: 'created',
}
def date_key_mapping(obj):
return getattr(obj, DATE_FIELD_MAPPING[type(obj)])
def feed(request):
object_list = sorted(chain(
Tender.objects.all(),
Job.objects.all(),
News.objects.all()
), key=date_key_mapping)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
4486 次 |
| 最近记录: |