django rest framework serializer.save() inernal error - serialization

When I try to create a user I get 500 internal error when serializer.save() method is called. It worked fine yesterday and after a good sleep it stopped working.
class UserCreate(APIView):
parser_classes = (MultiPartParser,)
def post(self, request):
serializer = UserSerializer(data=request.data)
print(request.data)
if serializer.is_valid():
user = serializer.save()
if user:
return Response(serializer.data, status=status.HTTP_201_CREATED)
else:
return Response(serializer.errors, status=status.HTTP_304_NOT_MODIFIED)
class UserSerializer(serializers.ModelSerializer):
email = serializers.EmailField(
required=True, validators=[UniqueValidator(queryset=User.objects.all())]
)
username = serializers.CharField(
validators=[UniqueValidator(queryset=User.objects.all())]
)
password = serializers.CharField(min_length=8)
def create(self, validated_data):
user = User.objects.create_user(
validated_data["username"],
validated_data["password"],
validated_data["email"],
cellphone=validated_data["cellphone"],
sex=validated_data["sex"],
first_name=validated_data["first_name"],
last_name=validated_data["last_name"],
profile_image=validated_data["profile_image"],
)
return user
class Meta:
model = User
fields = (
"id",
"username",
"password",
"email",
"cellphone",
"sex",
"first_name",
"last_name",
"profile_image",
)

Related

File uploaded with Django Rest Framework shows null on database

Created an API and while testing the JSON output I'm getting is
{
"id": 34,
"file_upload": null
}
While checking the admin panel, the new id is created but there is no uploaded image in that. And hence I'm not able to save it locally too.
Here's my urls.py
urlpatterns = [
path("api/", upload_file),
path("api-class/", UploadFileView.as_view())
]
I've created two paths one with function-based views and the other with class-based views, but neither is working.
views.py
class UploadFileView(APIView):
parser_classes = [MultiPartParser, FormParser,]
def get(self, request):
file = ApiSerializer.objects.all()
serializer = ApiSerializer(file, many=True)
return Response(serializer.data)
def post(self, request, format=None):
print(request.data)
serializer = ApiSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
#api_view(['POST'])
#parser_classes((MultiPartParser,))
def upload_file(request):
if request.method == 'POST':
serializer = ApiSerializer(data=request.data)
extension = 'csv'
ext = ['csv']
if extension in ext:
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
else:
report = {'message':'Serializer wasn\'t valid. Error occured'}
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
else:
resp = {'message': "Invalid Format"}
return Response(resp, status=status.HTTP_400_BAD_REQUEST)
serializer.py
class ApiSerializer(serializers.ModelSerializer):
class Meta:
model = UserInput
fields = '__all__'
models.py
def file(instance, filename):
filename = filename.replace(" ", "")
return '\{0}'.format(filename)
def validate_file_extension(value):
import os
ext = os.path.splitext(value.name)[1]
valid_extensions = ['.csv']
if not ext in valid_extensions:
raise ValidationError(u'File not supported!')
class UserInput(models.Model):
file_upload = models.FileField(null=True, blank=True, upload_to='file', validators=[validate_file_extension])

suspend function testing with spock

I have a simple function in kotlin like that :
suspend fun createTicket(#Valid request: CreateTicketRequest, authentication: Authentication): HttpResponse<Any> {
request.customerId = "customerId"
logger().info("Receive by the client $request")
return HttpResponse.created(service.create(request))
}
I've already Mock the request and the authentication.
So, I call it on Spock:
def 'It should create a ticket with success'() {
given:
def request = createRequest(
TICKET_ID,
TICKET_NAME,
TICKET_PHONE,
TICKET_CPF,
TICKET_EMAIL,
TICKET_COMMENT,
TICKET_SUBJECT,
TICKET_TAG
)
when:
response = controller.createTicket(
request,
authentication
)
then:
response != null
}
I'm getting the following error :
Suspend function 'create' should be called only from a coroutine or another suspend function.
Can anyone help me with this question ?
Best regards
Solved I created a Kotlin class code
class CallCreateTicket {
private lateinit var response: HttpResponse<Any>
private fun createTicket(
request: CreateTicketRequest,
authenticator: Authenticator,
controller: TicketController,
): HttpResponse<Any> {
runBlocking {
response = controller.createTicket(request, authenticator)
}
return response
}
}
and I called it on groovy ...
#Mockable(TicketCreateServiceImpl)
class TicketControllerTest extends Specification {
def mockUtil = new MockUtil()
def service = Mock(TicketCreateServiceImpl)
def authenticator = Mock(Authenticator)
def response = Mock(HttpResponse)
def controller = new TicketController(service)
def callCreateTicket = new CallCreateTicket()
def 'check if all instances are mocked'() {
mockUtil.isMock(authentication)
mockUtil.isMock(service)
}
def 'It should call the index function and return a valid String'() {
when:
response = controller.index()
then:
response == INDEX_RETURN
}
def 'It should call the index function and return a invalid String'() {
when:
response = controller.index()
then:
response != INVALID_INDEX_RETURN
}
def 'It should create a ticket with success'() {
given:
def request = createRequest(
TICKET_ID,
TICKET_NAME,
TICKET_PHONE,
TICKET_CPF,
TICKET_EMAIL,
TICKET_COMMENT,
TICKET_SUBJECT,
TICKET_TAG
)
when:
response = callCreateTicket.createTicket(
request,
authenticator,
controller
)
then:
response.status(HttpStatus.CREATED)
}
}

Django: How do I return JWT with custom claim after user Sign Up?

I know how to create custom claims with simplejwt. Now I want to return custom claim in the tokens containing email after user signs up. How do I do this?
My serializer:
class CreateUserSerializer(serializers.ModelSerializer):
password = serializers.CharField(min_length=8, required=True, write_only=True)
password2 = serializers.CharField(min_length=8, write_only=True, required=True)
tokens = serializers.SerializerMethodField()
def get_tokens(self, user):
refresh = RefreshToken.for_user(user)
return {
'refresh': str(refresh),
'access': str(refresh.access_token),
}
def validate(self, data):
if data['password'] != data['password2']:
raise serializers.ValidationError({"password": "Password fields didn't match."})
return data
def create(self, validated_data):
password = validated_data.pop('password', None)
password2 = validated_data.pop('password2', None)
instance = self.Meta.model(**validated_data)
if password is not None:
instance.set_password(password)
instance.save()
return instance
class Meta:
model = CustomUser
fields = ('id', 'email', 'password', 'password2', 'tokens')
extra_kwargs = {'password': {'write_only': True}}
It returns the default JWT access and refresh tokens. I want to return custom claim in the token here.
The view:
class CreateUserView(generics.CreateAPIView):
permission_classes = [permissions.AllowAny]
def create(self, request, *args, **kwargs):
serializer = CreateUserSerializer(data = request.data)
if serializer.is_valid(raise_exception=True):
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
you can create a custom function to get new refresh and access tokens with adding some extra info (your custom claim):
from rest_framework_simplejwt.tokens import RefreshToken
def get_tokens_for_user(user):
refresh = RefreshToken.for_user(user)
refresh['user_name'] = user.username
refresh['first_name'] = user.first_name
refresh['last_name'] = user.last_name
refresh['full_name'] = user.get_full_name()
return {
'refresh': str(refresh),
'access': str(refresh.access_token),
}
and then you can use this function wherever you want.
and also for CBV (TokenObtainPairView) if you like , you can use a custom Serializer as the following to get the same result :
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
from rest_framework_simplejwt.views import TokenObtainPairView
class MyTokenObtainPairSerializer(TokenObtainPairSerializer):
#classmethod
def get_token(cls, user):
token = super().get_token(user)
token['user_name'] = user.username
token['first_name'] = user.first_name
token['last_name'] = user.last_name
token['full_name'] = user.get_full_name()
return token
class MyTokenObtainPairView(TokenObtainPairView):
serializer_class = MyTokenObtainPairSerializer
and the url path will be as the following in urls.py
path('token/', MyTokenObtainPairView.as_view(), name='token_obtain_pair'),
this is just example , and change it based on your case/requirements .
i hope this helpful for you .
I figured it out. I just had to made this change in the existing get_tokens() function of my serializer:
def get_tokens(self, user):
refresh = RefreshToken.for_user(user)
refresh['email'] = user.email
return {
'refresh': str(refresh),
'access': str(refresh.access_token),
}
Here email is my added claim.

