簡體   English   中英

Django - 將兩個模型傳遞到一個視圖中,並顯示兩個模型

[英]Django - Pass two Models into one view, and display both models

我正在嘗試將兩個模型傳遞到創建視圖中,我試圖從 URL 獲取主鍵,以從食品卡車 model 檢索詳細信息,以便它可以顯示在頁面中,並且用戶可以在其中寫入關於食品卡車的評論。 另外,我想在頁面上顯示評論列表。

視圖.py

class TruckReviewView(CreateView):
    model = Review
    template_name = 'truckReviews/detail.html'
    fields = ['speedOfService', 'qualityAndTaste', 'valueForMoney', 'comment']

    def get_queryset(self):
        self.pk = self.kwargs['pk']
        queryset = super(TruckReviewView, self).get_queryset()
        return queryset

    def get_context_data(self, **kwargs):
        context = super(TruckReviewView, self).get_context_data(**kwargs)
        context['truck'] = FoodTrucks.objects.get(truckID=get_queryset())
        context['reviews'] = Review.objects.get(truckID=get_queryset())
        return context

網址.py

urlpatterns = [
    path('', TruckListView.as_view(), name='reviews-home'),
    path('truck/<int:pk>/', TruckReviewView.as_view(), name='truck-detail'),
    path('about/', About.as_view(), name='reviews-about'),
]

模型.py

class FoodTrucks(models.Model):
    truckID = models.IntegerField(primary_key=True, unique=True, null=False)
    name = models.CharField(max_length=25)
    category = models.CharField(max_length=20)
    bio = models.TextField()
    avatarSRC = models.TextField(default=None)
    avatarALT = models.CharField(max_length=20, default=None)
    avatarTitle = models.CharField(max_length=20, default=None)
    coverPhotoSRC = models.TextField(default=None)
    coverPhotoALT = models.CharField(max_length=20, default=None)
    coverPhotoTitle = models.CharField(max_length=20, default=None)
    website = models.TextField(default=None)
    facebook = models.CharField(max_length=100, default=None)
    instagram = models.CharField(max_length=30, default=None)
    twitter = models.CharField(max_length=15, default=None)


class Review(models.Model):
    reviewID = models.AutoField(primary_key=True, unique=True, serialize=False, null=False)
    truckID = models.ForeignKey(FoodTrucks, on_delete=models.CASCADE)
    userID = models.ForeignKey(User, on_delete=models.CASCADE)
    datePosted = models.DateTimeField(default=timezone.now)
    speedOfService = models.IntegerField()
    qualityAndTaste = models.IntegerField()
    valueForMoney = models.IntegerField()
    comment = models.TextField(max_length=128)

我嘗試使用get_queryset從 URL 獲取 pk 並將 pk 傳遞到get_context_data並在數據庫中使用該 ID 定位特定卡車。

首先,不需要創建 truckID 和 reviewID 主鍵字段,因為 Django 會自動為每個 object 創建一個唯一的 id 字段,您可以簡單地在其上執行.get(id=1).filter(id=1)等。

就像將 ID 放在具有外鍵或任何關系字段的字段中完全沒有用一樣,因為 Django 會自動將名稱和 append _id輸入到它。 例如,只是user將成為user_idtruck將成為后端的truck_id ,您可以在其中執行.get(user__id=1).get(user_id=1)例如。

您應該查看代碼的這一部分。 你實際上並沒有對主鍵做任何事情:

 def get_queryset(self):
    queryset = super().get_queryset()
    try:
       item = queryset.get(id=self.kwargs['pk'])
    except:
       ...
    else:
       # Do something with item here
       ...
    finally:
       return queryset

或者,使用get_context_data

  def get_context_data(self, **kwargs):
     context = super().get_context_data(**kwargs)
     queryset = super().get_queryset()

     try:
        item = queryset.get(id=kwargs['pk'])
     except:
        ...
     else:
        # Do something with item here
        context['item'] = item
     finally:
        return context

我很抱歉,但你的問題有點令人困惑。 如果您嘗試從 model 獲取詳細信息,則應使用DetailView 此外,在DetailView上,假設您需要 Review 的詳細信息,因為您對卡車進行了評論,您可以簡單地覆蓋get_context_data並通過執行self.object.truck在上下文中設置truck

如果您正在嘗試創建評論,那么使用CreateView是正確的,但這應該只適用於評論 model。

要列出您應該使用ListView

因此,據我了解,您有一個truckID ,並希望為此創建評論。 在這種情況下,它會有一個CreateView用於Review model。

查看CreateViewDetailViewListView文檔

困難來自您將列表視圖和創建視圖結合在一起的事實。 如果你想把它組合成一個視圖,那么你需要對Class Based Views的不同 mixin 進行一些混合和匹配。

它可以做到,但它不是微不足道的。 如果您是 Django 的新手,那么這可能有點過頭了。 我已將字段重命名為此類並將其作為練習。 我沒有為表單提交而煩惱,它應該不難實現,因為其他視圖不處理所涉及的方法(form_valid、get_success_url 等)。 你可以用它作為指南,看看你應該學習什么。 上面的鏈接站點非常方便查看事物是如何混合在一起的。

下面的結果將為模板提供變量“foodtruck”、“reviews”和“form”。

import typing as t

from django.views import generic
from .models import FoodTruck, Review
from .forms import ReviewForm

if t.TYPE_CHECKING:
    from django.http import HttpRequest, HttpResponse
    from django.contrib.auth.models import AbstractUser

    class AuthenticatedRequest(HttpRequest):
        user: AbstractUser = ...


class FoodTruckDetailReviewListCreateView(
    generic.list.MultipleObjectMixin, generic.edit.CreateView,
):
    template_name = "foodtrucks/detail.html"
    model = Review
    list_model = Review
    context_list_name = "reviews"
    context_object_name = "foodtruck"
    detail_model = FoodTruck
    form_class = ReviewForm

    def get(self, request: "AuthenticatedRequest", *args, **kwargs) -> "HttpResponse":
        """
        Combine the work of BaseListView and BaseDetailView

        Combines the get implementation of BaseListView and BaseDetailView, but
        without the response rendering. Then hands over control to CreateView's
        method to do the final rendering.

        Some functionality is stripped, because we don't need it.

        :param request: The incoming request
        :return: A response, which can be a redirect
        """
        # BaseListView
        self.object_list = self.get_queryset()
        # BaseDetailView
        self.object = self.get_object()
        context = self.get_context_data(
            object=self.object, object_list=self.object_list
        )
        # CreateView sets self.object to None, but we override form_kwargs, so
        # we can leave it at a value.

        return self.render_to_response(context=context)

    def get_template_names(self):
        # Bypass logic in superclasses that we don't need
        return [self.template_name]

    def get_object(self, queryset=None):
        # We provide the queryset to superclasses with the other model
        return super().get_object(queryset=self.detail_model.objects.all())

    def get_queryset(self):
        # This only gets called by MultipleObjectMixin
        pk = self.kwargs.get(self.pk_url_kwarg)
        if pk is None:
            raise AttributeError(
                "Unable to filter on food truck: {} is missing in url.".format(
                    self.pk_url_kwarg
                )
            )
        queryset = self.list_model.objects.filter(food_truck_id=pk)
        # print(str(queryset.query))
        return queryset

    def get_context_data(self, **kwargs):
        if "object" in kwargs:
            kwargs[self.context_object_name] = kwargs["object"]
        if "object_list" in kwargs:
            kwargs[self.context_list_name] = kwargs["object_list"]

        return super().get_context_data(**kwargs)

    def get_form_kwargs(self):
        # Bypass ModelFormMixin, which passes in self.object as instance if it
        # is set.
        return super(generic.edit.ModelFormMixin, self).get_form_kwargs()

作為參考,這就是我將模型更改為:

import uuid

from django.contrib.auth import get_user_model
from django.db import models
from django.utils import timezone


class FoodTruck(models.Model):
    name = models.CharField(max_length=25)
    category = models.CharField(max_length=20)
    bio = models.TextField()
    avatar_url = models.URLField(blank=True)
    avatar_alt_text = models.CharField(max_length=20, blank=True)
    avatar_title = models.CharField(max_length=20, blank=True)
    cover_photo_url = models.URLField(blank=True)
    cover_photo_alt_text = models.CharField(max_length=20, default="No photo provided")
    cover_photo_title = models.CharField(max_length=20, default="No photo provided")
    website = models.URLField(blank=True)
    facebook = models.CharField(max_length=100, blank=True)
    instagram = models.CharField(max_length=30, blank=True)
    # https://9to5mac.com/2017/11/10/twitter-display-name-limit/
    twitter = models.CharField(max_length=50, blank=True)

    def __str__(self):
        return self.name


class Review(models.Model):
    uuid = models.UUIDField(primary_key=True, default=uuid.uuid4)
    food_truck = models.ForeignKey(
        FoodTruck, on_delete=models.CASCADE, related_name="reviews"
    )
    user = models.ForeignKey(get_user_model(), on_delete=models.CASCADE)
    posted_at = models.DateTimeField(default=timezone.now)
    speed_of_service = models.IntegerField()
    quality_and_taste = models.IntegerField()
    value_for_money = models.IntegerField()
    comment = models.TextField(max_length=128)

    def __str__(self):
        return "Review about {} by {}".format(
            self.food_truck.name, self.user.get_full_name()
        )

最后是表單(注入引導類有一些技巧):

class ReviewForm(forms.ModelForm):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        for field in self.fields.values():
            if not field.widget.is_hidden:
                field.widget.attrs.setdefault("class", "form-control")

    class Meta:
        model = Review
        exclude = ("uuid", "user", "food_truck", "posted_at")

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM