Django Raw SQL - 左外连接效率和更好的方法?

时间:2013-07-16 11:24:28

标签: sql django django-templates django-views

我正在尝试3个表的外连接,并且想知道我的方法是否正确和有效?

型号:

class GuestCategory(models.Model):
    profile = models.ForeignKey(UserProfile)
    category = models.CharField(max_length=30)

    class Meta:
        db_table = 'guest_category'

class Guest(models.Model):
    profile = models.ForeignKey(UserProfile)
    guest_category = models.ForeignKey(GuestCategory, 
        null=True, blank=True, default = None)
    first_name = models.CharField(max_length=48, blank=False)
    last_name = models.CharField(max_length=48)
    invite_list = models.ManyToManyField(GuestList, through='RSVPList')

    class Meta:
        ordering = ('last_name', 'first_name')
        db_table = 'guest'

class GuestDetails(models.Model):
    guest = models.OneToOneField(Guest)
    email = models.EmailField(max_length=254, blank=True)
    ...
    country = models.IntegerField(choices=Country(), null=True, blank=True)

    class Meta:
        db_table = 'guest_details'

查看:

class GuestListView(LoginRequiredMixin, ListView):
    context_object_name = 'guest_list'
    template_name = 'guest/guest_list.html'

    def get_queryset(self):
        self.guests = Guest.objects.raw("SELECT \
            guest.id, \
            guest.first_name, \
            guest.last_name, \
            guest_details.email, \
            ...
            guest_details.country, \
            guest_category.category \
            FROM guest \
            LEFT OUTER JOIN guest_details \
            ON guest_details.guest_id = guest.id \
            LEFT OUTER JOIN guest_category \
            ON guest_category.id = guest.guest_category_id \
            WHERE guest.profile_id = %s", [self.request.user.get_profile().id]
        )
        return self.guests

模板:

<ul>
    {% for guest in guest_list %}
    <li>{{ guest.first_name }} {{ guest.last_name }}
        <ul>
            <li>Email: {{ guest.email }}</li>
            ...
            <li>Country: {{ guest.country }}</li>
            {% comment %} {{ guest_details.get_country_display }} {% endcomment %}
            <li>Category: {{ guest.guest_category }}</li>
            <li><a href="{% url 'guests:guest_update' pk=guest.pk %}">Edit</a></li>
            <li><a href="{% url 'guests:guest_delete' pk=guest.pk %}">Remove</a></li>
        </ul>
    </li>
    {% endfor %}
</ul>

基本上,用户可以创建访客类别以将他们的客人放入,例如朋友,家人。在创建访客时,他们可能会或可能不会准备好客人详细信息,因此在用户创建访客详细信息之前不会保存。我尝试在guest_details上使用prefetch_related,但如果没有条目,则不会返回访客。

我希望为用户返回用户的信息行,如下所示:

 first_name | last_name | country | category 
------------+-----------+---------+----------
 Guest      | Two       |     169 | Friends
 Guest      | One       |      13 | Friends
 Guest      | Three     |      10 | Friends
 Guest      | Four      |         | 

注意,客人类别也不是必修字段。我使用左外连接来获取类别和详细信息。但是,当我在浏览器中加载视图时,我注意到由于{{ guest.guest_category }}导致每个访客类别的数据库被点击。我可以从guest_category表中检索类别而不需要像上面的SQL结果中那样使用额外的数据库命中吗?

有没有更好的方法来实现我想要的?我不是SQL的陌生人,但如果有更多django-ish的缓存,那就太棒了。

1 个答案:

答案 0 :(得分:0)

实际上我意识到prefetch_related有效。我对我的模型进行了一些更改:

class GuestDetails(models.Model):
    guest = models.OneToOneField(Guest, related_name='details')
    ...

然后在观点中:

guest_list = Guest.objects.filter(profile=profile).prefetch_related('details')

模板中的引用很简单:

{% for g in guests %}
<li>{{ g.full_name }}</li>
<ul>
    <li>Category: {{ g.category }}</li>
    <li>Email: {{ g.details.email }}</li>
    <li>Country: {{ g.details.get_country_display }}</li>
</ul>
{% endfor %}

但是,每次在模板中返回g.category都会在数据库中命中。需要重温。