Ajutor cu django rest framework


(Stanciu Bogdan Mircea) #1

Sper că știe careva pe aici ceva Django (+ django rest framework)

Am creat două modele:

class Software(models.Model):
    version_name = models.CharField(max_length=5, unique=True)
    change_log = models.TextField(max_length=500)

    def __str__(self):
        return self.version_name
class Box(models.Model):
    software_key = models.ForeignKey(Software) # legătura cu modelul Software
    client_key = models.ForeignKey(Client) # folosit mai tarziu pentru un query

    field1 = models.CharField(max_length=100, default='wi-fi')
    field2 = models.CharField(max_length=125, unique=True)
    field3 = models.CharField(max_length=50, unique=True)

    def __str__(self):
        return self.field1

Modelul Box este legat de Software prin foreign key.

Am creat un serializer ce ma ajuta sa returnez toate campurile modelului Box in format json

class BoxSerializer(serializers.ModelSerializer):
    class Meta:
        model = Box
        fields = '__all__'

Valorile din model sunt returnate cu ajutorul unui view:

class BoxesListAPIView(ListAPIView):
    """view boxes of client id(from url param)"""
    serializer_class = BoxSerializer

    def get_queryset(self, *args, **kwargs):
        client = self.kwargs['client']

        queryset = Box.objects.filter(client_key=int(client))
        return queryset

Tot acest set-up imi oferă un răspuns de genul:

 {
        "id": 2,
        "field1": "valoare field 1",
        "field2": "valoare field 2",
        "field3": "valoare field 3",
        "client_key": 1,
        "software_key": 1,
    },

, un răspuns mai mult decât corect. Doar că eu imi doresc ca pentru câmpul software_key să imi returneze (și) altceva decât id-ul foreign-key-ului, ca în final să văd:

 {
        "id": 2,
        "field1": "valoare field 1",
        "field2": "valoare field 2",
        "field3": "valoare field 3",
        "client_key": 1,
        "software_key": valoarea din coloana `version_name`,
    },

Ce pot face?


(cosmos) #2

Nu poti sa incerci sa scrii un query in sql care sa iti ia acele date

Sau o intrebare mai buna
Ai o baza de date ?


(Stanciu Bogdan Mircea) #3

Chiar acum gasisem ceva pe net. Eu ce vreau să fac este de fapt un join. Django este conectat la MySql, deci în orice caz pot scrie un query și să îl execut direct. Daca găsesc o soluție mai eleganta o las și aici.


(cosmos) #4

Folosesti un orm ?

Eu mai lucrez in C# cu asp net mvc, iar pt baza de date mai folosesc un orm(Entity Framework). Pot sa scriu query-ul programatic(Linq) sau sql

:slight_smile:

au fost situatii in care am folosit sql pt ca era mai simplu !


(cosmos) #5

@mirceaciu, am gasit asta
https://docs.djangoproject.com/en/2.0/topics/db/sql/
si
http://blog.appliedinformaticsinc.com/how-to-perform-raw-sql-queries-in-django/

Toate orm-urile iti permit sa scrii query-uri raw :smiley:


(Horia Coman) #6

Amintirile de django sunt fuzzy. Dar in principiu poți accesa box.software_key și ar trebui sa fie o instanta corecta de Software (merita poate numit direct software). Trebuie doar sa mai faci ceva in serializare să obții json-ul corect din toate astea. Sigur are django o opțiune că e low-friction iar asta e un caz comun. Raw SQL e departe de ce-ți trebuie.


(cosmos) #7

Interesanta abordarea Django !


(Stanciu Bogdan Mircea) #8

Am ales django pentru că îmi ușurează munca de a pune pe picioare un backend/api.

Până acum am aflat că trebuie să fac altfel logica modelor. Box devine modelul principal de care se vor lega alte modele copil, prin foreign key și related_name:

class Box(models.Model):
    [...] # some fields
class ChildTable(models.Model):
    field = models.CharField(max_length=5)
    associated_box = models.ForeignKey('Box', related_name='child') # legatura cu Box
class LittleChildTable(models.Model):
    field = models.CharField(max_length=5)
    associated_box = models.ForeignKey('Box', related_name='littlechild') # legatura cu Box

În partea de sertizare selectez din modelul Box, astfel am să obțin și date (dacă doresc) din tabelele copil:

class BoxSerializer(serializers.ModelSerializer):
    child = ChildSerializer(many=True) # serializer creat separat
    littlechild = LittleChildSerializer(many=True) # serializer creat separat

    class Meta:
        model = Client
        fields = '__all__'

Acest set-up îmi ofera un json cu nested objects:

{
  "boxfield1"="",
  "boxfield2"="",
  "boxfield3"="",
  [...],
  "child": {
    "field": ""
 },
  "littlechild": {
    "field": ""
 },
}

Dacă selectez pornind de la un model copil primesc câmpurile sale și câmpul din părintele Box prin care se face legătura (pk în mod default).


(cosmos) #9

ma bucur ca ai rezolvat !

ps: python mi se pare usor si uneori te pune sa gandesti putin diferit pt s obtine simplitate in solutii :slight_smile: