【问题标题】:Django ListView: filter history based on chosen userDjango ListView:根据所选用户过滤历史记录
【发布时间】:2019-12-15 09:20:08
【问题描述】:

我有一个 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,
        }

它在一个大表中返回正确的历史项目(见下面的 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'),
            )
        ))

这个表单只是简单地创建了同一个 User 对象的两个 ModelChoiceFields,只是一个字段显示所有“普通”用户,另一个显示所有“特殊用户”

我的网址看起来像这样:

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 %}

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

但我不知道如何从我选择的用户那里接收 ID,我的表单始终在两个 ModelChoiceField 中显示正确的用户,但是我如何从这些用户那里获取 ID 以便在我的看法?

用户自己仅通过他们拥有的special字段进行区分,但他们共享相同的模型。

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

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

【问题讨论】:

    标签: python django listview filtering django-crispy-forms


    【解决方案1】:

    简答

    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 有一个关键字参数 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
    

    最后,删除您的第二个网址,因为这不再需要。

    【讨论】:

      猜你喜欢
      • 2017-09-13
      • 1970-01-01
      • 1970-01-01
      • 2021-03-24
      • 1970-01-01
      • 2012-12-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多