2015-11-14 8 views
9

Czy lepiej użyć relacji zagnieżdżonych lub pola PrimaryKeyRelated, jeśli masz dużo danych?django-REST: Zagnieżdżone relacje vs PrimaryKeyRelatedField

Mam model o głębokich relacjach.
Dla uproszczenia nie dodałem kolumn.

Model:

Model

USECASE:

  1. Użytkownik tworzy 1 Workoutplan z 2 treningi i 3 WorkoutExercises.
  2. Użytkownik tworzy 6 zestawów dla każdego ćwiczenia Ćwiczenie/Ćwiczenie.
  3. Użytkownik rozpoczyna trening> new FinishedWorkout jest tworzony
  4. Użytkownik ma pierwsze ćwiczenie i wchodzi zużyte ciężarów> new FinishedWorkoutExercise z FinishedSet jest tworzony

Pytanie:

Chcę śledzić postęp za każdy trening> trening> ćwiczenie. Więc z czasem użytkownik może skończyć dziesiątki ćwiczeń, a więc setki, jeśli zestawy są już w bazie danych.

Jeśli teraz używam relacji zagnieżdżonych, mogę załadować wiele danych, których nie potrzebuję. Ale jeśli używam PrimaryKeyRelatedFields, muszę załadować wszystkie potrzebne dane osobno, co oznacza więcej wysiłku w moim interfejsie.

Która metoda jest preferowana w takiej sytuacji?

Edit:
Jeśli używam PrimaryKeyRelatedFields jak mogę odróżnić jeśli np Treningi w Workoutplan to tablica z kluczami podstawowymi lub tablica z załadowanymi obiektami?

+0

gdzie jest kod? – dnozay

+0

Myślałem, że kod nie jest konieczne, ponieważ zmienia NestedRel. do PrimaryKeyRelatedEntities to tylko kilka linii trywialnego kodu w modelu django. A pobieranie na front-end jest prawie takie samo dla obu. – Altoyyr

Odpowiedz

1

Jeśli używasz PrimaryKeyRelatedField, będziesz miał duże przeciążenie zwrócenia się do niezbędnych danych w interfejsie

W twoim przypadku, chciałbym stworzyć konkretne serializers z pól chcesz (za pomocą atrybutu Meta.fields). Nie załadujesz niepotrzebnych danych, a frontend nie będzie wymagał więcej danych z backendu.

Potrafię napisać przykładowy kod, jeśli potrzebujesz więcej informacji.

+0

Zgadzam się. Mam fragment, który pozwala ci dynamicznie ładować serializery z obiektu, dzięki czemu twój zestaw wie kiedy użyć, powiedzmy, WorkoutCreateSerializer zamiast WorkoutListSerializer. Załaduję to tutaj, gdy dostanę się na mój komputer za kilka godzin. –

0

Przejdę do pytania dotyczącego serializerów w ciągu sekundy, ale przede wszystkim i do wyjaśnienia. Jaki jest cel posiadania zduplikowanych modeli jako Trening/Ukończony trening, Zestaw/Gotowy zestaw, ...?

Dlaczego nie ...

class Workout(models.Model): 
    #...stuff... 
    finished = models.DateTimeField(null=True, blank=True) 
    #...more stuff... 

Następnie można po prostu ustawić datę gotowy na trening, kiedy to zrobić.

Teraz, w odniesieniu do pytania. Proponuję myśleć o interakcji użytkownika.Jakie części front-endu próbujesz zapełnić? W jaki sposób dane są powiązane i w jaki sposób użytkownik miałby do niego dostęp?

Powinieneś pomyśleć o parametrach, które wyszukujesz w DRF. Można wysłać datę i oczekują treningi zakończone w określonym dniu:

// This example is done in Angular, but you get the point... 
var date= { 
    'day':'24', 
    'month':'10', 
    'year':'2015' 
}; 
API.finishedWorkout.query(date).$promise 
.then(function(workouts){ 
    //...workouts is an array of workout objects... 
}); 

Viewset ...

