рд╣реИрд▓реЛ, рдореБрдЭреЗ NullBooleanField рдФрд░ рдбреАрдмреА рдореЗрдВ рд╢реВрдиреНрдп рдорд╛рдиреЛрдВ рдХреЛ рдлрд╝рд┐рд▓реНрдЯрд░ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЦрд╛рд▓реА ('', 'рдХреЛрдИ рдирд╣реАрдВ') рдорд╛рди рдХреЗ рд╕рдВрдмрдВрдз рдореЗрдВ рдЖрдЬ рдХреБрдЫ рдмрд╣реБрдд рд╣реА рд░реЛрдЪрдХ рдмрд╛рдд рдХрд╛ рд╕рд╛рдордирд╛ рдХрд░рдирд╛ рдкрдбрд╝рд╛ред
рд░рд┐рдХреЙрд░реНрдб рдХреЗ рд▓рд┐рдП, рдореИрдВ django рдЖрд░рд╛рдо рдврд╛рдВрдЪреЗ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реВрдВред
рдпрд╣рд╛рдБ рдореЗрд░рд╛ рдЕрдиреБрднрд╡ рд╣реИ:
рдореИрдВ рдПрдХ django рдореЙрдбрд▓ рдмрдирд╛рддрд╛ рд╣реВрдВ:
class MyModel(models.Model):
is_solved = models.NullBooleanField()
рдФрд░ django рдЖрд░рд╛рдо рдврд╛рдВрдЪреЗ рдореЗрдВ, рдореИрдВ рдЕрдкрдирд╛ рд╡рд┐рдЪрд╛рд░ рдШреЛрд╖рд┐рдд рдХрд░рддрд╛ рд╣реВрдВ:
class MyModelFilter(filters.FilterSet):
class Meta:
model = MyModel
fields = ('is_solved',)
class MyModelViewSet(ModelViewSet):
queryset = MyModel.objects.all()
serializer_class = MyModelSerializer
filter_backends = (filters.DjangoFilterBackend,)
filter_class = MyModelFilter
рдЗрд╕рдХреЗ рд╕рд╛рде, рдореЗрд░реЗ рдкрд╛рд╕ django рдЖрд░рд╛рдо рдврд╛рдВрдЪреЗ рдХреЗ рд╕рд╛рде is_solved
рдлрд╝реАрд▓реНрдб рдкрд░ рдлрд╝рд┐рд▓реНрдЯрд░ рд╣реИред
рдлрд╝рд┐рд▓реНрдЯрд░ рд▓реЗрдмрд▓/рдорд╛рдиреЛрдВ рдХреЗ рд╕рд╛рде рдПрдХ рдЪреБрдирд┐рдВрджрд╛ рд╡рд┐рдЬреЗрдЯ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИ:
choices = (('', _('Unknown')),
('true', _('Yes')),
('false', _('No')))
рдЬреИрд╕рд╛ рдХрд┐ рдпрд╣рд╛рдВ рдмрддрд╛рдпрд╛ рдЧрдпрд╛ рд╣реИ: https://github.com/carltongibson/django-filter/blob/develop/django_filters/widgets.py#L103
рдЬрдм рдореИрдВ рдЗрд╕ рдлрд╝рд┐рд▓реНрдЯрд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реВрдВ, рдпрджрд┐ рдореИрдВ Unknown
рдХрд╛ рдЪрдпрди рдХрд░рддрд╛ рд╣реВрдВ, рддреЛ рд╕рдм рдХреБрдЫ рд╡рд╛рдкрд╕ рдХрд░ рджрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ... рдЗрд╕рд▓рд┐рдП рдХреБрдЫ рднреА рдлрд╝рд┐рд▓реНрдЯрд░ рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ...
рдореИрдВ рдЬреЛ рдЪрд╛рд╣рддрд╛ рдерд╛ рд╡рд╣ рдХреЗрд╡рд▓ is_solved
рд╡рд╛рд▓реА рд╡рд╕реНрддреБрдУрдВ рдХреЛ рдбреАрдмреА рдореЗрдВ null
рдкрд░ рд╕реЗрдЯ рдХрд░рдирд╛ рд╣реИред
рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рдореИрдВ is_solved
рдкреНрд░рджрд░реНрд╢рд┐рдд рд╣реЛрдиреЗ рдХреЗ рддрд░реАрдХреЗ рдХреЛ рдмрджрд▓рдирд╛ рдЪрд╛рд╣рддрд╛ рдерд╛, рдЗрд╕рд▓рд┐рдП рдореИрдВрдиреЗ рдЕрдкрдиреЗ рдореЙрдбрд▓ рдореЗрдВ рдереЛрдбрд╝рд╛ рд╕рдВрд╢реЛрдзрди рдХрд┐рдпрд╛ рд╣реИред
рдирдП рдореЙрдбрд▓:
CHOICES = (
(None, "OFF"),
(True, "YES"),
(False, "NO")
)
class MyModel(models.Model):
is_solved = models.NullBooleanField(choices=CHOICES)
рдЗрд╕ рд╕рдВрд╢реЛрдзрди рдХреЗ рд╕рд╛рде, django рдЖрд░рд╛рдо рдврд╛рдВрдЪреЗ рдореЗрдВ рдлрд╝рд┐рд▓реНрдЯрд░ рдореБрдЭреЗ рд╕рд╣реА рд╡рд┐рдЬреЗрдЯ рдХрд╛ рдЪрдпрди рдХрд░рддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдЕрдм рдпрд╣ рдЕрдкрдиреЗ рд╕реНрд╡рдпрдВ рдХреЗ рд╡рд┐рдЬреЗрдЯ рдХреЗ рд╕рд╛рде рдЪреЙрдЗрд╕рдлрд┐рд▓реНрдб рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИред
рдпрд╣ рдФрд░ рднреА рд╕рдордЭ рдореЗрдВ рдЖрддрд╛ рд╣реИ, рдХреНрдпреЛрдВрдХрд┐ рдЯреЗрдХреНрд╕реНрдЯ рдЗрдирдкреБрдЯ рдХреЗ рдмрдЬрд╛рдп рдореЙрдбрд▓ рдмрдирд╛рддреЗ рд╕рдордп рдЕрдм тАЛтАЛрдореЗрд░реЗ рдкрд╛рд╕ рдПрдХ рдЪрдпрди рдмреЙрдХреНрд╕ рд╣реИред
рд▓реЗрдХрд┐рди рдЬрдм рдореИрдВ рдлрд╝рд┐рд▓реНрдЯрд░рд┐рдВрдЧ рдХреЗ рд▓рд┐рдП OFF
рдХрд╛ рдЪрдпрди рдХрд░рддрд╛ рд╣реВрдВ, рддреЛ url рдПрдХ query_parameter рдХреЛ ?is_solved=
рдХреЗ рд░реВрдк рдореЗрдВ рд╕реЗрдЯ рдХрд░рддрд╛ рд╣реИ: /
рдпрд╣ рд╡реИрд╕реЗ рднреА рд╕рд╣реА рдФрд░ рдЧрд▓рдд рдХреЗ рд╕рд╛рде рдЕрдЪреНрдЫреА рддрд░рд╣ рд╕реЗ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИред
рддреЛ рдЗрд╕реЗ django рдЖрд░рд╛рдо рдврд╛рдВрдЪреЗ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдореИрдВрдиреЗ рдЕрдкрдиреА рдкрд╕рдВрдж рдХреЛ рдЗрд╕рдореЗрдВ рдмрджрд▓ рджрд┐рдпрд╛:
CHOICES = (
('None', "OFF"),
(True, "YES"),
(False, "NO")
)
None рдХреЗ рдмрдЬрд╛рдп None
'None'
рдиреЛрдЯ рдХрд░реЗрдВред рдФрд░ рдпрд╣ рдареАрдХ рд╣реИ, рдЕрдм рдореЗрд░реЗ рдкрд╛рд╕ рдПрдХ рдХреНрд╡реЗрд░реА рдкреИрд░рд╛рдореАрдЯрд░ рд╣реИ ?is_solved=None
рд▓реЗрдХрд┐рди рдЕрдм, рдЗрд╕ рдлрд╝рд┐рд▓реНрдЯрд░ рдХреЗ рд╕рд╛рде рдХреБрдЫ рднреА рд╡рд╛рдкрд╕ рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ... рд╕реВрдЪреА рдЦрд╛рд▓реА рд╣реИ...
рдореБрдЭреЗ рдЕрдкрдиреЗ рд╣рд╛рде django_filters рдХреЛрдб рдореЗрдВ рдбрд╛рд▓ рджрд┐рдпрд╛ :)
рдХреБрдВрдЬреА рдХреЛрдб рдХреЗ рдЗрд╕ рднрд╛рдЧ рдореЗрдВ рд╣реИ:
https://github.com/carlongibson/django-filter/blob/develop/django_filters/filters.py#L172
def filter(self, qs, value):
if isinstance(value, Lookup):
lookup = six.text_type(value.lookup_type)
value = value.value
else:
lookup = self.lookup_expr
if value in EMPTY_VALUES:
return qs
if self.distinct:
qs = qs.distinct()
qs = self.get_method(qs)(**{'%s__%s' % (self.name, lookup): value})
return qs
рдХреЛрдб рдХрд╛ рдпрд╣ рдЫреЛрдЯрд╛ рд╕рд╛ рдЯреБрдХрдбрд╝рд╛ рдлрд╝рд┐рд▓реНрдЯрд░рд┐рдВрдЧ рдХрд░рддрд╛ рд╣реИред
рдФрд░ рдореИрдВрдиреЗ dkango QuerySet рд╡реНрдпрд╡рд╣рд╛рд░ рдХреЗ рд╕рд╛рде рдХреБрдЫ рдмрд╣реБрдд рд╣реА рд░реЛрдЪрдХ рдкрд╛рдпрд╛ рд╣реИред
рдорд╣рддреНрд╡рдкреВрд░реНрдг рдкрдВрдХреНрддрд┐рдпреЛрдВ рдореЗрдВ рд╕реЗ рдПрдХ рд╣рд┐рд╕реНрд╕рд╛ рд╣реИрдВ:
if value in EMPTY_VALUES:
return qs
рдпрджрд┐ рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдПрдХ рдЦрд╛рд▓реА рдорд╛рди рд╣реИ, рдЬреЛ [], (), u'', {}, None
. рд╣реИ, рддреЛ рдХреНрд╡реЗрд░реА рдХреЛ рдлрд╝рд┐рд▓реНрдЯрд░ рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ
рд▓реЗрдХрд┐рди рд╣рдорд╛рд░рд╛ рдореВрд▓реНрдп 'None'
рд╣реИ, рдЗрд╕рд▓рд┐рдП рдпрд╣ рдареАрдХ рд╣реИ, рд╕рднреА рдЙрджрд╛рд╣рд░рдг рдХреЛрдб рдиреЗ 'None'
рдорд╛рди рдХреЛ None
рдореЗрдВ рдирд╣реАрдВ рдмрджрд▓рд╛ред рд▓реЗрдХрд┐рди NullBooleanField
рдмрд┐рдирд╛ choices
рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рд╕реЗ рдХреБрдЫ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рдЕрд▓рдЧ рд╣реЛ рдЬрд╛рддрд╛ рд╣реИ рдХреНрдпреЛрдВрдХрд┐ рдлрд╝реАрд▓реНрдб рдХреЛ рдЪреЙрдЗрд╕рдлрд╝рд┐рд▓реНрд▓реНрдб рдХреЗ рд░реВрдк рдореЗрдВ рдирд╣реАрдВ рдорд╛рдирд╛ рдЬрд╛рддрд╛ рд╣реИ:
django рдХреЛрд░ рд╕реЗ рдХреЛрдб:
class NullBooleanField(BooleanField):
"""
A field whose valid values are None, True and False. Invalid values are
cleaned to None.
"""
widget = NullBooleanSelect
def to_python(self, value):
"""
Explicitly checks for the string 'True' and 'False', which is what a
hidden field will submit for True and False, for 'true' and 'false',
which are likely to be returned by JavaScript serializations of forms,
and for '1' and '0', which is what a RadioField will submit. Unlike
the Booleanfield we need to explicitly check for True, because we are
not using the bool() function
"""
if value in (True, 'True', 'true', '1'):
return True
elif value in (False, 'False', 'false', '0'):
return False
else:
return None
def validate(self, value):
pass
рдЕрдм рдЪреАрдЬреЗрдВ рд╡рд╛рдХрдИ рд╡рд╛рдХрдИ рджрд┐рд▓рдЪрд╕реНрдк рд╣реЛ рдЬрд╛рддреА рд╣реИрдВ ...
рдЗрд╕ рд▓рд╛рдЗрди рдкрд░ рдПрдХ рдирдЬрд╝рд░ рдбрд╛рд▓реЗрдВ:
qs = self.get_method(qs)(**{'%s__%s' % (self.name, lookup): value})
рдпрд╣ django core db Queryset рдХреЛ рдкрд╛рд╕ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдлрд╝рд┐рд▓реНрдЯрд░рд┐рдВрдЧ рдХрд░рддрд╛ рд╣реИред
рд╣рдо рдЗрд╕рдХрд╛ рдЕрдиреБрд╡рд╛рдж рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ:
qs = qs.filter(is_solved__exact='None')
рдпрд╣ рдСрдкрд░реЗрд╢рди рдПрдХ рдЦрд╛рд▓реА рдХреНрд╡реЗрд░реАрд╕реЗрдЯ рд▓реМрдЯрд╛рдПрдЧрд╛ ...
рдпрд╣ is_solved = None
рдХреЗ рд╕рд╛рде рдПрдХ sql рдХреНрд╡реЗрд░реА рддреИрдпрд╛рд░ рдХрд░реЗрдЧрд╛
рд▓реЗрдХрд┐рди рдЕрдЧрд░ рд╣рдо рдкрд░реАрдХреНрд╖рдг рдХрд░рддреЗ рд╣реИрдВ:
qs = qs.filter(is_solved__exact=None)
рдпрд╣ рдбреАрдмреА рдореЗрдВ null
рдорд╛рдиреЛрдВ рдХреЗ рд╕рд╛рде рдХреЗрд╡рд▓ рдЙрджрд╛рд╣рд░рдгреЛрдВ рдХреЛ рд╕рд╣реА рдврдВрдЧ рд╕реЗ рд▓реМрдЯрд╛рддрд╛ рд╣реИред
рдпрд╣ is_solved IS NULL
рдХреЗ рд╕рд╛рде рдПрдХ sql рдХреНрд╡реЗрд░реА рддреИрдпрд╛рд░ рдХрд░реЗрдЧрд╛
рдкрд░реАрдХреНрд╖рдг рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдпрд╣ рд╡рд╣реА рдмрд╛рдд рд╣реИ:
qs = qs.filter(is_solved__isnull=True)
рд╣рд╛рд▓рд╛рдВрдХрд┐, 'True'
рдФрд░ 'False'
рдорд╛рдиреЛрдВ рдореЗрдВ рдпрд╣ рд╕рдорд╕реНрдпрд╛ рдирд╣реАрдВ рд╣реИред рдЯреНрд░рд╛рдВрд╕рдХреНрд░рд┐рдкреНрд╢рди Django рджреНрд╡рд╛рд░рд╛ рд╕рд╣реА рд╣реИред
рд╣рдо рдЕрдкрдиреЗ рдлрд╝рд┐рд▓реНрдЯрд░ рдХреЗ lookup_epxr рдХреЛ isnull
рд╕реЗ рдУрд╡рд░рд░рд╛рдЗрдб рдХрд░рдиреЗ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рд╕реЛрдЪ рд╕рдХрддреЗ рд╣реИрдВ рд▓реЗрдХрд┐рди рд╣рдорд╛рд░рд╛ рдлрд╝рд┐рд▓реНрдЯрд░ True
рдФрд░ False
рдорд╛рдиреЛрдВ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдирд╣реАрдВ рдХрд░реЗрдЧрд╛...
рдЗрд╕ рдмрд┐рдВрджреБ рдкрд░, рдореИрдВ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдирд╣реАрдВ рдЬрд╛рдирддрд╛ рдХрд┐ рдЗрд╕ рд╡реНрдпрд╡рд╣рд╛рд░ рдХреЛ рдХреИрд╕реЗ рд╕рдВрднрд╛рд▓рдирд╛ рд╣реИ, django bug? django рдлрд╝рд┐рд▓реНрдЯрд░ рдХреБрдЫ рдпрд╛рдж рдХрд░ рд░рд╣рд╛ рд╣реИ?
рд╡реИрд╕реЗ рднреА, рдореИрдВ django рдлрд╝рд┐рд▓реНрдЯрд░ рдХреЗ filter
рдлрд╝рдВрдХреНрд╢рди рдХреЛ рдлрд┐рд░ рд╕реЗ рд▓рд┐рдЦрдХрд░ рдЗрд╕реЗ рдХрд╛рдо рдХрд░рдиреЗ рдореЗрдВ рд╕рдХреНрд╖рдо рд╣реВрдВ:
def filter(self, qs, value):
from django.db.models import NullBooleanField
if isinstance(value, Lookup):
lookup = six.text_type(value.lookup_type)
value = value.value
else:
lookup = self.lookup_expr
if value in EMPTY_VALUES:
return qs
if self.distinct:
qs = qs.distinct()
# if original field is a NullBooleanField, we need to transform 'None' value as None
if isinstance(self.model._meta.get_field(self.name), NullBooleanField) and value in ('None',):
value = None
qs = self.get_method(qs)(**{'%s__%s' % (self.name, lookup): value})
return qs
рдпрд╣ рдПрдХ рд╣реИрдХ рдХреА рддрд░рд╣ рджрд┐рдЦрддрд╛ рд╣реИ рдФрд░ рдпрд╣ рдореБрдЭреЗ рдЕрднреА рдХреЗ рд▓рд┐рдП рдЦреБрд╢ рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИ ...
рдЕрдЧрд░ рдХрд┐рд╕реА рдХреЛ рдЗрд╕ рдореБрджреНрджреЗ рдкрд░ рд╕реЛрдЪрдиреЗ рдореЗрдВ рджрд┐рд▓рдЪрд╕реНрдкреА рд╣реИ рддреЛ рдореБрдЭреЗ рдпрд╣ рд╕реБрдирдХрд░ рдЦреБрд╢реА рд╣реЛрдЧреА! :рдбреА
рдЕрднреА рдХреЗ рд▓рд┐рдП, рдЗрд╕ рд╕рдВрд╢реЛрдзрди рдкрд░ рдХреЛрдИ рд╡рд┐рдЪрд╛рд░?
рдЕрднреА, рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдореИрдВ django рдлрд╝рд┐рд▓реНрдЯрд░ рдХреЗ рдлреЛрд░реНрдХрдб рд╕рдВрд╕реНрдХрд░рдг рдХрд╛ рдЙрдкрдпреЛрдЧ рди рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╡рд┐рдХрд▓реНрдк рд╡рд┐рдХрд▓реНрдк рдХреЗ рд╕рд╛рде IntegerField
рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реВрдВрдЧрд╛ ... рдХреНрдпреЛрдВрдХрд┐ рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдпрд╣ рдПрдХ django рдлрд╝рд┐рд▓реНрдЯрд░ рд╢реБрд░реБрдЖрдд рдирд╣реАрдВ рд╣реИ :)
рдзрдиреНрдпрд╡рд╛рдж,
рд╣рд╛рдп @GuillaumeCisco - рдРрд╕рд╛ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдпрд╣рд╛рдВ рддреАрди рдореБрджреНрджреЗ рд╣реИрдВ:
BooleanWidget
w/ NullBooleanField
s рдХрд╛рдо рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИ, рдХреНрдпреЛрдВрдХрд┐ рдпрд╣ рд╢реВрдиреНрдп рдорд╛рдиреЛрдВ рдХреЛ рдорд╛рдиреНрдп рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИредрд╕рдВрднрд╡рддрдГ рдПрдХ NullBooleanWidget
рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдП рдЬреЛ рдЕрддрд┐рд░рд┐рдХреНрдд рд╡рд┐рдХрд▓реНрдк рдХреЛ рд╕рдорд╛рдпреЛрдЬрд┐рдд рдХрд░рддрд╛ рд╣реЛред
рдпрд╣ рд╢рд╛рдпрдж рд╡рд┐рдЬреЗрдЯ рд╡рд░реНрдЧ рдХреЛ рдЙрдкрд╡рд░реНрдЧрд┐рдд рдХрд░рдХреЗ рдФрд░ choices
рд╕рдВрдкрддреНрддрд┐ рдХреЛ рдореИрдиреНрдпреБрдЕрд▓ рд░реВрдк рд╕реЗ рд╕реЗрдЯ рдХрд░рдХреЗ рд╕рдмрд╕реЗ рдЕрдЪреНрдЫрд╛ рдирд┐рдпрдВрддреНрд░рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред BooleanWidget
рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдПрдХ рд╡рд┐рдХрд▓реНрдк рддрд░реНрдХ рдХреЛ рд╕реНрд╡реАрдХрд╛рд░ рдирд╣реАрдВ рдХрд░ рд╕рдХрддрд╛ рд╣реИ, рдХреНрдпреЛрдВрдХрд┐ рдпрд╣ рд╡рд┐рд╢рд┐рд╖реНрдЯ рдореВрд▓реНрдпреЛрдВ рдХреА рдЕрдкреЗрдХреНрд╖рд╛ рдХрд░рддрд╛ рд╣реИ ( 'true'
/ 'false'
рдХреЗ рдмрдЬрд╛рдп True
/ False
) . рд╡рд╣реА рд╕рдВрднрд╛рд╡рд┐рдд NullBooleanWidget
рдкрд░ рд▓рд╛рдЧреВ рд╣реЛрдЧрд╛ред
None
рджреНрд╡рд╛рд░рд╛ рдлрд╝рд┐рд▓реНрдЯрд░ рдХрд░рдиреЗ рдореЗрдВ рд╕рдорд╕реНрдпрд╛рдПрдБ рд╣реИрдВ, рдХреНрдпреЛрдВрдХрд┐ рдпрд╣ рд░рд┐рдХреНрдд рдорд╛рди рдЬрд╛рдБрдЪ рдХреЛ рдкрд╛рд╕ рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИредрдПрдХ рдЬрд╛рджреБрдИ рдореВрд▓реНрдп рдЬреИрд╕реЗ 'None'
рдпрд╛ 'null'
рдпрд╣рд╛рдВ рдЖрд╡рд╢реНрдпрдХ рд╣реЛрдиреЗ рдЬрд╛ рд░рд╣рд╛ рд╣реИред рдЗрд╕рдХреЗ рд▓рд┐рдП filter()
рдкрджреНрдзрддрд┐ рдХрд╛ рд╣рд┐рд╕рд╛рдм рджреЗрдирд╛ рд╣реЛрдЧрд╛ред
рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдЗрд╕рдХрд╛ рдмрдбрд╝рд╛ рд╣рд┐рд╕реНрд╕рд╛ #519 рджреНрд╡рд╛рд░рд╛ рдХрд╡рд░ рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛ред
@GuillaumeCisco рдХреГрдкрдпрд╛ рдЗрд╕рдХреА рд╕рдореАрдХреНрд╖рд╛ рдХрд░реЗрдВред рдпрджрд┐ рдХреЛрдИ рд╡рд┐рд╢рд┐рд╖реНрдЯ рдкрд░реАрдХреНрд╖рдг рдорд╛рдорд▓рд╛ рд╣реИ рдЬреЛ рдЖрдкрдХреЛ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдХрд╡рд░ рдХрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдП, рддреЛ рдХреНрдпрд╛ рдЖрдк рдЗрд╕реЗ рдЬреЛрдбрд╝рдХрд░ рдПрдХ рдкреАрдЖрд░ рдЦреЛрд▓ рд╕рдХрддреЗ рд╣реИрдВ рдФрд░ рд╣рдо рд╕рдореАрдХреНрд╖рд╛ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред
рдзрдиреНрдпрд╡рд╛рджред
рдзрдиреНрдпрд╡рд╛рдж @carltongibson рдФрд░ рдЖрдкрдХреЛ рднреА рдзрдиреНрдпрд╡рд╛рдж @rkilby
рдмрд╕ рд╡рд┐рдХрд╛рд╕ рд╢рд╛рдЦрд╛ рдЦреАрдВрдЪ рд▓реАред
NullBooleanField рдЕрдм рдЗрд╕ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдХреЗ рд╕рд╛рде django рд░реЗрд╕реНрдЯ рдлреНрд░реЗрдорд╡рд░реНрдХ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░ рд░рд╣рд╛ рд╣реИ:
Model
:
CHOICES = (
(None, "OFF"),
(True, "YES"),
(False, "NO")
)
class MyModel(models.Model):
is_solved = models.NullBooleanField(choices=CHOICES)
View
:
choices = (
(True, "YES"),
(False, "NO")
)
class MyModelFilter(filters.FilterSet):
is_solved = ChoiceFilter(null_label='OFF', choices=choices)
class Meta:
model = MyModel
fields = ('is_solved',)
class MyModelViewSet(ModelViewSet):
queryset = MyModel.objects.all()
serializer_class = MyModelSerializer
filter_backends = (filters.DjangoFilterBackend,)
filter_class = MyModelFilter
рд╡рд┐рдХрд▓реНрдк рдЯреБрдкрд▓реНрд╕ рдХреЗ рдмреАрдЪ рдЕрдВрддрд░ рдкрд░ рдзреНрдпрд╛рди рджреЗрдВред
рд╕рдмрд╕реЗ рдЙрдкрдпреЛрдЧреА рдЯрд┐рдкреНрдкрдгреА
рдзрдиреНрдпрд╡рд╛рдж @carltongibson рдФрд░ рдЖрдкрдХреЛ рднреА рдзрдиреНрдпрд╡рд╛рдж @rkilby
рдмрд╕ рд╡рд┐рдХрд╛рд╕ рд╢рд╛рдЦрд╛ рдЦреАрдВрдЪ рд▓реАред
NullBooleanField рдЕрдм рдЗрд╕ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдХреЗ рд╕рд╛рде django рд░реЗрд╕реНрдЯ рдлреНрд░реЗрдорд╡рд░реНрдХ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░ рд░рд╣рд╛ рд╣реИ:
Model
:View
:рд╡рд┐рдХрд▓реНрдк рдЯреБрдкрд▓реНрд╕ рдХреЗ рдмреАрдЪ рдЕрдВрддрд░ рдкрд░ рдзреНрдпрд╛рди рджреЗрдВред