【问题标题】:Use data from GET request in get_intial() and get_form_kwargs() of FormVIew在 FormVIew 的 get_intial() 和 get_form_kwargs() 中使用来自 GET 请求的数据
【发布时间】:2021-03-21 01:35:29
【问题描述】:

我正在尝试重构我的代码以继承 FormView 而不是 View。我正在使用的视图在 GET 请求中接收值。我在 get_context_data 方法中检索值并将它们传递给不同的函数,最终得到一组我可以在上下文中传递的变量。

简而言之:

为了举例,变量集包括变量 FOO 和 BAR。我需要通过在 kwargs 中传递变量 FOO 来初始化我的表单,并将表单字段的初始值设置为 BAR。我知道我应该使用 get_initial() 和 get_form_kwargs() 方法来做到这一点。我只是在纠结如何从 get_context_data 方法中获取 FOO 和 BAR。

我尝试将 FOO 和 BAR 添加到上下文字典中:

context = super().get_context_data(**kwargs)
context["FOO"] = foo
context["BAR"] = bar
return context

然后从其他方法调用它:

def get_initial(self):
    """ Get initial value for the form field """

    initial = super(NameOfView, self).get_initial()
    context = self.get_context_data()
    initial_value = context["BAR"]
    initial.update({'name': inital_value})
    return initial

get_form_kwargs 也是如此。但我得到一个 RecursionError:

调用 Python 对象时超出最大递归深度

任何帮助理解我如何实现这一点将不胜感激

更新:我的实际代码更像这样:*

class ConfirmTripView(FormView):
    """
    Provides the user a set of choice options based on their search input in
    the products.TripsView
    """

    model = Booking
    template_name = "bookings/trips_available.html"
    form_class = DateChoiceForm

    def __init__(self):
        self.searched_date = None
        self.passengers = None
        self.destination_id = None
        self.gte_dates = None
        self.lt_dates = None

    def convert_to_int(self, type_tuple):
        """ Converts tuple value to integer """

        type_int = int(''.join(type_tuple))
        return type_int

    def get_available_trips(self, destination, passengers):
        """ Find trips with enough seats for searched no. of passengers """

        available_trips = Trip.objects.filter(
            destination=destination
        ).filter(seats_available__gte=passengers)
        return available_trips

    def get_trips_matched_or_post_date(self, date, destination, passengers):
        """
        Returns trips that either match or are post- searched_date
        Refine to trips with dates closest to searched_date
        limit to 3 results
        """

        available_trips = self.get_available_trips(destination, passengers)
        gte_dates = available_trips.filter(date__gte=date)[:3]
            return gte_dates

    def get_trips_preceding_date(self, date, destination, passengers):
        """
        Returns trips that are pre- searched_date
        Refines to trips with dates closest to searched_date
        limits to 3 results
        """

        available_trips = self.get_available_trips(destination, passengers)
        lt_dates = available_trips.filter(date__lt=date).order_by("-date")[:3]
        return lt_dates

    def make_timezone_naive(self, obj):
        """ Turns date attribute to a time-zone naive date object """

        date_attr = obj.date
        date_string = date_attr.strftime("%Y-%m-%d")
        datetime_naive = datetime.strptime(date_string, "%Y-%m-%d")
        return datetime_naive

    def get_trips_queryset(self, gte_dates, lt_dates):
        """ Creates the queryset that will be used by the ModelChoiceField
        in the DateChoiceForm """

        # Merge both queries
        trips = lt_dates | gte_dates
        trips = trips.order_by('date')
        return trips

    def get_initial(self, **kwargs):
        """ Takes values from get request and formulates variables
        to be used in the form """

        # Values from GET request
        self.searched_date = self.request.GET.get('request_date')
        self.passengers = self.request.GET.get('passengers')
        self.destination_id = self.convert_to_int(
            self.request.GET.get("destination")
        )

        # Return querysets for dates before/beyond searched_date respectively:
        self.gte_dates = self.get_trips_matched_or_post_date(
            self.searched_date,
            self.destination_id,
            self.passengers)

        self.lt_dates = self.get_trips_preceding_date(
            self.searched_date,
            self.destination_id,
            self.passengers)

        naive_searched_date = datetime.strptime(self.searched_date, "%Y-%m-%d")
        # Find the trip closest to the searched_date (for form initial value)
        if self.gte_dates:
            gte_date = self.gte_dates[0]
            naive_gte_date = self.make_timezone_naive(gte_date)
            if self.lt_dates:
                lt_date = self.lt_dates[0]
                naive_lt_date = self.make_timezone_naive(lt_date)

                if (
                    naive_gte_date - naive_searched_date
                    > naive_searched_date - naive_lt_date
                ):
                    default_selected = lt_date
                else:
                    default_selected = gte_date

            else:
                default_selected = gte_date

        elif self.lt_dates:
            lt_date = self.lt_dates[0]
            default_selected = lt_date

        else:
            messages.error(
                self.request,
                "Sorry, there are no dates currently available for the"
                "selected destination.",
            )

        # Get initial valuees for the form
        initial = super(ConfirmTripView, self).get_initial()
        initial.update({'trip': default_selected})
        return initial

    def get_form_kwargs(self, **kwargs):
        """ Provides keyword arguemnt """

        kwargs = super(ConfirmTripView, self).get_form_kwargs()

        trips = self.get_trips_queryset(self.gte_dates, self.lt_dates)
        kwargs.update({'trips': trips})
        return kwargs

    def get_context_data(self, **kwargs):

        context = super().get_context_data(**kwargs)
        destination = Product.objects.filter(id=self.destination_id)
        context["passengers"] = self.passengers
        context["destination_obj"] = destination
        return context

    def form_valid(self, form):
        """
        Takes the POST data from the DateChoiceForm and creates an
        Intitial Booking in the database
           """

        booking = form.save(commit=False)
        booking.status = "RESERVED"
        booking.save()
        trip = form.cleaned_data['trip']
        destination = trip.destination
        booking_line_item = BookingLineItem(
            booking=booking,
            product=destination,
            quantity=self.request.GET.get("passengers")
        )
        booking_line_item.save()
        return redirect('create_passengers', booking.pk)

【问题讨论】:

    标签: django methods formview


    【解决方案1】:

    首先,bookmark this

    其次,get_initial() 和 get_context_data() 解决了两个不同的问题:

    • get_initial 是将初始值传递给表单。
    • get_context_data 是将变量传递给模板

    正如您在上面的站点中看到的,表单通过get_context_data() 注入到模板变量中,这就是您的递归问题的来源:

    - get()
     |- get_context_data()     <----------------------------------\
       |- get_form()                                              |
         |- get_form_kwargs()                                     |
           |- get_initial() --> you call get_context_data here ---/
    

    现在,您的问题尚不清楚您的 GET 参数和表单应该如何协同工作,但如果您需要 GET 中的一些值作为初始表单值,请将它们放入 get_initial()

    更新:

    1. 我不会有一个带有这样签名的方法get_queryset(),原因是处理模型的几个视图也有一个带有不同签名的get_queryset() 方法。 get_trips() 在这种情况下很有意义
    2. 您已经提取了一些功能,这很好,但是也可以提取“最接近搜索日期的结果”,并将结果存储在 self 中。
    3. 可以使用__range 查找,这可能会使您的逻辑更容易。将语义更改为“查找搜索日期之前 30 天和之后 30 天之间的行程”。这并不相同,但实际上是一种足够好的方法。

    如果您仍然卡住,请告诉我们具体是什么。

    【讨论】:

    • 好吧好吧。我觉得我明白了。听起来我应该反过来做(因为我还需要将一些值传递给模板)
    • 感谢网站的建议。我认为这将非常有用
    • 好吧,也许我根本没有得到这个。我将用我的代码更新问题,以便您查看。你介意看一下吗?
    • 您不必在一处进行。在需要时选择您需要的东西。如果您在两个地方都需要它们,请将结果存储在视图实例 self.result_of_function = function(self.request.GET.get('name-of-variables')) 中并在 get_context_data():context["foo"] = self.result_of_function 中获取结果。
    • 当然,无论如何,与 foo 和 bar 沟通都很困难 :)
    猜你喜欢
    • 2013-09-07
    • 1970-01-01
    • 1970-01-01
    • 2015-11-15
    • 1970-01-01
    • 2016-10-17
    • 1970-01-01
    • 2019-08-10
    • 2018-10-16
    相关资源
    最近更新 更多