Làm cách nào để thực hiện lọc truy vấn trong các mẫu django


82

Tôi cần thực hiện một truy vấn đã lọc từ bên trong mẫu django, để nhận một tập hợp các đối tượng tương đương với mã python trong một chế độ xem:

queryset = Modelclass.objects.filter(somekey=foo)

Trong mẫu của tôi, tôi muốn làm

{% for object in data.somekey_set.FILTER %}

nhưng tôi dường như không thể tìm ra cách viết FILTER.

Câu trả lời:


119

Bạn không thể làm điều này, đó là do thiết kế. Các tác giả khung Django dự định tách mã trình bày khỏi logic dữ liệu một cách chặt chẽ. Lọc mô hình là logic dữ liệu và xuất ra HTML là logic trình bày.

Vì vậy, bạn có một số tùy chọn. Đơn giản nhất là thực hiện lọc, sau đó chuyển kết quả cho render_to_response. Hoặc bạn có thể viết một phương thức trong mô hình của mình để bạn có thể nói {% for object in data.filtered_set %}. Cuối cùng, bạn có thể viết thẻ mẫu của riêng mình, mặc dù trong trường hợp cụ thể này, tôi khuyên bạn không nên làm điều đó.


2
Xin chào mọi người bây giờ là năm 2014! Khoảng 6 năm sau, các thư viện JS đã đạt được nhiều tiến bộ và việc lọc lượng dữ liệu không quá lớn nên được thực hiện ở phía máy khách với sự hỗ trợ của một số thư viện tập lệnh java đẹp, hoặc ít nhất là AJAX-ed.
andilabs

1
@andi: Tôi chắc chắn đồng ý với các tập dữ liệu thậm chí lớn vừa phải, ví dụ: thậm chí hàng nghìn hàng trong một bảng. Đã làm việc trên cơ sở dữ liệu với hàng triệu hàng, chắc chắn vẫn có một nơi để lọc phía máy chủ :)
Eli Courtwright

chắc chắn nhưng tôi chỉ muốn chỉ ra rằng mọi người thường xử lý với vài K hàng, điều đó có thể xảy ra trong trình duyệt của người dùng. Và đối với những người thậm chí xử lý các tập dữ liệu khổng lồ, một số aproach lai có thể là một giải pháp tốt, ví dụ như bộ lọc theo vài M đến vài K ở phía máy chủ, và các nhân viên khác nhẹ hơn bên trong vài K này làm ở phía máy khách.
andilabs

9
@andi Ngoại trừ các trường hợp bạn đang lọc nội dung dựa trên các quyền sẽ không bao giờ được thực hiện ở phía máy khách. Đúng?

38

Tôi chỉ thêm một thẻ mẫu bổ sung như thế này:

@register.filter
def in_category(things, category):
    return things.filter(category=category)

Sau đó, tôi có thể làm:

{% for category in categories %}
  {% for thing in things|in_category:category %}
    {{ thing }}
  {% endfor %}
{% endfor %}

Tôi đang cố gắng giải pháp này nhưng nó tiếp tục gây ra một lỗi: 'for' statements should use the format 'for x in y': for p in r | people_in_roll_department:d. Có ý kiến ​​gì không?
diosney

12

Tôi gặp phải vấn đề này một cách thường xuyên và thường sử dụng giải pháp "thêm một phương pháp". Tuy nhiên, chắc chắn có những trường hợp "thêm một phương thức" hoặc "tính toán nó trong dạng xem" không hoạt động (hoặc không hoạt động tốt). Ví dụ: khi bạn đang lưu các đoạn mẫu vào bộ nhớ đệm và cần một số tính toán DB không quan trọng để tạo ra nó. Bạn không muốn DB hoạt động trừ khi bạn cần, nhưng bạn sẽ không biết mình có cần làm hay không cho đến khi bạn hiểu sâu về logic mẫu.

Một số giải pháp khả thi khác:

  1. Sử dụng thẻ mẫu {% expr <expression> as <var_name>%} được tìm thấy tại http://www.djangosnippets.org/snippets/9/ Biểu thức là bất kỳ biểu thức Python hợp pháp nào với Ngữ cảnh của mẫu là phạm vi cục bộ của bạn.

  2. Thay đổi bộ xử lý mẫu của bạn. Jinja2 ( http://jinja.pocoo.org/2/ ) có cú pháp gần giống với ngôn ngữ mẫu Django, nhưng có sẵn toàn bộ sức mạnh Python. Nó cũng nhanh hơn. Bạn có thể thực hiện việc bán buôn này hoặc bạn có thể giới hạn việc sử dụng nó cho các mẫu mà bạn đang làm việc, nhưng hãy sử dụng các mẫu "an toàn hơn" của Django cho các trang do nhà thiết kế duy trì.


9

Tùy chọn khác là nếu bạn có bộ lọc mà bạn luôn muốn áp dụng, để thêm trình quản lý tùy chỉnh trên mô hình được đề cập, mô hình này luôn áp dụng bộ lọc cho các kết quả trả về.

Một ví dụ điển hình về điều này là một Eventmô hình, trong đó 90% các truy vấn bạn thực hiện trên mô hình, bạn sẽ muốn một cái gì đó tương tự Event.objects.filter(date__gte=now), tức là bạn thường quan tâm đến Eventsđiều đó sắp tới. Điều này sẽ trông giống như:

class EventManager(models.Manager):
    def get_query_set(self):
        now = datetime.now()
        return super(EventManager,self).get_query_set().filter(date__gte=now)

Và trong mô hình:

class Event(models.Model):
    ...
    objects = EventManager()

Nhưng một lần nữa, điều này áp dụng cùng một bộ lọc đối với tất cả các truy vấn mặc định được thực hiện trên Eventmô hình và do đó không linh hoạt như một số kỹ thuật được mô tả ở trên.


9

Điều này có thể được giải quyết bằng thẻ chuyển nhượng:

from django import template

register = template.Library()

@register.assignment_tag
def query(qs, **kwargs):
    """ template tag which allows queryset filtering. Usage:
          {% query books author=author as mybooks %}
          {% for book in mybooks %}
            ...
          {% endfor %}
    """
    return qs.filter(**kwargs)

3
Assign_tag đã bị xóa trong Django 2.0
Andreas Bergström

1

Đối với bất kỳ ai đang tìm kiếm câu trả lời vào năm 2020. Điều này đã làm việc cho tôi.

Trong Lượt xem:

 class InstancesView(generic.ListView):
        model = AlarmInstance
        context_object_name = 'settings_context'
        queryset = Group.objects.all()
        template_name = 'insta_list.html'

        @register.filter
        def filter_unknown(self, aVal):
            result = aVal.filter(is_known=False)
            return result

        @register.filter
        def filter_known(self, aVal):
            result = aVal.filter(is_known=True)
            return result

Trong mẫu:

{% for instance in alarm.qar_alarm_instances|filter_unknown:alarm.qar_alarm_instances %}

Trong mã giả:

For each in model.child_object|view_filter:filter_arg

Hy vọng rằng sẽ giúp.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.