Django ListView:根据所选用户过滤历史记录

Django ListView: filter history based on chosen user

我有一个 History ListView,我想让我的用户根据他们在我提供的 ModelChoiceFields 中选择的用户来过滤 Historyitems

我的历史视图如下所示:

class HistoryItems(ListView):
    model = HistoryItem
    template_name = 'history/history_table.html'
    context_object_name = 'history_items'

    def get_context_data(self, **kwargs):
        user_id = kwargs.get('user_id')

        query = {}

        if user_id:
            user = get_object_or_404(User, pk=user_id)
            query['changed_by'] = user
        else:
            user = None

        history_items = HistoryItem.objects.filter(**query).select_related('changed_by',
                                                                           'content_type')

        return {
            'filter_history_form': HistoryFilterForm(user_id=user_id),
            'history_items': history_items,
        }

它 returns 我在大 table 中找到了正确的历史记录(请参阅下面的 html)。然后我得到了这个表格:

class HistoryFilterForm(forms.Form):
    normal_user = forms.ModelChoiceField(User.objects.filter(special=None), label="Normal Users", empty_label="All normal users")
    special_user = forms.ModelChoiceField(User.objects.exclude(special=None), label="Special User", empty_label="All special users")

    def __init__(self, *args, **kwargs):
        user_id = kwargs.pop('user_id')
        super(HistoryFilterForm, self).__init__(*args, **kwargs)

        self.fields['normal_user'].initial = user_id
        self.fields['special_user'].initial = user_id

        self.helper = FormHelper()
        self.helper.label_class = 'sr-only'
        self.helper.add_layout(Layout(
            Row(
                Div('normal_user', css_class='col-sm-3'),
                Div('special_user', css_class='col-sm-3'),
            )
        ))

此表单简单地创建了同一用户对象的两个 ModelChoiceField,一个字段显示所有 "normal" 用户,另一个显示所有 "special users"

我的网址看起来很漂亮:

urls = [
    path('', views.HistoryItems.as_view(), name='history_index'),
    path('u=<int:pk>', views.HistoryItems.as_view(), name='history_index'),
]

我想当我搜索另一个用户的历史项目时,我需要一直刷新我的页面,我正在用 JavaScript 做这件事(见下面的 HTML ).我还将 url 中的用户 ID 设置为额外参数。

最后是我的 HTML:


{% block extra_js %}
    {{ block.super }}

    <script type="application/javascript">

    $(function(){


        var historyUrlBase = '/history/';

        var getParams = function(){
            return {
                'normalUserId': $('#id_normal_user').val(),
                'specialUserId': $('#id_special_user').val()
            }
        };

        var getNormalUrl = function(){
            var params = getParams();
            return historyUrlBase + 'u=' + params.normalUserId;
        };

        $('#id_normal_user').change(function(){
            window.location.href = getNormalUrl();
        });

        var getSpecialUrl = function(){
            var params = getParams();
            return historyUrlBase + 'u=' + params.specialUserId;
        };

        $('#id_special_user').change(function(){
            window.location.href = getSpecialUrl();
        });

    });
    </script>
{% endblock %}

{% block main %}

   {% crispy filter_history_form %}

    <table class="table table-bordered table-responsive-sm">
        <thead class="thead-light">
            <tr>
                <th>Changed at</th>
                <th>Object</th>
                <th>Action</th>
                <th>Changed by</th>
                <th>Difference</th>
            </tr>
        </thead>
        <tbody>
        {% for history_item in history_items %}
            <tr>
                <td>
                    {{ history_item.changed_at|date:"d.m.Y h:i:s" }}
                </td>
                <td>
                    {{ history_item.object }}
                </td>
                <td>
                    {% if history_item.action == 'custom' %}
                        {{ history_item.description }}
                    {% else %}
                        {{ history_item.get_action_display }}
                    {% endif %}
                </td>
                <td>
                    {{ history_item.changed_by }}
                </td>
                <td>
                    {{ history_item.difference|default:'' }}
                </td>
            </tr>
        {% endfor %}
        </tbody>
    </table>
{% endblock %}

我现在的主要问题是,在我的 View 中,我收到的 kwargs 始终是一个空的 dict,ofc 没有任何作用。

但我不知道如何从我选择的用户那里接收 ID,我的表单总是在两个 ModelChoiceFields 中显示正确的用户,但我如何从这些用户那里获取 ID 以使用它们在我看来?

用户本身只是通过他们拥有的special字段来区分,但他们共享相同的模型。

我正在使用 Django 2.2 和 Python 3.7 顺便说一句,所以也许如果有人知道更简单的方法,那也很受欢迎!

我希望有人知道一个好的解决方案或者可以告诉我我做错了什么。谢谢! :)

简答

get_context_data 中的 kwargs 字典包含在您的 url 中定义的任何关键字参数。

urls = [
    path('', views.HistoryItems.as_view(), name='history_index'),
    path('u=<int:pk>', views.HistoryItems.as_view(), name='history_index'),
]

您的第一个 url 没有定义关键字参数。您的第二个 url 有一个关键字参数 pk(即不是 user_id)。所以你的代码实际上应该是

user_id = kwargs.get('pk')

长答案

您设置表单的方式通常不是您处理数据过滤的方式。您要做的是使用 GET 请求提交表单。

https://docs.djangoproject.com/en/dev/topics/forms/#get-and-post

这将生成一个 url 查询字符串参数,类似于

/history/?normal_user=1&special_user=1

然后您可以通过请求对象中的 GET 字典在您的视图中访问这些查询字符串参数。

def get_context_data(self, **kwargs):
    normal_user = self.request.GET.get('normal_user')
    special_user = self.request.GET.get('special_user')

    # filter your history with normal_user/special_user

最后,删除您的第二个 url,因为这不再是必需的。