Как динамически передавать аргументы формам в Django? - PullRequest
0 голосов
/ 08 октября 2019

У меня есть форма «BasicSearch», имеющая два поля. Одним из них является поле выбора с именем 'search_by', а другим - текстовое поле с именем 'search_for'. У меня есть модели для клиентов, поставщиков, предметов, проектов и несколько других. Я хочу дать пользователю возможность выполнять поиск по различным моделям на соответствующих страницах, предоставляя запрос в текстовом поле и выбирая из поля выбора то, в чем он хочет искать (заголовки столбцов из моделей).

Я уже пробовал несколько решений на стеке, но ни одно из них не работает для меня. Это прекрасно работает, когда я вручную создаю словарь заголовков столбцов и передаю его в поле выбора.

В настоящее время класс формы поиска выглядит следующим образом (который не работает)

class BasicSearch(forms.Form):
    def __init__(self,arg):
        super(BasicSearch, self).__init__(arg)
        caller = arg
        if caller == 'customer':
            cu = Customers()
        field_dct = get_col_heads(cu)
        self.fields['search_by'] = forms.ChoiceField(choices=field_dct,widget=forms.Select(attrs={'class':'form-control'}))
        self.fields['search_for'] = forms.CharField(widget=forms.TextInput(attrs={'class':'form-control'}))

Функция get_col_heads:

def get_col_heads(cu):
    all_fields = cu._meta.fields
    all_field_list = []
    for fields in all_fields:
        column_head = (str(fields)).split(".")
        all_field_list.append(column_head[-1])
        field_list = all_field_list[1:-2]
        field_dct = tuple(zip(field_list,field_list))
    return field_dct

клиенты просматривают класс в view.py

class IndexView(TemplateView):
    template_name = 'crudbasic/index.html'
    def get_context_data(self,**kwargs):
        context = super().get_context_data(**kwargs)
        context ['page_title'] = ''
        return context

class CustomerView(ListView):
    template_name = 'crudbasic/customers.html'
    model = Customers
    context_object_name = 'customer_data'

    def get_context_data(self,**kwargs):
        context = super().get_context_data(**kwargs)
        context['search_form'] = BasicSearch('customer')
        return context

    def post(self, request, *args, **kwargs):
        search_form = BasicSearch(request.POST)
        if search_form.is_valid():
            data = request.POST.copy()
            qby = data.get('search_by')
            qstrting = data.get('search_for')
            queryparam = qby+'__'+'contains'
            search_list = Customers.objects.filter(**{queryparam:qstrting})
            customer_data = search_list
        return render(request, self.template_name, {'customer_data': customer_data,'search_form':search_form})

Когда я помещаю init в поле формы, чтобы взять аргумент для выбора соответствующей модели / таблицы и затем сгенерировать словарь из заголовков столбцов таблицы, все этопошла с ума. в настоящее время с кодом выше он дает мне следующую ошибку.

AttributeError at /customers/
'str' object has no attribute 'get'

Пожалуйста, помогите, если кто-нибудь знает способ сделать это.

Спасибо

1 Ответ

0 голосов
/ 08 октября 2019

Ваш пользовательский метод __init__ класса BasicSearch не учитывает все остальные аргументы, которые может иметь форма. Вы не можете сделать это. Более подходящий способ - использовать пользовательский аргумент kwarg примерно так:

class BasicSearch(forms.Form):
    def __init__(self, *args, **kwargs):
        caller = kwargs.pop('caller')
        super(BasicSearch, self).__init__(*args, **kwargs)
        # ...


# usage
form = BasicSearch(caller='customer')

# usage with POST
form = BasicSearch(request.POST,  caller='customer')

PS. В python все является объектом, даже классами, поэтому вместо предоставления "string" в качестве вызывающей стороны вы можете просто передать сам класс: form = BasicSearch(caller=Customers)

...