I have 2 custom validation functions created using packages from PyPI, I want to inlcude them in my serializers.py in my django project before converting it to JSON using rest. Problem is i dont know where or how to put the functions in such that the code will run through it. Here is my code:
enter image description here(this is how im adding users right now, using the model's fields ive registered)
Here is my code:
/* serializers.py */
import re
import phonenumbers
from rest_framework import serializers
from phonenumbers import carrier
from validate_email import validate_email
class basicSerializer(serializers.Serializer):
emailplus = serializers.EmailField()
country = serializers.CharField(max_length=2)
phone_number = serializers.CharField(max_length=100)
def validate_emailplus(self):
email = self.validated_data.get("email")
if not validate_email(email, check_mx=True, verify=True):
raise serializers.ValidationError("Invalid email")
return email
/* views.py */
from django.shortcuts import render
from django.http import HttpResponse
from django.shortcuts import get_object_or_404
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from .models import basic
from .serializers import basicSerializer
class basicList(APIView):
def get(self, request):
basic1 = basic.objects.all()
serializer = basicSerializer(basic1, many=True)
return Response(serializer.data)
def post(self):
pass
As you can see I am not using models.py anymore and serializers.py as some sort of model with the given email and phone fields. In order for my function to work (which is not at the moment), it needs to use get() method from the entered data and do validate_email to know if the email exists. Please tell me what changes should be made, i do not know if the problem is with views.py which still uses models.py or if i should register the serializer as a model?
To run your validations, you must call serializer.is_valid(), however, that requires data to be passed to the serializer not instances. The logic behind this is that drf validates data coming in not data already stored in your DB
Correct logic
Considerations
It looks like you are implementing a list view, but you are validating the email address, which is probably not what you intended to do in the first place. I am guess you want to validate email on create.
You can make use of drf's generic views and mixins such as GenericViewSet, ListModelMixin, and ListModelMixin
I think you have a type in validate_emailplus where you try to get the field email while the serializer declares it as emailplus
You seem not to be following PEP-8 (style guide for Python)
serializers.py
import re
import phonenumbers
from rest_framework import serializers
from phonenumbers import carrier
from validate_email import validate_email
class BasicSerializer(serializers.Serializer):
emailplus = serializers.EmailField()
country = serializers.CharField(max_length=2)
phone_number = serializers.CharField(max_length=100)
def validate_emailplus(self):
email = self.validated_data.get("emailplus")
if not validate_email(email, check_mx=True, verify=True):
raise serializers.ValidationError("Invalid email")
return email
views.py
from rest_framework import mixins, viewsets
class BasicViewSet(
viewsets.GenericViewSet,
mixins.ListModelMixin,
mixins.CreateModelMixin,
):
queryset = Basic.objects.all()
serializer_class = BasicSerializer
For a better understanding of how viewset and mixins work, I recommend checking their implementation
Validation in Admin site
From the screenshot you added, it looks like you are trying to validate in the admin site, for that consider the below code:
models.py
class Basic(models.Model):
...
def clean(self):
if not validate_email(self.email, check_mx=True, verify=True):
raise ValidationError("Invalid email")
This works because Django admin generates forms based on your models and then the forms call full_clean() on the model, which calls clean()
Related
I created a serializer and an API endpoint so I can retrieve some data from a Django DB in my React app but getting this error message:
AttributeError: 'ProgrammingChallengesView' object has no attribute 'get'
Here is my models.py:
#creating programming challenges
class ProgrammingChallenges(models.Model):
challenge_id = models.AutoField(primary_key=True)
challenge_name = models.CharField(max_length=200)
challenge_description = models.TextField()
challenge_expectations = models.TextField()
my serializer:
from accounts.models import ProgrammingChallenges
...
class ProgrammingChallengesView(serializers.ModelSerializer):
class Meta:
model = ProgrammingChallenges
fields = '__all__'
and my urls.py:
path('api/programming_challenges/', ProgrammingChallengesView, name='programming_challenges'),
Thanks to the comments; I clearly didn't understand that a serializer only transforms my data to make it available through an API. I still had to create a view for my API's endpoint.
I opted to create a ReadOnlyModelView because I only want to GET data from this endpoint.
Here is what I wrote in my views:
class ProgrammingChallengesView(ReadOnlyModelViewSet):
serializer_class = ProgrammingChallengesSerializer
queryset = ProgrammingChallenges.objects.all()
#action(detail=False)
def get_list(self, request):
pass
and in my urls.py:
path('api/programming_challenges/', ProgrammingChallengesView.as_view({'get':'list'}), name='programming_challenges'),
I think you shouldn't hurry read the docs again. You are trying to use serializers as views.
Models - are representation of db tables as class.
Serializer serializes the data to json.
View accepts the reqeust from client and returns a Response.
Code shoudld be:
models.py
class ProgrammingChallenge(models.Model):
name = models.CharField(max_length=200)
description = models.TextField()
expectations = models.TextField()
Your model name should be ProgrammingChallenge(singular) not ProgrammingChallenges(plural).
You should't add prefix challenge before all field names. Because we already know that the fields are in a Model called ProgrammingChallenge. And it is easy to access them like ProgrammingChallenge.name than ProgrammingChallenge.challenge_name
You don't have to add field id manually. Django model automatically adds id field as primary_key
serializer.py
from accounts.models import ProgrammingChallenge
...
class ProgrammingChallengeSerializer(serializers.ModelSerializer):
class Meta:
model = ProgrammingChallenge
fields = '__all__'
No problem in serialize.
Now, main problem is you don't have any view. You definetly read docs. You can use APIView, generic views or viewset. In this example i'm going to use ViewSet that handles CRUD operations built in.
viewsets.py
from rest_framework.viewsets import ModelViewSet
from .models import ProgrammingChallenge
from .serializers import ProgrammingChallengSerializer
class ProgrammingChallengViewSet(ModelViewSet):
queryset = ProgrammingChallenge.objects.all()
serializer_class = ProgrammingChallengeSerializer
urls.py
from rest_framework.routers import SimpleRouter
from .viewsets import ProgrammingChallenge
router = SimpleRouter()
router.register('challengr', ProgrammingChallengeViewSet)
urlpatterns = router.urls
Another advantage of using viewset, it also generate all endpoint for it's CRUD methods automatically via routes.
It should help you to start your first project.
AGAIN, READ THE DOCS!
When I access the base URL of http://127.0.0.1:8000/ I get the following error
ImproperlyConfigured at /
Could not resolve URL for hyperlinked relationship using view name "wallet-detail". You may have failed to include the related model in your API, or incorrectly configured the `lookup_field` attribute on this field.
When I try to access the admin URL it works fine but when I access my data URL which is http://127.0.0.1:8000/wallets I get a 404 error page not found?
This is my serializers.py file
from rest_framework import serializers
from .models import Wallet
class WalletSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Wallet
fields = ('__all__')
My views.py file is the following
from django.shortcuts import render
from rest_framework import viewsets
from rest_framework.response import Response
from rest_framework.decorators import api_view
from .serializers import WalletSerializer
from .models import Wallet
#api_view(['GET'])
def getData(request):
queryset = Wallet.objects.all()
serializer = WalletSerializer(queryset, many=True, context={'request': request})
return Response(serializer.data)
This is my Models.py file
from django.db import models
class Wallet(models.Model):
raddress = models.CharField(max_length=60)
def __str__(self):
return self.raddress
I was using a simple class in my views.py file instead of 'GET' functions which I am doing now and I was also using routers in my urls.py file but I removed all that so I could create CRUD functions but I face this problem now
I've been trying all sorts of method but still cant seem to get this task done even through asking here with my previous questions. The problem is, I am trying to convert my data that is entered by the user on django's admin page to json data using rest. But before converting the data to json, I have 2 custom functions that validates the email and phone number fields entered by the user that uses packages from PyPI and I need these functions to run through the entered text values on the admin page. I dont know where to put my 2 functions in my python files, whether in models.py or serializers.py, Ive actually tried both ways but cant seem to get it to work.
/* models.py */
import re
import phonenumbers
from django.db import models
from phonenumbers import carrier
from validate_email import validate_email
class razer(models.Model):
emailplus = models.EmailField()
country = models.CharField(max_length=2)
phone_number = models.CharField(max_length=100)
def clean_emailplus(self):
email = self.cleaned_data.get("emailplus")
if not validate_email(email, check_mx=True, verify=True):
raise models.ValidationError("Invalid email")
return email
def clean_phone_number(self):
phone_number = self.cleaned_data.get("phone_number")
clean_number = re.sub("[^0-9&^+]", "", phone_number)
# alpha_2 = self.cleaned_data.get("country")
alpha_2 = self.cleaned_data.get("country")
z = phonenumbers.parse(clean_number, "%s" % (alpha_2))
if len(clean_number) > 15 or len(clean_number) < 3:
raise forms.ValidationError(
"Number cannot be more than 15 or less than 3")
if not phonenumbers.is_valid_number(z):
raise forms.ValidationError(
"Number not correct format or non-existent")
if carrier.name_for_number(z, "en") == '':
raise forms.ValidationError("Please enter a mobile number")
return phonenumbers.format_number(
z, phonenumbers.PhoneNumberFormat.E164)
def __str__(self):
return self.emailplus
/* serializers.py */
import re
import phonenumbers
from rest_framework import serializers
from .models import razer
from phonenumbers import carrier
from validate_email import validate_email
class razerSerializer(serializers.ModelSerializer):
class Meta:
model = razer
fields = ('emailplus', 'country', 'phone_number')
/* views.py */
from django.shortcuts import render
from django.http import HttpResponse
from django.shortcuts import get_object_or_404
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from .models import razer
from .serializers import razerSerializer
class razerList(APIView):
def get(self, request):
razer1 = razer.objects.all()
serializer = razerSerializer(razer1, many=True)
return Response(serializer.data)
def post(self):
pass
Also if I put the phonenumber and email fields in my serializers.py as in phone_number = serializers.CharField(), and then put the 2 custom functions as well, do I have to register serializer as a model and what should my views.py be changed into as it is using models.py currently . Please tell me what changes should be made, as I need to validate the text values entered by the users on the admin page on the registered model or via another method where users can enter the text separately.
You could create a custom validator on your serialize for emailplus field.
def clean_emailplus(value):
email = value
if not validate_email(email, check_mx=True, verify=True):
raise serializers.ValidationError("Invalid email")
class razerSerializer(serializers.ModelSerializer):
emailplus = serializers.StringField(validators=[clean_emailplus])
class Meta:
model = razer
fields = ('emailplus', 'country', 'phone_number')
If you are creating a Django rest framework application, you need to use the validate method in the serializer.
def validate(self, data):
# clean the data
return data
I'm trying to create user creation API, but I'm not sure if I'm doing this ok because I get something like this:
Am, I doing something wrong? Because I doubt this should look like this, this is my code:
serializer.py
from rest_framework import serializers
from django.contrib.auth.models import User
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('username', 'password', 'email')
views.py
from rest_framework import status
from rest_framework.decorators import api_view, permission_classes
from rest_framework.response import Response
from rest_framework.permissions import AllowAny
from .serializer import *
#api_view(['POST'])
#permission_classes((AllowAny,))
def user_creation(request):
serializer = UserSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer, status=status.HTTP_201_CREATED)
else:
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
Like #Mohit Harshan said you need to add:
#api_view(['POST','GET'])
to your view.
When you use the Rest Framework explorer, it is by default making a GET request, so it will always get a complaint if that method is not available. However, in this case your POST methods will still work.
Typically for user generated creation, the GET method will return a simple form that the user can fill in and then submit as a POST request, creating the user.
OK, problem solved, I wanted to know if POST view should look like on photo, and it should, I just need do write in Content field all my model fields by using dictionary
So i'm simply trying to pass out my own custom error which works in my view here below:
from django.shortcuts import render
from django.http import HttpResponse
from TasksManager.models import Supervisor, Developer
from django import forms
class someView(forms.Form):
error_name = {'required':'You must type a name !','invalid':'Wrong format.'}
name = forms.CharField(label="Name", max_length=30, error_messages=error_name)
but when i try to do it in a model it just ignores the custom error_message i'm passing through to it and uses djangos built in error_message code below:
from django.db import models
class someModel(models.Model):
error_name = {'required':'You must type a name !','invalid':'Wrong format.'}
name = models.CharField(max_length=50, verbose_name="Name", error_messages=error_name)
What could i do to make this work in my model(how do i make my 2nd block of code work)?
According to the docs, the available error types are null, blank, invalid, invalid_choice, unique, and unique_for_date. There is no 'required' error type.
https://docs.djangoproject.com/en/dev/ref/models/fields/#error-messages