2013-07-16 35 views
1

我正在嘗試3個表的外連接,並想知道我的方法是否正確和高效?Django原始SQL - 左外部加入效率和更好的方法?

型號:

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與緩存它會是太棒了。

回答

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將達到每個數據庫時間。需要重新審視。