dictionary update sequence element #0 has length 1; 2 is required

i look this error i all internet but i really dont understand the answers, i hard to understand what is the function given to you or what it has to give to you, i let you my code i hope any one help
What im looking for?
i need to put into act_user_suc the users sucursal_u fro res_users thats all and i relly apreciated the help
class bodega(osv.Model):
_name = 'bodega'
_description = 'datos generales'
def dame_usuario(self, cr, uid, ids, fieldname, arg, context=None):
digits = self.pool.get('res.users').browse(cr, uid, uid, context=context).company_id.currency_id
return digits
_columns = {
'name': fields.char("Name", required=True),
'act_user_suc': fields.function(dame_usuario, type='many2one', readonly = True),
}
_defaults = {
}
bodega()
You need to update few things in code.
Specify relation attribute in fields.function, you have defined that many2one as field type but it's related to which model ?.
And other things is that company_id.currency_id it gives you an browsable object not an id.
So try following,
def dame_usuario(self, cr, uid, ids, fieldname, arg, context=None):
res = {}
for obj in self.browse(cr, uid, ids, context=context):
result[obj.id] = False
user = self.pool.get('res.users').browse(cr, uid, uid, context=context)
if user and user.sucursal_u:
result[obj.id] = user.sucursal_u.id
return res
_columns = {
'name': fields.char("Name", required=True),
'act_user_suc': fields.function(dame_usuario,
type='many2one', readonly = True, relation='sucursales'),
}

AttributeError: 'NoneType' object has no attribute 'get_default_company'

class Sale(osv.osv):
_name = 'sale'
_columns = {
'name': fields.char('Company Name', size=128)
}
def get_default_company(self, cr, uid, context=None):
company_id = self.pool.get('res.users').browse(cr, uid, uid).company_id.id,
return company_id
Sale()
I used above code , all is well but I don't know where and how to call my function get_default_company(). As when I call this method it's give
cr and uid invalids
What is AttributeError: 'NoneType'?
NoneType means that function or instance of whatever Class or Object not working with you, you've actually got None.
You are Sale() that's why this error occur, you need to call get_default_company() function, and calling this function before you must implement this method. otherwise give you error (get_default_company function does not exist).
class Sale(osv.osv):
_name = 'sale'
def get_default_company(self, cr, uid, context=None):
company_id = self.pool.get('res.users').browse(cr, uid, uid).company_id.id,
return company_id
get_default_company() // Call this function
_columns = {
'name': fields.char('Company Name', size=128)
}
And you want to create function field yes you can create check this documentation.
Just add in Sale class _defaults dict. OpenERP will call it automaticly at creating new object.
_defaults = {
'company_id': get_default_company,
}
For example look at here.
More details you can find in OpenERP modules code.
It look like you need to set default value for your company. for that you need to use _defaults model attribute which sets default value for your field. like
_defaults = {
'company_id': get_company
}
before this method you need to define get_company method which should return company id like
def get_company(self, cr, uid, context=None):
user_rec = self.pool.get('res.users').browse(cr, uid, uid, context)
return user_rec.company_id.id
and to all this you need a field in _columns. so you also need to add company_id as many2one field. like
_columns = {
'name': fields.char('Company Name', size=128),
'company_id': fields.many2one('res.company', "Company")
}
Alter all this your model will look like,
class sale(osv.osv):
_name = 'sale'
_columns = {
'name': fields.char('Company Name', size=128),
'company_id': fields.many2one('res.company', "Company")
}
def get_company(self, cr, uid, context=None):
user_rec = self.pool.get('res.users').browse(cr, uid, uid, context)
return user_rec.company_id.id
_defaults = {
'company_id': get_company
}
sale()
Hope This helps!