Bienvenue sur IndexError.

Ici vous pouvez poser des questions sur Python et le Framework Django.

Mais aussi sur les technos front comme React, Angular, Typescript et Javascript en général.

Consultez la FAQ pour améliorer vos chances d'avoir des réponses à vos questions.

Comment modifier le champs de recherche (ID par défaut) dans l'url des données?

+2 votes

Dans DRF pour accédez a une donnée précise, du moins dans mon interface il faut que j'appelle l'URL suivante :

https://server/api/type_data/id

Grâce à ça j'accède à la ligne de ma table dont l'ID est spécifié, que ce soit via l'API ou en json.

Comment est-ce que je pourrais faire pour remplacer ID par un autre champ contenu dans la table tel qu'un champ name?

Edit : D'après ce que j'ai vu, ça aurait avoir avec la pagination, du coup j'ai créer une custom classe pagination ou je change le page_query_param:

class CustomPaginationClass(PageNumberPagination):
    page_query_param = 'licensenumber'

Et dans ma Viewset j'ai ajouté ça :

class LicensingContractViewSet(viewsets.ModelViewSet):
    queryset = LicensingContract.objects.all()
    serializer_class = LicensingContractSerializer
    pagination_class = CustomPaginationClass

Mais ça ne fonctionne toujours pas, je ne sais pas si c'est juste le paramètre que j'utilise qui n'est pas bon ou mon implémentation qui est mauvaise.

Edit : Je rouvre le sujet car c'est totalement lié, en effet, il s'avère que pour certain besoin, je dois accéder au données via deux paramètres différent dans l'url à savoir l'id et le champ name.

De cette manière là :

https://server.example.com/api/license/id
https://server.example.com/api/license/name

j'ai regarder la documentation de django rest framework (http://www.django-rest-framework.org/api-guide/generic-views/#creating-custom-mixins)

Et j'ai donc créer ma classe mixin :

class MultipleFieldLookupMixin(object):
    def get_object(self):
        queryset = self.get_queryset()  # Get the base queryset
        print queryset
        queryset = self.filter_queryset(queryset)  # Apply any filter backends
        print queryset
        filter = {}
        for field in self.lookup_fields:
            filter[field] = self.kwargs[field]
        return get_object_or_404(queryset, **filter)  # Lookup the object

Puis j'ai modifier ma vue de cette manière :

class LicensingContractViewSet(MultipleFieldLookupMixin, viewsets.ModelViewSet):
    queryset = LicensingContract.objects.all()
    serializer_class = LicensingContractSerializer
    lookup_fields = ('id', 'licensenumber')

Le problème est le suivant, l'attribut self.kwargs dans ma mixin ne contient que l'élément pk (Primary Key). Et impossible de savoir comment modifier ça. Je ne sais pas si c'est parceque j'utilise une ViewSet au lieu d'une RetrieveAPIView comme indiquer dans la doc, d'après mes tests je dirais que non, puisque même son utilisation ne permet pas de régler le soucis.

demandé 19-Fev-2016 par Takka (242 points)
edité 25-Fev-2016 par Takka

2 Réponses

+3 votes
 
Meilleure réponse

Je commence seulement moi même avec DRF, mais j'ai eu le même problème, donc voici ce que j'ai fait.

Sur ton ViewSet tu peux simplement déclarer le "lookup_field". La doc dit ceci:

lookup_field - The model field that should be used to for performing object lookup of individual model instances. Defaults to 'pk'.

Donc ta classe devrais ressembler à

class LicensingContractViewSet(viewsets.ModelViewSet):
    queryset = LicensingContract.objects.all()
    serializer_class = LicensingContractSerializer
    lookup_filed = 'licensenumber'

Mais attention, comme le dit aussi la doc, si tu utilises un HyperlinkedModelSerializer tu dois aussi définir le lookup_field comme paramètre du field *url*

Note that when using hyperlinked APIs you'll need to ensure that both the API views and the serializer classes set the lookup fields if you need to use a custom value

Ton serializer aura alors cette tête là

class LicensingContractSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = LicensingContract
        extra_kwargs = {
            'url': {'lookup_field': 'licensenumber'}
        }

Comme expliqué dans la doc sur les HyperlinkedModelSerializer

Pour le paginator, je ne sais pas s'il y a besoin de le définir. Moi je n'ai pas eu besoin de le faire en tout cas.

répondu 20-Fev-2016 par benjamin (394 points)
sélectionné 25-Fev-2016 par Takka
0 votes

Je me suis permis de rouvrir le sujet puisque le soucis est le même mais pour accéder au données via deux attributs distincts dans l'url. L'explication est dans l'edit du premier message.

Edit : je vais mettre ma réponse ici, puisque j'ai réussi en bidouillant de manière très sale à faire ce que je voulais.

Il s'avère que la variable self.kwargs dans le mixin contient la valeur passer en paramètre de l'url, dans mon cas par exemple pour :

http://server.example.com/api/contract/107

Self.kwargs contenait 107. J'avais donc deux champs a utiliser pour pouvoir accédez à mes données, un champs id, donc uniquement des chiffre et un champ licensenumber contenant 17 caractère, uniquement des chiffres et des lettres majuscules.

J'ai donc procéder avec une regex dans le mixin, et je n'ai même plus besoin du champ lookup_fields dans la vue. C'est sale, mais ça fonctionne.

class MultipleFieldLookupMixin(object):
    def get_object(self):
        queryset = self.get_queryset()  # Get the base queryset
        queryset = self.filter_queryset(queryset)  # Apply any filter backends
        filter = {}
        if re.match(r'[A-Z0-9]{17}', self.kwargs['pk']):
            filter['licensenumber'] = self.kwargs['pk']
        else:
            filter['id'] = self.kwargs['pk']
        return get_object_or_404(queryset, **filter)  # Lookup the object


class LicensingContractViewSet(MultipleFieldLookupMixin, viewsets.ModelViewSet):
    queryset = LicensingContract.objects.all()
    serializer_class = LicensingContractSerializer
répondu 25-Fev-2016 par Takka (242 points)
edité 25-Fev-2016 par Takka
...