DRFの小ネタとか
この記事は Django Advent Calendar 2017 13日目の記事です。
DjangoRestFrameWorkの初心者向けの記事になります。
DRF便利ですよね。でも日本語の資料がなかったりして英語ばっかり読むの辛いですし、こんな時にどうしよう?みたいな悩みがちょくちょく出てくると思います。
そんな時の業務で得た豆知識集を書いていこうと思います。
正直。ググれば公式やstackoverflowなんかにでてくるネタではありますしベストな回答かどうかはわかりませんが。。。
前提としては主にModelSerializerの話をします
Selializerのfieldsから必要な項目だけ抽出したい
apiによって欲しい項目というものは当然異なってきます。
とはいえModelは広大になっていき全項目を返しているとデータ転送量はふくれあがるし、若干重くもなります。
だからといって用途毎Selializerを作っていたら XXMiniselializerとかXXsnipetSelializerとかよく分からないものがいっぱいできます。
そこで、今回は宣言した項目の中から必要なものだけ抽出して返せるような仕組みを考えて見たいと思います。
class AnimeSelializer(serializers.ModelSerializer):
def __init__(self, *args, **kwargs):
super(AnimeSelializer, self).__init__(*args, **kwargs)
try:
context = kwargs.get('context')
fields = context.get('fields', None)
if fields:
allowed = set(fields)
existing = set(self.fields.keys())
for field_name in existing - allowed:
self.fields.pop(field_name)
except AttributeError:
pass
class Meta:
model = Anime
fields = ('id', 'title', 'start_date', 'end_date', 'director', 'is_harem', 'is_robot', 'thumbnail',)
例えば欲しい項目だけquerystringでこんな風に渡してきたとして
xxx.com/anime/v1/anime?field=id&field=title
class AnimetListView(APIView):
def get(self, request):
fields = request.GET.getlist("field")
animes = Anime.objects.all().order_by('-id')
return Response(AnimeSelializer(animes, many=True, context=dict(fields=fields))
親の項目名を返したい
例えば、UserModelと一対一のprofileModelがあるとします。
当然usernameやemailなどuserに持っている項目はそれをそのまま返したいですよね。
こういう書き方もできますが、正直get_XXはあんまり書きたくないですよね
いまいちな書き方
class ProfileSerializer(serializers.ModelSerializer):
name = serializers.SerializerMethodField()
email = serializers.SerializerMethodField()
class Meta:
model = Anime
fields = ('id', 'name', 'email', 'birthday', )
def get_name(self, obj):
return obj.user.username
def get_email(self, obj):
return obj.user.email
さっきよりはすっきりした書き方
class ProfileSerializer(serializers.ModelSerializer):
name = serializers.CharField(source='user.username')
email = serializers.EmailField(source='user.email')
class Meta:
model = Anime
fields = ('id', 'name', 'email', 'birthday', )
すっきり書けますね(自分は最初user_usernameのように書いていて、上手くいかないなーと悩んでました
個人的にはfieldsにuser_username と書ければ一番良いのですが、そういう書き方はちょっとわからなかったです。
methodを制限したい
なんらかの事情でpostやputをされたくないapiはあると思います。
その際はこんな感じで制限を掛けます。
継承基を制限すれば大丈夫そうです。
悪意のある人間がいきなりdeleteメソッドを送ってきてもこれで大丈夫ですね!
class AnimeViewSet(generics.ListAPIView, generics.RetrieveAPIView):
queryset = Anime.objects.all()
serializer_class = AnimeSerializer
参考)
http://www.django-rest-framework.org/api-guide/generic-views/#concrete-view-classes
処理を追いかけたい!
DRFは記述量が少なくて済む代わりに裏側で落ちたりすると原因がよく分からないことがあります。
そんな時の追いかけ方です。
とりあえず裏側で走ってしまってよく分からない部分を明示的に呼ぶようにして、そこからデバック実行します。
まぁ、、中まで突っ込んでいくことは滅多にありませんが。
def list(self, request, *args, **kwargs):
return super().list(request, *args, **kwargs)
@transaction.atomic()
def retrieve(self, request, *args, **kwargs):
return super().retrieve(request, *args, **kwargs)
@transaction.atomic
def create(self, request, *args, **kwargs):
return super().create(request, *args, **kwargs)
@transaction.atomic
def update(self, request, *args, **kwargs):
return super().update(request, *args, **kwargs)
他にも業務上の小ネタ(特にnest関係)は結構ありますので、気がついたら更新していこうと思います
Author And Source
この問題について(DRFの小ネタとか), 我々は、より多くの情報をここで見つけました https://qiita.com/pro_proletariat/items/5fd7ad55bac9d8f7cb0a著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .