2010-09-08 33 views
8

Tôi đã tìm kiếm một cách thanh lịch để đại diện cho trường có nhiều ngày trong tuần (Thứ Hai, Thứ Ba, Thứ Tư ...) trong mô hình Django. Ban đầu tôi đã nghĩ đến việc đi trường số nguyên bằng cách sử dụng toán học bitwise nhưng tôi không chắc chắn liệu đây có phải là cách để đi hay không.Đại diện cho trường đa lựa chọn cho các ngày trong tuần trong mô hình Django

Đây sẽ là trường được đọc nhiều nhất. Tôi muốn phương thức Queryset giống như Entry.objects.get(weekdays__contains=MONDAY) Trường hợp MONDAY sẽ là một hằng số.

Có lẽ ai đó có thể đưa ra giải pháp tốt hơn? Hoặc có thể ai đó đã làm điều gì đó tương tự và có một số mã ví dụ mà họ có thể đóng góp?

+0

Nếu không có thêm thông tin (kích thước của tập dữ liệu, chủ yếu là đọc vs chủ yếu là viết, vv) đi với bitfields cảm thấy như sợ hãi sớm tối ưu hóa. –

+0

Tôi sẽ thêm thông tin bổ sung cho câu hỏi. Cảm ơn ngài Rowell. –

+0

Bạn có cân nhắc việc thêm mối quan hệ nhiều đến nhiều giữa một mô hình 'Weekday' và mô hình được đề cập không? Tôi biết đây là một chút của một overkill xem xét rằng các ngày trong tuần được cố định về số lượng, nhưng nó sẽ làm cho lọc rất đơn giản. –

Trả lời

14

Đây là một câu hỏi cũ, nhưng tôi nghĩ tôi sẽ cho thấy làm thế nào nó có thể được thực hiện hợp lý đơn giản chỉ trong Django.

Đây là một lớp helper để chuẩn bị lựa chọn của bạn:

class BitChoices(object): 
    def __init__(self, choices): 
    self._choices = [] 
    self._lookup = {} 
    for index, (key, val) in enumerate(choices): 
     index = 2**index 
     self._choices.append((index, val)) 
     self._lookup[key] = index 

    def __iter__(self): 
    return iter(self._choices) 

    def __len__(self): 
    return len(self._choices) 

    def __getattr__(self, attr): 
    try: 
     return self._lookup[attr] 
    except KeyError: 
     raise AttributeError(attr) 

    def get_selected_keys(self, selection): 
    """ Return a list of keys for the given selection """ 
    return [ k for k,b in self._lookup.iteritems() if b & selection] 

    def get_selected_values(self, selection): 
    """ Return a list of values for the given selection """ 
    return [ v for b,v in self._choices if b & selection] 

Xác định mô hình của bạn với một PositiveIntegerField, và các lựa chọn bạn muốn:

WEEKDAYS = BitChoices((('mon', 'Monday'), ('tue', 'Tuesday'), ('wed', 'Wednesday'), 
       ('thu', 'Thursday'), ('fri', 'Friday'), ('sat', 'Saturday'), 
       ('sun', 'Sunday') 
      )) 

Điều này có nghĩa bạn có thể truy cập vào các giá trị như này:

>>> print list(WEEKDAYS) 
[(1, 'Monday'), (2, 'Tuesday'), (4, 'Wednesday'), (8, 'Thursday'), (16, 'Friday'), (32, 'Saturday'), (64, 'Sunday')] 
>>> print WEEKDAYS.fri 
16 
>>> print WEEKDAYS.get_selected_values(52) 
['Wednesday', 'Friday', 'Saturday'] 

Bây giờ hãy xác định mô hình của bạn với PositiveIntegerField và các lựa chọn này:

class Entry(models.Model): 
    weekdays = models.PositiveIntegerField(choices=WEEKDAYS) 

Và các mô hình của bạn đã hoàn tất. Đối với các truy vấn, sau đây hiện các trick:

Entry.objects.extra(where=["weekdays & %s"], params=[WEEKDAYS.fri]) 

Có thể có một cách để tạo một lớp con Q() đối tượng mà gọn gàng gói truy vấn, vì vậy họ trông như thế này:

Entry.objects.filter(HasBit('weekdays', WEEKDAYS.fri)) 

Hoặc thậm chí Hack tại một F() lớp con để tạo ra một cái gì đó như thế này:

Entry.objects.filter(weekdays=HasBit(WEEKDAYS.fri)) 

Nhưng tôi không có thời gian để khám phá rằng vào lúc này. .where hoạt động tốt và có thể được tóm tắt thành một hàm queryset.

Một xem xét cuối cùng là bạn có thể ánh sáng để tạo trường mô hình tùy chỉnh chuyển đổi mặt nạ bit trong cơ sở dữ liệu thành danh sách hoặc được đặt bằng Python. Sau đó, bạn có thể sử dụng tiện ích SelectMultiple (hoặc CheckboxSelectMultiple) để cho phép người dùng chọn giá trị của họ trong quản trị viên.

+0

Câu trả lời http: // stackoverflow này.com/questions/19645227/django-create-multiselect-checkbox-đầu vào broaches mà chủ đề liên quan đến teh phụ tùng – Yablargo

+0

Chỉ muốn nói cảm ơn một lần nữa, tôi đã có thể vấp ngã thông qua xây dựng một widget chống lại lớp học của bạn, và nó hoạt động như một nhà vô địch. – Yablargo

+0

@Yablargo và tác giả: Cảm ơn rất nhiều! Tôi cũng có thể tạo ra một widget chống lại lớp của bạn, nhưng tôi bị mắc kẹt khi thực hiện chức năng ngược lại (từ chuỗi (giá trị) (giả sử "12") thành datadict {(4, "wednesday"), (8, " Thứ năm ")} để hiển thị (và chỉnh sửa) dữ liệu ban đầu. Bạn có thể vui lòng trợ giúp ở đây: http://stackoverflow.com/q/25575951/3849359? Cảm ơn một triệu! – gabn88

Các vấn đề liên quan