How to set Email field as lookup_field in DRF?

I need user-detail url endpoint as api/email/[email protected]; api/email/[email protected], but it not works

If i add url field to serialiser class, then on user-list page i have exeption: Could not resolve URL for hyperlinked relationship using view name "user-email". You may have failed to include the related model in your API, or incorrectly configured thelookup_fieldattribute on this field.

Thats my code: serializers.py

class EmailSerializer(serializers.ModelSerializer):
    """
    Профиль пользователя
    """
    class Meta:
        model = User
        fields = ('url', 'email', )  
        read_only_fields = ('email', )
        extra_kwargs = {
            'url': {'view_name': 'user-email', 'lookup_field': 'email'}
        }

views.py

class RetrieveModelViewSet(mixins.RetrieveModelMixin,
                            mixins.ListModelMixin,
                            viewsets.GenericViewSet):
    """
    действия просмотр
    """
    pass

class EmailViewSet(RetrieveModelViewSet):
    queryset = User.objects.all()
    serializer_class = EmailSerializer
    lookup_field = 'email'

urls.py

router.register(r'email', views.EmailViewSet, 'email') 

Also i try clean email field by quote_plus: serializers.py

from urllib.parse import quote_plus
class EmailSerializer(serializers.ModelSerializer):
    """
    Профиль пользователя
    """
    email = quote_plus(serializers.EmailField(read_only=True))
    class Meta:
        model = User
        fields = ('url', 'email', )  
        read_only_fields = ('email', )
        extra_kwargs = {
            'url': {'view_name': 'user-email', 'lookup_field': 'email'}
        }

but i have error: TypeError: quote_from_bytes() expected bytes

Upvotes: 5

Views: 1956

Answers (2)

Georgie
Georgie

Reputation: 118

Same problem, I managed as below.

I would lookup with an email field, but impossible it use it in URL endpoints.

As the json from my API contains the good URL endpoints, with their related email, I query the json to get the URL endpoint. A kind of manual relationship:

import requests, json, subprocess

REQUEST_URL = 'http://127.0.0.1:8000/users/?format=json'
login = 'DjangoLogin'
password = 'DjangoPassWord'
response = requests.get(REQUEST_URL, auth=(login, password))

json_data = response.text.encode('utf-8', 'ignore')
readable_json = json.loads(json_data)

email_reference = YOUR_EMAIL_FIELD
new_firstname = YOUR_FIRSTNAME_FIELD
new_lastname = YOUR_LASTNAME_FIELD

match_count = 0

for results in readable_json['results']:
    match_count += 1
    if results['email'] == email_reference and results['email'] is not None and match_count != 1:
        my_url = results['url']

        my_cmd = 'http -a ' + login + ':' + password + ' PUT ' + my_url + ' firstname="' + new_firstname + '"' + ' lastname="' + new_lastname + '"'

        p = subprocess.Popen(my_cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        out, err = p.communicate()

More explanation in my website: https://hg-map.fr/astuces/69-django-rest-api

Upvotes: 0

miloslu
miloslu

Reputation: 454

By default "." is not allowed in lookup regex (django-rest-framework.org/api-guide/routers), you should change "lookup_value_regex" field to allow punctuation (".") character. Default is this '[^/.]+', so you need to remove punctuation (".") character from '[^/]+'.

Upvotes: 5

Related Questions