çŸåšããªã¬ãŒã·ã§ã³ã·ããã¯ããã¥ãŒã«é©çšãããã®ãšåãæš©éãšãã£ã«ã¿ãªã³ã°ã®ã»ãããèªåçã«é©çšããŸããã æš©éãå¿ èŠãªå ŽåããŸãã¯é¢ä¿ããã£ã«ã¿ãªã³ã°ããå¿ èŠãããå Žåã¯ãæ瀺çã«åŠçããå¿ èŠããããŸãã
å人çã«ã¯ããããèªåçã«åŠçããè¯ãæ¹æ³ã¯ããããŸããããå°ãªããšãããã¥ã¡ã³ãåãæ¹åããããšã§ã§ããããšã¯æããã§ãã
ä»ã®ãšãããç§ã®æèŠã§ã¯ãç°¡åãªäŸã®ã±ãŒã¹ãèãåºãããããæ瀺çã«ã©ã®ããã«åŠçããããææžåããå¿ èŠããããŸãã ãããåŠçããããã®èªåã³ãŒãã¯ããµãŒãããŒãã£ã®ããã±ãŒãžäœæè ãåŠçã§ããããã«æ®ããŠããå¿ èŠããããŸãã ããã«ãããä»ã®å¯çš¿è ãåé¡ã調æ»ããã³ã¢ã«å«ãŸããå¯èœæ§ã®ããåªãããœãªã¥ãŒã·ã§ã³ãèãåºãããšãã§ãããã©ããã確èªã§ããŸãã
å°æ¥ããã®åé¡ã¯ãããã¥ã¡ã³ãããããæ¡åŒµãã«ææ Œããå¯èœæ§ããããŸããããµãŒãããŒãã£ããã±ãŒãžã«ãã£ãŠããã¯ã¢ãããããå ·äœçãªææ¡ããªãéãããã®ç¶æ ã®ãŸãŸã«ãªããŸãã
ã³ãŒããæãäžããŠã¿ãŸããããç°¡åãªæ¹æ³ãèŠã€ãããŸããã§ããã çæ³çã«ã¯ãé¢é£ãããã¹ãŠã®ãªããžã§ã¯ãã«å¯ŸããŠããŒããã·ã§ã³ã®ãhas_object_permissionããåŒã³åºãããšãã§ããã¯ãã§ãã çŸåšãã·ãªã¢ã©ã€ã¶ãŒã¯ã¢ã¯ã»ã¹èš±å¯ãªããžã§ã¯ãã«ã¢ã¯ã»ã¹ã§ããŸããã
çŸåšãã·ãªã¢ã©ã€ã¶ãŒã¯ã¢ã¯ã»ã¹èš±å¯ãªããžã§ã¯ãã«ã¢ã¯ã»ã¹ã§ããŸããã
ããã¯ããã»ã©åçŽã§ã¯ãªãããšãé€ããŠã
_ã©ã®_èš±å¯ãªããžã§ã¯ãïŒ ãããã¯_other_ãªããžã§ã¯ããšã®é¢ä¿ã§ãããããçŸåšã®ãã¥ãŒã®ããŒããã·ã§ã³ã¯ã©ã¹ãšãã£ã«ã¿ãŒã¯ã©ã¹ã¯ããªããžã§ã¯ãã®é¢ä¿ã«é©çšãããã«ãŒã«ãšå¿ ãããåãã§ã¯ãããŸããã
ãã€ããŒãªã³ã¯ãããé¢ä¿ã®å Žåãçè«çã«ã¯ïŒ+ïŒãæããã¥ãŒã決å®ããããã«åºã¥ããŠãã£ã«ã¿ãªã³ã°/èš±å¯ã決å®ã§ããŸãããããã¯ç¢ºãã«æãããå¯çµåã®èšèšã«ãªããŸãã ãã€ããŒãªã³ã¯ãããŠããªãé¢ä¿ã®å Žåããããè¡ãããšããã§ããŸããã åã¢ãã«ãåäžã®æ£èŠãã¥ãŒã§1åå ¬éãããä¿èšŒã¯ãªãããããã€ããŒãªã³ã¯ãããŠããªãé¢ä¿ã«äœ¿çšããæš©éãèªåçã«æ±ºå®ããããšã¯ã§ããŸããã
ïŒ+ïŒå®éã«ã¯ããããå®éã«ã¯ããã_è³¢æãª_æ¹æ³ã§è¡ãããšã¯äžå¯èœã§ããããšãããããµããããŸãããã
ãã¶ããhas_
人ã ã¯ã©ã®ããã«ãã£ã«ã¿ãªã³ã°ã䜿çšããŸããïŒ ãŠãŒã¶ãŒãæš©éãæããªããªããžã§ã¯ããé衚瀺ã«ããããã ãã«äœ¿çšããŠããŸããïŒ ããããŠãŒã¹ã±ãŒã¹ã§ããå Žåããããããã£ã«ã¿ãŒã¯å¿ èŠãªãããã§ãã
åç §ãããŠããåé¡ã®1ã€ïŒ1646ã¯ãé¢é£ãã£ãŒã«ãã®é²èŠ§å¯èœãªAPIããŒãžã«è¡šç€ºãããéžæè¢ãå¶éããããšãæ±ã£ãŠããŸãã
ç§ã¯é²èŠ§å¯èœãªAPIã倧奜ãã§ãããã¯ãšã³ãéçºè ãšããŠã ãã§ãªããRESTAPIã®ããã³ããšã³ãéçºè /ãŠãŒã¶ãŒã«ãšã£ãŠãçŽ æŽãããããŒã«ã ãšæããŸãã é²èŠ§å¯èœãªAPIããªã³ã«ããŠè£œåãåºè·ããããšæããŸãïŒã€ãŸãããµã€ããDEBUGã¢ãŒãã§å€ç«ããŠããªãå Žåã§ãå®è¡ãããŸãïŒã ãããã§ããããã«ããããã«ãé²èŠ§å¯èœãªAPIããŒãžããæ å ±æŒãããèµ·ããããããšã¯ã§ããŸããã ïŒãã¡ãããããã¯ããããã®ããŒãžãäžè¬çã«æ¬çªç°å¢ã«å¯Ÿå¿ããŠããŠå®å šã§ãããšããèŠä»¶ã«å ããŠïŒã
ã€ãŸããé¢é£ãããã£ãŒã«ãã®ååšã«é¢ããæ å ±ã¯ãPOSTã§åŠç¿ã§ããæ å ±ãããHTMLããŒãžã§åŠç¿ã§ããã¯ãããããŸããã
æçµçã«ãé¢é£ãã£ãŒã«ãã®ãã¥ãŒã䜿çšããŠãã£ã«ã¿ãªã³ã°ãæäŸããã·ãªã¢ã©ã€ã¶ãŒã®ããã¯ã¹ã€ã³ã¯ã©ã¹ãäœæããŸããã
class RelatedFieldPermissionsSerializerMixin(object):
"""
Limit related fields based on the permissions in the related object's view.
To use, mixin the class, and add a dictionary to the Serializer's Meta class
named "related_queryset_filters" mapping the field name to the string name
of the appropriate view class. Example:
class MySerializer(serializers.ModelSerializer):
class Meta:
related_queryset_filters = {
'user': 'UserViewSet',
}
"""
def __init__(self, *args, **kwargs):
super(RelatedFieldPermissionsSerializerMixin, self).__init__(*args, **kwargs)
self._filter_related_fields_for_html()
def _filter_related_fields_for_html(self):
"""
Ensure thatk related fields are ownership filtered for
the browseable HTML views.
"""
import views
try:
# related_queryset_filters is a map of the fieldname and the viewset name (str)
related_queryset_filters = self.Meta.related_queryset_filters
except AttributeError:
related_queryset_filters = {}
for field, viewset in related_queryset_filters.items():
try:
self.fields[field].queryset = self._filter_related_qs(self.context['request'], getattr(views, viewset))
except KeyError:
pass
def _filter_related_qs(self, request, ViewSet):
"""
Helper function to filter related fields using
existing filtering logic in ViewSets.
"""
view = ViewSet()
view.request = request
view.action = 'retrieve'
queryset = view.get_queryset()
try:
return view.queryset_ownership_filter(queryset)
except AttributeError:
return queryset
ã·ãªã¢ã©ã€ã¶ãŒãšãã¥ãŒãæ··åšãããã®ã§ã¯ãªãããã¥ãŒããã¯ã¹ã€ã³ã䜿çšããŠããã解決ããŸããïŒïŒ1935ã èŸæžãå¿
èŠãšããã®ã§ã¯ãªãããã¥ãŒã§secured_fields
ãªã¹ãã䜿çšããŸããã
ãã®åçŽãªSerializerããã¯ã¹ã€ã³ã䜿çšããŠãé¢é£ãã£ãŒã«ãã®ã¯ãšãªã»ããããã£ã«ã¿ãªã³ã°ããŸããã
class FilterRelatedMixin(object):
def __init__(self, *args, **kwargs):
super(FilterRelatedMixin, self).__init__(*args, **kwargs)
for name, field in self.fields.iteritems():
if isinstance(field, serializers.RelatedField):
method_name = 'filter_%s' % name
try:
func = getattr(self, method_name)
except AttributeError:
pass
else:
field.queryset = func(field.queryset)
䜿ãæ¹ãç°¡åã§ãïŒ
class SocialPageSerializer(FilterRelatedMixin, serializers.ModelSerializer):
account = serializers.PrimaryKeyRelatedField()
class Meta:
model = models.SocialPage
def filter_account(self, queryset):
request = self.context['request']
return queryset.filter(user=request.user)
ã©ãã§ããïŒ äœãåé¡ããããŸããïŒ
ç§ã«ãšã£ãŠã¯ããŠãŒã¶ãŒãšãªã¯ãšã¹ãã«é¢ããããžãã¯ãã·ãªã¢ã©ã€ã¶ãŒããé€å€ãããã¥ãŒã«æ®ããŠããã®ã奜ãã§ãã
åé¡ã¯é¢é£ãããã£ãŒã«ãã«ãããŸãã ãŠãŒã¶ãŒã¯ãã¥ãŒã«ã¢ã¯ã»ã¹ã§ããŸãã
ãã¹ãŠã®é¢é£ãªããžã§ã¯ãã§ã¯ãããŸããã
18:16ã®æ°Žææ¥ã2014幎11æ5æ¥ã«ã¯ãã¢ã¬ãã¯ã¹Rothberg [email protected]
æžããŸããïŒ
ç§ã«ãšã£ãŠã¯ããŠãŒã¶ãŒãšãªã¯ãšã¹ãã«é¢ããããžãã¯ãé€å€ããã®ã奜ãã§ãã
ã·ãªã¢ã©ã€ã¶ãŒãšããããã¥ãŒã«æ®ããŸããâ
ãã®ã¡ãŒã«ã«çŽæ¥è¿ä¿¡ããããGitHubã§è¡šç€ºããŠãã ãã
https://github.com/tomchristie/django-rest-framework/issues/1985#issuecomment -61873766
ã
ã©ããããããèªãã§ãã ãããããã¯é¢é£ãããããã¯ã®ããã§ãã OPTIONSã¡ãœãããšPOSTãŸãã¯PUTã¡ãœããã®ã¡ã¿ïŒModelSerializerïŒã®ãã£ã«ã¿ãªã³ã°é¢é£ãã£ãŒã«ããªããžã§ã¯ããã©ã®ããã«åé¢ã§ããŸããïŒ
https://groups.google.com/forum/#!topic/django -rest-framework / jMePw1vS66A
model = serializers.PrimaryKeyRelatedFieldïŒqueryset = Model.objects.noneïŒïŒïŒãèšå®ããå Žåãsealizer PrimaryKeyRelatedField "ã¯ãšãªã»ããã¯ãã£ãŒã«ãå ¥åã®æ€èšŒæã«ã¢ãã«ã€ã³ã¹ã¿ã³ã¹ã®ã«ãã¯ã¢ããã«äœ¿çšããã"ãããé¢é£ããã¢ãã«ã€ã³ã¹ã¿ã³ã¹ãšãšãã«çŸåšã®ãªããžã§ã¯ããä¿åã§ããŸããã
model = serializers.PrimaryKeyRelatedFieldïŒqueryset = Model.objects.allïŒïŒïŒïŒModelSerializerã®ããã©ã«ããšããŠãããã«ã³ã¡ã³ãã§ããŸãïŒã®å Žåããã¹ãŠã®ãé¢é£ããããªããžã§ã¯ãïŒOPTIONSã¯ã¢ã¯ã·ã§ã³ïŒPOSTãPUTïŒã衚瀺ãããããå®éã«ã¯é¢é£ããŠããŸããïŒ ãã¢ãã«ããã£ãŒã«ãïŒOPTIONSã¡ãœããïŒã®éžæè¢ã«è¡šç€ºãããã¡ã€ã³ã®Modelã¯ã©ã¹ã®ããããã£ïŒé¢é£ãªããžã§ã¯ãã®ã€ã³ã¹ã¿ã³ã¹ã§ã¯ãããŸããïŒã
ã¢ããããŒãã @ cancan101 + 1ã ããããããŠãŒã¶ãŒãã ãã§ã¯ãããŸããã ã·ãªã¢ã©ã€ã¶ãŒã®ã¯ãšãªã»ãããserializers.PrimaryKeyRelatedFieldïŒqueryset = "ããèŠããšãããã¯ããžãã¯ãšã·ãªã¢ã©ã€ã¶ãŒãçµã¿åãããã®ã¯æªãèãã ãšæããŸãã
ãã¡ãããããã¯è¯ãããšã§ãïŒ
ã¯ã©ã¹ModelSerializerïŒ
ã¯ã©ã¹ã¡ã¿ïŒ
model =ã¢ãã«
ã·ãªã¢ã©ã€ã¶ãŒã¯ãã¢ãã«ããèªåçã«äœæãããã£ãŒã«ãã®æ¹æ³ãšæ¹æ³ãç¥ãå¿ èŠãããããã§ãã
ããã«ãããããããç§ã¯ééã£ãŠããå¯èœæ§ããããŸãã
ããã¯ããŸãããããã§ãïŒ
class BlogSerializer(serializers.ModelSerializer):
entries = serializers.SerializerMethodField()
class Meta:
model = Blog
def get_entries(self, obj):
queryset = obj.entries.all()
if 'request' in self.context:
queryset = queryset.filter(author=self.context['request'].user)
serializer = EntrySerializer(queryset, many=True, context=self.context)
return serializer.data
@dustinfarrisããã¯èªã¿åãå°çšãã£ãŒã«ãã«ãªããŸã...ãããããã¯æ©èœããŸãã
ãã®ã¹ã¬ããã«é¢é£ããŠãããšæãããåé¡ãçºçããŸããã ãã£ã«ã¿ãªã³ã°ããã¯ãšã³ãïŒç§ã®å Žåã¯Django FilterïŒãæå¹ã«ãªã£ãŠããå Žåãé²èŠ§å¯èœãªAPIã¯ã€ã³ã¿ãŒãã§ã€ã¹ã«Filters
ãã¿ã³ãè¿œå ããããããããŠã³ããã£ãŒã«ãã«èšå®ãããã¯ãšãªã»ãããå°éããªãããšãããããŸãã ç§ã«ã¯ããããã¹ãã ãšæããŸãã
äŸïŒ
class Item(models.Model):
project = models.ForeignKey(Project)
class ItemSerializer(serializers.ModelSerializer):
def __init__(self, *args, **kwargs):
request = kwargs.get('context', {}).get('request')
self.fields['project'].queryset = request.user.project_set.all()
super(ItemSerializer, self).__init__(*args, **kwargs)
äžèšã®äŸã§ã¯ãã¢ã€ãã ã®è¿œå /ç·šéãã©ãŒã ã®ãããžã§ã¯ãããããããŠã³ãæ£ãããããžã§ã¯ãã«å¶éãããŠããŸããããã¹ãŠãFilters
ããããããŠã³ã«è¡šç€ºãããŸãã
ãã€ã«ã¬ã³ã®ã¢ãããŒãã¯ç§ã«ãšã£ãŠã¯ããªãããŸããããŸãããã1察å€ã®é¢ä¿ã«å¯ŸããŠã®ã¿ã§ãã ããã§ãé¢ä¿ãManyToManyFieldã§ããã¢ãã«ã1ã€ãããŸãã ãã®å ŽåãMixinã¢ãããŒãã¯æ©èœããŸããã ãããã®ããã«ããã解決ããæ¹æ³ã¯ãããŸããïŒ
@fibbsã¯ã以äžãè¿œå ããããšã§ãã€ã«ã¬ã³ã®ã¢ãããŒããå€æŽããŸãã
if isinstance(field, serializers.ManyRelatedField):
method_name = 'filter_%s' % name
try:
func = getattr(self, method_name)
except AttributeError:
pass
else:
field.child_relation.queryset = func(field.child_relation.queryset)
ã©ããã誰ããããã«ã¯ãªãŒã³ãªãœãªã¥ãŒã·ã§ã³ãæäŸããinitã¡ãœããããããã³ã°ããããšãªãå¯èœã«ãªããŸããïŒ https ïŒ
ãã®ã¹ã¬ãããæŽæ°/éããããŠããªãã®ã¯ãªãã§ããïŒ
ãã®èª°ããç§ã§ã;ïŒ
è¯ãç¹ã§ããïŒ3605ããã§ã«ããã¥ã¡ã³ãã«ããã«ã€ããŠäœããè¿œå ããŠããã®ã§ããããéããŸãã
誰ããäœããæã£ãŠæ¥ãããšãã§ããã°ãç§ãã¡ã¯ãŸã ãã®éšåã®ãããªãæ¹åãæ€èšããŠããŸãã
RelatedFieldsã«get_queryset()
ã¡ãœãããååšããã®ã¯çŽ æŽãããããšã§ãã ãã¹ããããã·ãªã¢ã©ã€ã¶ãŒã«ãããããããšçŽ æŽãããã§ãããïŒ
å€åã ãããé²ãããã§ããïŒ :)
ãããŒ...ãããããããææžåãããŠããå Žåãæ£ããæ¹åã«ç§ãåããŠããã ããŸããïŒ ãããç解ããã®ã«é·ãæéãããããŸããïŒ
ãããç§ã®åèåé¡ã®èŠçŽã§ãïŒ
ãã®äŸã§ã¯ãã¢ãã«åã¯ãdeployedEnvsããšãHostãã§ãã
deployedEnvsã«ã¯ããã¹ãã¢ãã«ãžã®å€éšããŒãå«ãŸããŠããŸãïŒã€ãŸããå€ãã®deployedEnvsãåããã¹ããæãããšãã§ããŸãïŒã ãã¹ãã®PKã§ã¯ãªãHOSTã®fqdnãã£ãŒã«ãã衚瀺ããããã«ã·ãªã¢ã©ã€ã¶ãŒãå¿
èŠã§ããïŒéåžžã«åçŽãªãã®ã«ã¯ã¹ã©ã°é¢é£ã®ãã£ãŒã«ãã䜿çšããŸããïŒã ãŸããdeployedEnvãšã³ããªïŒPOSTïŒãäœæãããšãã«ãé¢é£ããHOST byFQDNãã£ãŒã«ãã®FKå€ãæ€çŽ¢ããŠãã¹ããæå®ã§ããããã«ããå¿
èŠããããŸããã äŸïŒäžèŽããhost.fqdnãã£ãŒã«ãã䜿çšããŠHostãªããžã§ã¯ãã®PKãæ€çŽ¢ããããšã«ããããã£ãŒã«ãhostïŒé¢é£ãããã¹ããªããžã§ã¯ãã®äžèŽããfqdnã«èšå®ïŒã䜿çšããŠdeployedEnvãäœæããŸãã
æ®å¿µãªãããããããããŠã³ããŒã«è¿ãããçµæããçŸåšã®ãŠãŒã¶ãŒãææãããã¹ããªããžã§ã¯ãã®éžæè¢ã ãã«å¶éããããšã¯ã§ããŸããã§ããã
ãããslugRelatedFieldã䜿çšããããã«é©åãããç§ã®ä¿®æ£ã³ãŒãã§ã
class UserHostsOnly(serializers.SlugRelatedField):
def get_queryset(self):
user = self.context['request'].user
queryset = Host.objects.filter(owner=user)
return queryset
class deployEnvSerializer(serializers.ModelSerializer):
host = UserHostsOnly(slug_field='fqdn')
ç§ã¯Djangoã«çŽ5åã®æ¬ãæã£ãŠããŸãïŒå¿ èŠã«å¿ããŠããããã¹ãŠããªã¹ãã§ããŸãïŒããŸãããã¬ãŒã ã¯ãŒã¯ã®ãã®ç¹å®ã®é å/æ©èœãæäœããæ¹æ³ã瀺ããªãã¡ã¬ã³ã¹ããã¹ãã¯ãããŸããã æåã¯äœããããããšæã£ããã§ãããïŒ ç§ãããããšããŠããããšãããããã®ããè¯ãæ¹æ³ã¯ãããŸããïŒ ãã®åé¡ã«ã€ããŠã®ã³ã¡ã³ããæ··ä¹±ãããªãããã«ãOOBãŸã§ãæ°è»œã«ãé£çµ¡ãã ããã ç§ã®ã³ã¡ã³ããèªãããã«æéãå²ããŠããããã¹ãŠã®äººã«æè¬ããŸãïŒdjangoåå¿è ãšããŠãããã¯æ¬åœã«ç解ããã®ãå°é£ã§ããïŒã
@Lcstyle
DRFã®åField
ïŒ Serializers
èªäœãå«ãïŒã«ã¯ãããŒã¿ãã·ãªã¢ã«åããããã®2ã€ã®ã³ã¢ã¡ãœããããããŸãïŒã€ãŸããJSONã¿ã€ããšPythonã¿ã€ãã®éïŒã
to_representation
-ããŒã¿ããã¢ãŠããã«ãªããŸãto_internal_value
-ãå
¥ã£ãŠãããããŒã¿æäŸããã¢ãã«ã®å€§ãŸããªæŠèŠã以äžã«ç€ºããŸãã以äžã¯ãRelatedFieldsãã©ã®ããã«æ©èœãããã®æŠèŠã§ãããSlugRelatedFieldã¯ç¹æ®ãªããŒãžã§ã³ã§ãã
class UserHostsRelatedField(serializers.RelatedField):
def get_queryset(self):
# do any permission checks and filtering here
return Host.objects.filter(user=self.context['request'].user)
def to_representation(self, obj):
# this is the data that "goes out"
# convert a Python ORM object into a string value, that will in turn be shown in the JSON
return str(obj.fqdn)
def to_internal_value(self, data):
# turn an INCOMING JSON value into a Python value, in this case a Django ORM object
# lets say the value 'ADSF-1234' comes into the serializer, you want to grab it from the ORM
return self.get_queryset().get(fqdn=data)
å®éã«ã¯ãéåžžãã»ãã¥ãªãã£ãªã©ïŒ django-guardian
ãrules
ãªã©ã䜿çšããå ŽåïŒã®ããã«ã get_queryset
ãŸãã¯to_internal_value
ã¡ãœããã®ããããã«äžé£ã®ãã§ãã¯ãå
¥ããããšèããŠããŸãã rules
ïŒãŸããå®éã®ORMãªããžã§ã¯ããååšããããšã確èªããŸãã
ããå®å šãªäŸã¯æ¬¡ã®ããã«ãªããŸã
from rest_framework.exceptions import (
ValidationError,
PermissionError,
)
class UserHostsRelatedField(serializers.RelatedField):
def get_queryset(self):
return Host.objects.filter(user=self.context['request'].user)
def to_representation(self, obj):
return str(obj.fqdn)
def to_internal_value(self, data):
if not isinstance(data, str):
raise ValidationError({'error': 'Host fields must be strings, you passed in type %s' % type(data)})
try:
return self.get_queryset().get(fqdn=data)
except Host.DoesNotExist:
raise PermissionError({'error': 'You do not have access to this resource'})
@ cancan101ãå°ãåã«æžããããšã«é¢ããŠïŒ
ãã®ã¹ã¬ããã«é¢é£ããŠãããšæãããåé¡ãçºçããŸããã ãã£ã«ã¿ãªã³ã°ããã¯ãšã³ãïŒç§ã®å Žåã¯Django FilterïŒãæå¹ã«ãªã£ãŠããå Žåãé²èŠ§å¯èœãªAPIã¯ã€ã³ã¿ãŒãã§ã€ã¹ã«[Filters]ãã¿ã³ãè¿œå ããããããããŠã³ããã£ãŒã«ãã«èšå®ãããã¯ãšãªã»ãããå°éããªãããšãããããŸãã ç§ã«ã¯ããããã¹ãã ãšæããŸãã
ç§ãèŠãéããããã¯ãŸã çå®ã§ãã ããã¯ãã«ã¹ã¿ã ãçµç±ããŠæ¹åããããšãã§ããŸãFilterset
ããŒã¿ããªãŒã¯ããŠããã®ForeignKeyãã£ãŒã«ãã®ãã£ãŒã«ãããç§ã¯ãŸã ããããèªåãã«è§£æ±ºãããã¹ãã ãšæã@tomchristieãšãã£ã«ã¿modelchoiceã¯å°éãã¹ãget_queryset
æ¹æ³ãã·ãªã¢ã©ã€ã¶ãŒã®ã«ã¹ã¿ã ãã£ãŒã«ã宣èšã®
ãããã«ãããè¿œå ã®ããã¥ã¡ã³ããå¿ èŠã«ãªããŸãã
ã«ã¹ã¿ã ãã£ã«ã¿ãŒã»ãããä»ããŠããã解決ããæ¹æ³ã以äžã«ææžåããŠããŸãã
ãµã³ãã«ã¯ãŒã¯ãšã³ããªãŒã¢ãã«ïŒ
class WorkEntry(models.Model):
date = models.DateField(blank=False, null=True, default=date.today)
who = models.ForeignKey(User, on_delete=models.CASCADE)
...
åºæ¬ã¢ãã«ãã¥ãŒã»ããïŒ
class WorkEntryViewSet(viewsets.ModelViewSet):
queryset = WorkEntry.objects.all().order_by('-date')
# only work entries that are owned by request.user are returned
filter_backends = (OnlyShowWorkEntriesThatAreOwnedByRequestUserFilterBackend, ...)
#
filter_fields = (
# this shows a filter dropdown that contains User.objects.all() - data leakage!
'who',
)
# Solution: this overrides filter_fields above
filter_class = WorkentryFilter
ã«ã¹ã¿ã FilterSetïŒåºæ¬ã¢ãã«ã®ãã¥ãŒã»ããã®filter_classãä»ããŠfilter_fields
ããªãŒããŒã©ã€ãããŸãïŒ
class WorkentryFilter(FilterSet):
"""
This sets the available filters and filter types
"""
# foreignkey fields need to be overridden otherwise the browseable API will show User.objects.all()
# data leakage!
who = ModelChoiceFilter(queryset=who_filter_function)
class Meta:
model = WorkEntry
fields = {
'who': ('exact',),
}
ããã«èšèŒãããŠããããã«åŒã³åºãå¯èœãªã¯ãšãªã»ããïŒ http ïŒ
def who_filter_function(request):
if request is None:
return User.objects.none()
# this solves the data leakage via the filter dropdown
return User.objects.filter(pk=request.user.pk)
@macolo
ãã®ã³ãŒããèŠãŠãã ããïŒ
ããã¯ããªããèšåããŠããããŒã¿æŒæŽ©ã®åé¡ãä¿®æ£ããŸãããïŒ ç§ã®æ€çŽ¢ãã£ãŒã«ãã¯é²èŠ§å¯èœãªAPIã«ååšããŸãããããã§ãçµæã¯ææè ã«ãã£ãŠãã£ã«ã¿ãªã³ã°ãããã¯ãšãªã»ããã«å¶éãããŸãã
class HostsViewSet(DefaultsMixin, viewsets.ModelViewSet):
search_fields = ('hostname','fqdn')
def get_queryset(self):
owner = self.request.user
queryset = Host.objects.filter(owner=owner)
return queryset
@Lcstyleãã¹ãããã£ã«ã¿ãªã³ã°ããããšã¯ããŠããŸãããé¢é£ãããã£ãŒã«ãã®ã€ã³ã¹ã¿ã³ã¹ïŒããšãã°ããã¹ãã®ææè ïŒããã£ã«ã¿ãªã³ã°ããããšããŠããŸãã
ç§ã¯RESTã§è§£æ±ºããããã®ç¹å®ã®åé¡ãèŠãŠããŸã...éåžžãäŸã¯request.user
åºã¥ããŠããŸãã ããå°ãè€éãªã±ãŒã¹ãæ±ãããã®ã§ããã
Company
ãæã€Employees
ããã Company
ã«ãã®æã®åŸæ¥å¡ã®å±æ§ããããšããŸãã
class Company(Model):
employee_of_the_month = ForeignKey(Employee)
...
class Employee(Model):
company = ForeignKey(Company)
ç§ã¯å¶éããããã«ãRESTã€ã³ã¿ãŒãã§ãŒã¹ããemployee_of_the_month
ããããšã«ãã£ãŠEmployee
ãšåãcompany.id
ã®ããã«Company
ã
ããã¯ç§ããããŸã§ã«æãã€ãããã®ã§ãã
class CompanySerializer(ModelSerializer):
employee_of_the_month_id = PrimaryKeyRelatedField(
source='employee_of_the_month',
queryset=Employee.objects.all())
def __init__(self, *args, **kwargs):
super(CompanySerializer, self).__init__(*args, **kwargs)
view = self.context.get('view', None)
company_id = None
if view and isinstance(view, mixins.RetrieveModelMixin):
obj = view.get_object()
if isinstance(obj, Company): # We could get the model from the queryset.
company_id = obj.id
q = self.fields['employee_of_the_month_id'].queryset
self.fields['employee_of_the_month_id'].queryset = q.filter(company_id=company_id)
...ãã®æ¹æ³ã¯æœè±¡åã§ãããã®ã§ããïŒ @nailgunã®https://github.com/encode/django-rest-framework/issues/1985#issuecomment-61871134ã«å°ãåºã¥ããŠã
ç§ã¯ãŸããç§ã¯å¯èœæ§ãèããŠããŸãvalidate()
ãã®employee_of_the_month
æºãããŠããããšããããšã«ãããäžèšæ§ç¯ãããã¯ãšãªã»ããget()
ã§ã¯ãšãªã»ããã«å¯ŸããŠã¯employee_of_the_month.id
ïŒ3605ãèŠããšãããã¯ãã£ãŒã«ãã®ã«ã¹ã¿ã ã·ãªã¢ã©ã€ã¶ãŒã§ãå®è¡ã§ããããšãããããŸããä»æã®åŸæ¥å¡ã®ä»£ããã«CEOã䜿çšããŸãããã
class CEOField(serializers.PrimaryKeyRelatedField):
def get_queryset(self):
company_id = None
view = self.context.get('view', None)
if view and isinstance(view, mixins.RetrieveModelMixin):
obj = view.get_object()
if isinstance(obj, Company):
dashboard_id = obj.id
return Employee.objects.filter(company_id=company_id)
ããã¯ãç¹å®ã®äŒç€Ÿã調ã¹ãŠããå Žåãé€ããŠãéžæ察象ã®ãªããžã§ã¯ããè¿ããªãããã«ç¹å¥ã«èšèšãããŠããŸãã èšãæããã°ãæ°ããäŒç€Ÿã¯ãäŒç€Ÿãèšç«ããããŸã§ããªããæã€ããšãã§ããªãåŸæ¥å¡ããããŸã§ãCEOãæã€ããšãã§ããŸããã§ããã
ãã®ã¢ãããŒãã§ã®ç§ã®å¯äžã®åŸæã¯ããããDRYer / genericã«ããããšãã§ããããã ãšããããšã§ãã
æãåèã«ãªãã³ã¡ã³ã
ãã®åçŽãªSerializerããã¯ã¹ã€ã³ã䜿çšããŠãé¢é£ãã£ãŒã«ãã®ã¯ãšãªã»ããããã£ã«ã¿ãªã³ã°ããŸããã
䜿ãæ¹ãç°¡åã§ãïŒ
ã©ãã§ããïŒ äœãåé¡ããããŸããïŒ