繁体   English   中英

Django和具有多个外键的模型

[英]Django and models with multiple foreign keys

我是Django的新手,到目前为止我的能力给我留下了深刻的印象。 我正在玩更复杂的模型,我有问题正确使用它们。 使用Django 1.3,我正在尝试编写一个摘要页面,它将使用以下结构显示下面的三个模型。 换句话说,列出他们的目的地和活动的旅行。

  • 旅行1
    • 目的地1
    • 目的地2
    • 活动1
  • 旅行2
    • 目的地1
    • 活动2

楷模

  • 旅行< - > TripDestination < - >目的地(旅程可以有多个目的地)
  • 活动 - >旅行,活动 - >目的地(为特定地点/目的地的旅行定义活动)
    class Destination(models.Model):
        city_name=models.CharField()

    class Trip(models.Model):
        departing_on=models.DateField()
        returning_on=models.DateField()
        destinations=models.ManyToManyField(Destination)

    class Activity(models.Model):
        destination=models.ForeignKey(Destination, null=False)
        trip=models.ForeignKey(Trip, null=False)

我正在尝试编写一个视图,该视图将生成具有上述结构的页面。 我现在面临的主要问题是显示特定旅行和目的地的活动。 正如您在下面的代码中看到的,我正在构建一个字典,我怀疑这是正确的做法。 此外,视图变为

视图

def list_trip(request, template_name = 'trip-list.html'):
    trips = Trip.objects.all()

    # Build a dictionary for activities -- Is this the right thing to do?
    activities = Activity.objects.filter(trip__in=trips)
    activities_by_trips = dict()
    for activity in activities:
        if activity.trip_id not in activities_by_trips:
            activities_by_trips[activity.trip_id] = dict()

        if activity.destination_id not in activities_by_trips[activity.trip_id]:
            activities_by_trips[activity.trip_id][activity.destination_id] = []

        activities_by_trips[activity.trip_id][activity.destination_id].append(activity)

    return render_to_response(template_name, {
        'page_title': 'List of trips',
        'trips': trips,
        'activities_by_trips': activities_by_trips,
    })

模板


{% block content %}
    {% for trip in trips %}
        {{ trip.id }} - {{ trip.name }}

        {% for destination in trip.destinations.all %}
            {{ destination.city_name }}

            ** This is terrible code -- How to fix that **
            {% for key, value in activities_by_trips|dict_lookup:trip.id %}
                {% if value %}
                    {% for key_prime, value_prime in value|dict_lookup:destination.id %}
                       {{ value_prime.description }}
                    {% endfor %}
                {% endif %}
            {% endfor %}
        {% endfor %}
    {% endfor %}
{% endblock %}

简而言之,有人可以帮助我得到所有旅行和活动的摘要吗? 实现这一目标的最佳方法是什么? 模型是否正确?

谢谢!

还有很大的改进空间。 通过在ManyToManyField上使用through,您可以明确定义连接表,我们可以方便地将其视为在特定旅行期间对城市的单次访问。 在那次访问期间我们有活动,所以活动应该有一个外国访问。

对于表中的每个外键,Django将为关系的另一侧的对象集添加API便利管理器。 Destination将有一个visit_set ,但Trip也是如此。 同样,由于visit Activity foreignkey,每次访问都会有一个activity_set

首先从模型开始:

from django.db import models

# Create your models here.
class Destination(models.Model):
    city_name=models.CharField(max_length=50)

class Trip(models.Model):
    departing_on=models.DateField()
    returning_on=models.DateField()
    destinations=models.ManyToManyField(Destination, through='Visit')

class Visit(models.Model):
    destination=models.ForeignKey(Destination)
    trip=models.ForeignKey(Trip)

class Activity(models.Model):
    name=models.CharField(max_length=50)
    visit=models.ForeignKey(Visit)

然后让我们list_trip更改list_trip ,添加print_trip以清楚模板中发生的事情:

def list_trip(request, template_name = 'trip-list.html'):
    return render_to_response(template_name, {
        'page_title': 'List of trips',
        'trips': Trip.objects.all(),
        })

def print_trips():
    for trip in Trip.objects.all():
        for visit in trip.visit_set.select_related().all():
            print trip.id, '-', visit.destination.city_name
            for act in visit.activity_set.all():
                print act.name

最后是改进的模板:

{% block content %}
    {% for trip in trips %}
        {{ trip.id }} - {{ trip.name }}

        {% for visit in trip.visit_set.select_related.all %}
            {{ visit.destination.city_name }}

            {% for act in visit.activity_set.all %}
                 {{ act.name }}
            {% endfor %}
        {% endfor %}
    {% endfor %}
{% endblock %}

还有一些改进的改进空间。 注意我使用了select_related。 这将在获取访问时预取所有目标,因此visit.destination.city_name不会引发另一个db调用。 但是,这不适用于反向ManyToMany关系(在我们的例子中是activity_set的所有成员)。 Django 1.4将推出名为prefetch_related的新方法,该方法也将解决这个问题。

与此同时,请阅读有效的反向查找 ,了解如何进一步减少数据库命中数。 在评论中,也提到了几个现成的解决方案。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM