Aracıyı (model aracılığıyla) Django Rest Framework'teki yanıtlara dahil et


110

M2m / modellerle başa çıkma ve bunların django dinlenme çerçevesinde sunumu hakkında bir sorum var. Klasik bir örnek alalım:

models.py:

from django.db import models

class Member(models.Model):
    name = models.CharField(max_length = 20)
    groups = models.ManyToManyField('Group', through = 'Membership')

class Group(models.Model):
    name = models.CharField(max_length = 20)

class Membership(models.Model):
    member = models.ForeignKey('Member')
    group = models.ForeignKey('Group')
    join_date = models.DateTimeField()

serializers.py:

imports...

class MemberSerializer(ModelSerializer):
    class Meta:
        model = Member

class GroupSerializer(ModelSerializer):
    class Meta:
        model = Group

views.py:

imports...

class MemberViewSet(ModelViewSet):
    queryset = Member.objects.all()
    serializer_class = MemberSerializer

class GroupViewSet(ModelViewSet):
    queryset = Group.objects.all()
    serializer_class = GroupSerializer

Bir Üyenin bir örneğini ALIRKEN, tüm üye alanlarını ve ayrıca gruplarını başarıyla alıyorum - ancak Üyelik modelinden gelen ekstra ayrıntılar olmadan yalnızca grupların ayrıntılarını alıyorum.

Başka bir deyişle şunları almayı bekliyorum :

{
   'id' : 2,
   'name' : 'some member',
   'groups' : [
      {
         'id' : 55,
         'name' : 'group 1'
         'join_date' : 34151564
      },
      {
         'id' : 56,
         'name' : 'group 2'
         'join_date' : 11200299
      }
   ]
}

Not join_date .

Elbette bununla ilgili Django Rest-Framework resmi sayfası da dahil olmak üzere pek çok çözümü denedim ve hiç kimse bu konuda düzgün bir cevap vermiyor - bu ekstra alanları dahil etmek için ne yapmam gerekiyor? Bunu django-tastypie ile daha açık buldum ama başka sorunlar yaşadım ve rest-framework'ü tercih ettim.



8
Bu lezzetli turta için, Django Rest Framework ile çalışıyorum.
mllm

Yanıtlar:


139

Peki ya .....

MemberSerializer'ınızda aşağıdaki gibi bir alan tanımlayın:

groups = MembershipSerializer(source='membership_set', many=True)

ve ardından üyelik serileştiricinizde şunu oluşturabilirsiniz:

class MembershipSerializer(serializers.HyperlinkedModelSerializer):

    id = serializers.Field(source='group.id')
    name = serializers.Field(source='group.name')

    class Meta:
        model = Membership

        fields = ('id', 'name', 'join_date', )

Bu, kaynağında istediğiniz üyeliğe sahip serileştirilmiş bir değer, gruplar yaratmanın genel etkisine sahiptir ve ardından görüntülemek istediğiniz bitleri çıkarmak için özel bir serileştirici kullanır.

DÜZENLEME: @bryanph tarafından yorumlandığı gibi, DRF 3.0'da serializers.fieldolarak yeniden adlandırıldı serializers.ReadOnlyField, bu nedenle bu şöyle olmalıdır:

class MembershipSerializer(serializers.HyperlinkedModelSerializer):

    id = serializers.ReadOnlyField(source='group.id')
    name = serializers.ReadOnlyField(source='group.name')

    class Meta:
        model = Membership

        fields = ('id', 'name', 'join_date', )

herhangi bir modern uygulama için


2
fyi, bunun birçok çeşidini denedim ve bunu çalıştıramıyorum. Bu resmi belgelerde yok mu? Üyelik_ kümesi nerede tanımlanır?
kil

3
membership_setÜye için varsayılan ilgili isimdir -> Üyelik
dustinfarris

Benim için işin püf noktası "üyelik_ kümesi" adını keşfetmekti. Açıkça "ilişkili" adı olmayan bir geçiş modelim vardı, bu yüzden Django Many to Many'daki belgeleri okuyarak adını tahmin etmek zorunda kaldım .
miceno

bu harika çalışıyor, ipucu için teşekkürler. Bununla birlikte, bu durumda DRF'nin biraz mantıksız olduğunu düşünüyorum çünkü sınıf Üyesi, gruplar adı verilen bir m2m alanını zaten tanımlıyor ve bu çözüm serileştiricideki alanı, geçiş modelinden ters ilişkiye işaret etmeye zorlayarak geçersiz kılıyor gibi görünüyor. DRF uygulama ayrıntılarıyla pek ilgilenmiyorum, ancak muhtemelen model iç gözlemle otomatik olarak teslim edilebilir. sadece biraz düşünmek için yiyecek :)
gru