class FinishedWorkoutViewset(viewsets.GenericAPIView,mixins.ListModelMixin): 
    serializer_class = FinishedWorkOutSerializer 
    queryset = Workout.objects.all() 
    def list(self, request): 
     user = self.request.user 
     day = self.data['day']; 
     month = self.data['month']; 
     year = self.data['year']; 
     queryset = self.filter_queryset(self.get_queryset().filter(finished__date=datetime.date(year,month,day)).filter(user=user)) 
     page = self.paginate_queryset(queryset) 
     serializer = self.get_serializer(queryset, many=True) 
     return response.Response(serializer.data) 

I wówczas FinishedWorkoutSerializer może tylko mieć cokolwiek chcesz pola dla danego typu pytanie.

To pozostawia wiele bardzo specyficznych adresów URL, co nie jest wcale takie wspaniałe, ale można użyć konkretnych serializerów dla tych interakcji i jesteś także otwarty na dynamiczną zmianę filtru, w zależności od tego, jakie parametry są self.data.

Istnieje również prawdopodobieństwo, że możesz chcieć filtrować różnie w zależności od metody, która jest wywoływana, np. Chcesz wyświetlić tylko aktywne ćwiczenia, ale jeśli użytkownik zapyta o konkretne ćwiczenie, chcesz, aby miał do niego dostęp (zauważ, że obiekt ćwiczenia powinien mieć atrybut models.BooleanField "aktywny").

class ExerciseViewset(viewsets.GenericViewSet, mixins.RetrieveModelMixin, mixins.ListModelMixin): 
    serializer_class = ExerciseSerializer 
    queryset = Exercise.objects.all() 
    def list(self, request): 
     queryset = self.filter_queryset(self.get_queryset().filter(active=True)) 
     page = self.paginate_queryset(queryset) 
     serializer = self.get_serializer(queryset, many=True) 
     return response.Response(serializer.data) 

Teraz masz różne obiekty pojawiają się na tym samym URL, w zależności od akcji. Jest trochę bliżej tego, czego potrzebujesz, ale nadal używasz tego samego serializera, więc jeśli potrzebujesz ogromnego obiektu zagnieżdżonego na retrieve(), dostaniesz też ich kilka, gdy list().

Aby zachować listę skrótów i szczegółów zagnieżdżonych, należy użyć różnych serializerów.

Załóżmy, że chcesz wysyłać tylko atrybuty "pk i name, gdy są one na liście, ale za każdym razem, gdy ćwiczenie jest sprawdzane, nie możesz przesłać wszystkich powiązanych obiektów" Ustaw "uporządkowanych wewnątrz tablicy" Treningów " ...

# Taken from an SO answer on an old question... 
class MultiSerializerViewSet(viewsets.GenericViewSet): 
    serializers = { 
     'default': None, 
    } 
    def get_serializer_class(self): 
     return self.serializers.get(self.action, self.serializers['default']) 


class ExerciseViewset(MultiSerializerViewSet, mixins.RetrieveModelMixin, mixins.ListModelMixin): 
    queryset = Exercise.objects.all() 
    serializers = { 
     'default': SimpleExerciseSerializer, 
     'retrieve': DetailedExerciseSerializer 
    } 

Wtedy twój serializers.py może wyglądać trochę jak ...

#------------------Exercise 
#--------------------------Simple List 
class SimpleExerciseSerializer(serializers.ModelSerializer): 
    class Meta: 
     model Exercise 
     fields = ('pk','name') 

#--------------------------Detailed Retrieve 
class ExerciseWorkoutExerciseSetSerializer(serializers.ModelSerializer): 
    class Meta: 
     model Set 
     fields = ('pk','name','description') 

class ExerciseWorkoutExerciseSerializer(serializers.ModelSerializer): 
    set_set = ExerciseWorkoutExerciseSetSerializer(many=True) 
    class Meta: 
     model WorkoutExercise 
     fields = ('pk','set_set') 

class DetailedExerciseSerializer(serializers.ModelSerializer): 
    workoutExercise_set = exerciseWorkoutExerciseSerializer(many=True) 
    class Meta: 
     model Exercise 
     fields = ('pk','name','workoutExercise_set') 

ja tylko rzucając wokół spraw i atrybutów, które prawdopodobnie nie mają sensu w modelu ruchu, ale Mam nadzieję, że to jest pomocne.

P.S .; Sprawdź, w jaki sposób Java znalazła się na końcu: p "ExcerciseServiceExcersiceBeanWorkoutFactoryFactoryFactory"