Bunun DRF'nin en son sürümüyle çalışıp çalışmadığını bize bildirebileceğiniz herhangi bir durum var mı? Ya da en azından hangi sürümü kullandığınızı söyleyin? DRF'nin geçiş alan modelini döndürmesini sağlayamıyorum - her zaman orijinal ilişkiyle sonuçlanır (Üyelik yerine - her zaman Grubu döndürür).
Andrey Cizov

18

Bu sorunla karşı karşıyaydım ve çözümüm (DRF 3.6 kullanarak) nesne üzerinde SerializerMethodField kullanmak ve Üyelik tablosunu şu şekilde açıkça sorgulamaktı:

class MembershipSerializer(serializers.ModelSerializer):
    """Used as a nested serializer by MemberSerializer"""
    class Meta:
        model = Membership
        fields = ('id','group','join_date')

class MemberSerializer(serializers.ModelSerializer):
    groups = serializers.SerializerMethodField()

    class Meta:
        model = Member
        fields = ('id','name','groups')

    def get_groups(self, obj):
        "obj is a Member instance. Returns list of dicts"""
        qset = Membership.objects.filter(member=obj)
        return [MembershipSerializer(m).data for m in qset]

Bu, her bir diktenin MembershipSerializer'dan serileştirildiği grup anahtarı için bir dikt listesi döndürecektir. Yazılabilir hale getirmek için, MemberSerializer'da kendi oluşturma / güncelleme yönteminizi tanımlayabilirsiniz; burada girdi verileri üzerinde yineleme yapabilir ve Üyelik modeli örneklerini açıkça oluşturabilir veya güncelleyebilirsiniz.


-4

NOT: Bir Yazılım Mühendisi olarak, Mimarileri kullanmayı seviyorum ve Geliştirme için Katmanlı Yaklaşım üzerinde derinlemesine çalıştım, bu yüzden buna Katmanlara Saygı ile Cevap vereceğim.

Sorunu anladığım kadarıyla, İşte Çözüm modelleri.py

class Member(models.Model):
    member_id = models.AutoField(primary_key=True)
    member_name = models.CharField(max_length = 

class Group(models.Model):
    group_id = models.AutoField(primary_key=True)
    group_name = models.CharField(max_length = 20)
    fk_member_id = models.ForeignKey('Member', models.DO_NOTHING, 
                             db_column='fk_member_id', blank=True, null=True)

class Membership(models.Model):
    membershipid = models.AutoField(primary_key=True)
    fk_group_id = models.ForeignKey('Group', models.DO_NOTHING, 
                             db_column='fk_member_id', blank=True, null=True)
    join_date = models.DateTimeField()

serializers.py

import serializer

class AllSerializer(serializer.Serializer):
    group_id = serializer.IntegerField()
    group_name = serializer.CharField(max_length = 20)
    join_date = serializer.DateTimeField()

CustomModels.py

imports...

    class AllDataModel():
        group_id = ""
        group_name = ""
        join_date = ""

BusinessLogic.py

imports ....
class getdata(memberid):
    alldataDict = {}
    dto = []
    Member = models.Members.objects.get(member_id=memberid) #or use filter for Name
    alldataDict["MemberId"] = Member.member_id
    alldataDict["MemberName"] = Member.member_name
    Groups = models.Group.objects.filter(fk_member_id=Member)
    for item in Groups:
        Custommodel = CustomModels.AllDataModel()
        Custommodel.group_id = item.group_id
        Custommodel.group_name = item.group_name
        Membership = models.Membership.objects.get(fk_group_id=item.group_id)
        Custommodel.join_date = Membership.join_date
        dto.append(Custommodel)
    serializer = AllSerializer(dto,many=True)
    alldataDict.update(serializer.data)
    return alldataDict

Teknik olarak, Veri Erişim Katmanından Filtrelenmiş Nesneleri döndüren İsteği Veri Erişim Katmanına iletmeniz gerekirdi, ancak Soruyu Hızlı Bir Şekilde Yanıtlamam gerektiğinden, İş Mantığı Katmanındaki Kodu ayarladım!


1
Bu, Rest API geliştirmelerimin çoğu için kullandığım Tam Özelleştirilmiş bir Yaklaşım, çünkü Django Rest Framework oldukça esnek olmasına rağmen Bounds ile çalışmanın hayranı değilim!
Syed Faizan

2
Bu çok fazla tasarlanmış bir waaaay, ayrıca DRF bile kullanmıyor.
michauwilliam
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.