I am a beginner to django and trying to create a post request on django rest-framework.
I have a following model:
class ProjectScheme(models.Model):
name = models.CharField(max_length=250, blank=False,null=False)
parent_scheme_id = models.ForeignKey(ProjectSchemeMaster, on_delete = models.CASCADE)
rule = models.TextField(blank=True)
def __str__(self):
return str(self.name)
And a serializer:
class SchemeDetailSerializer(serializers.ModelSerializer):
class Meta:
model = ProjectScheme
fields = ('id', 'name', 'parent_scheme_id', 'rule')
depth=1
And my view:
#api_view(['POST'])
#renderer_classes((JSONRenderer,))
def create_project_scheme(request):
if request.method == 'POST':
data = JSONParser().parse(request)
serializer = SchemeDetailSerializer(data=data)
comp_logger.info('Call to create_project')
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
else:
return Response({'response':serializer.errors})
return Response({})
With post request body as:
{
"name": "django-rf"
}
This gives serializer.is_valid() to true, but in response I get
(1048, "Column 'parent_scheme_id_id' cannot be null")
I tried adding parent_scheme_id = models.ForeignKey(ProjectSchemeMaster, on_delete = models.CASCADE, blank=False, null=False) but that didn't make any difference.
How can I validate the request input so that it shows proper validation message like for name field?
In your model, you set your ForeignKey field as a required field, Django by default consider a field required=True if not explicitely provide null=True. So if you want to create ProjectScheme instance without a ForeignKey referrence, then make sure you provide null=True to your ForeignKey field,
class ProjectScheme(models.Model):
name = models.CharField(max_length=250, blank=False,null=False)
parent_scheme_id = models.ForeignKey(ProjectSchemeMaster, null=True, blank=True, on_delete = models.CASCADE)
rule = models.TextField(blank=True)
def __str__(self):
return str(self.name)
in mention, blank=True works in form level validation.
Related
This is view:
def post(self, request):
author_request = request.data.get("author")
queryset = Book.objects.filter(author=author_request)
serializer = BookSerializer(queryset, None)
return Response(serializer.data, HTTP_200_OK)
This is model:
class Author(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
full_name = models.CharField(max_length=255, null=True, blank=True)
about = models.TextField(null=True, blank=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def __str__(self):
return self.full_name
class Meta:
verbose_name = 'Author'
verbose_name_plural = 'Authors'
So, when i try to filter the book by author i get the error. The error tells me that the POST data that i entered which is "Aleksa Petrovic" a name of a author that exists in the database is not an UUID. So when i filter it, it filters by UUID and i want it to filter by "full_name"
You can .filter(…) [Django-doc] with:
Book.objects.filter(author__full_name=name_of_author)
One can use double underscores (__) to look "through" relations.
The view thus looks like:
def post(self, request):
author_request = request.data.get('author')
queryset = Book.objects.filter(author__full_name=author_request)
serializer = BookSerializer(queryset, None)
return Response(serializer.data, HTTP_200_OK)
Typically searches with a filter are not handled by a POST request, but by a GET request, since a GET request is supposed to retrieve data from the web server.
I want to realize POST method to create Article object.
I have to provide this body:
{
"title": "Sample title",
"link": "https://www.sample.com/"
}
And get Article object with auto assigned ID, author_name(current user) and creation_date.
But i got an problem - "create" methor deletes one field - author_name. (See code below)
Finally i get next error msg:
IntegrityError at /api/articles/
Error: Null value in column "author_name_id" with NOT NULL
DETAIL: Error row contains (32, Sample title, https://www.sample.com/, 2020-11-08, null).
How do i solve my problem?
models.py
class Article(models.Model):
title = models.CharField(
name='title',
max_length=120,
null=False,
)
link = models.URLField(
name='link',
unique=True,
null=False,
)
creation_date = models.DateField(
name='creation_date',
default=date.today,
null=False,
)
author_name = models.ForeignKey(
User,
on_delete=models.CASCADE,
related_name='articles',
null=False,
)
def __str__(self):
return self.title
views.py
class ArticleView(APIView):
def post(request):
if request.user.is_authenticated:
data = {"author_name": request.user}
data.update(request.data)
print(request.data)
serializer = ArticleSerializer(data=data)
if serializer.is_valid(raise_exception=True):
serializer.save()
return Response(status=201)
return Response(status=403)
request.data >>> {'title': 'Sample title', 'link': 'https://www.sample.com/', 'author_name': <SimpleLazyObject: <User: admin>>}
serializers.py
class ArticleSerializer(serializers.ModelSerializer):
author_name = serializers.StringRelatedField()
class Meta:
model = Article
fields = "__all__"
def create(self, validated_data):
print(validated_data)
return Article.objects.create(**validated_data)
validated_data >>> {'title': 'Sample title', 'link': 'https://www.sample.com/'}
I think it is because of the author_name = serializers.StringRelatedField() you have on your serializers. By default this is a read-only field so the serializer will remove it from the data you pass to it.
I'm pretty sure if you would just do:
serializer = ArticleSerializer(request.data)
if serializer.is_valid():
serializer.save(author_name=request.user)
this should solve your problem. Because on the serializer you validate the fields that are not read-only and then you save the data by passing the user instance to the save method of the serializer.
I also see you are using an ApiView for creating a model instance, I would recommend looking into CreateApiView
So I know there are a few similar questions but none of the solutions worked for me. I've tried save(commit=false) and save_m2m as well as a bunch of other stuff but i get the error
NOT NULL constraint failed: home_services.managers_id
Anyways here's my code:
views.py
def service(request):
if request.user.is_authenticated:
if request.method == 'POST': #Create Service
form = CreateServiceForm(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect('/service') #Later change this to redirect to server page
else:
form = CreateServiceForm()
args = {'user': request.user, 'form': form}
return render(request, 'service.html', args)
else:
return HttpResponseRedirect('/feed')
models.py
class Services(models.Model):
name = models.CharField(max_length=100, default='')
description = models.CharField(max_length=500, default='')
owner = models.OneToOneField(User, on_delete=models.CASCADE)
managers = models.ForeignKey(User, related_name="managers", on_delete=models.CASCADE)
members = models.ManyToManyField(User, related_name="members")
def __str__(self):
return str(self.name) + ": id" + str(self.id)
forms.py
class CreateServiceForm(forms.ModelForm):
owner = forms.ModelChoiceField(queryset=User.objects.all())
members = forms.ModelMultipleChoiceField(queryset=User.objects.all())
class Meta:
model = Services
fields = [
'name',
'description',
'owner',
'members',
]
I want the user to be able to create a service and select 1 or more members that is in the default django User model.
I want the user to be able to create a service and select 1 or more members that is in the default django User model.
You are not providing managers, which is not allowed as per the current configuration.
So, change:
managers = models.ForeignKey(
User,
related_name="managers",
on_delete=models.CASCADE,
)
To:
managers = models.ForeignKey(
User,
related_name="managers",
on_delete=models.CASCADE,
blank=True,
null=True,
)
You might want to read more about blank and null.
Hi i'm currently trying to write validation for my update API. i used the model fields in my serializer like so as i only want these fields to be update in the custom User model:
class UpdateUserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = (
'email', 'uid', 'nickname', 'eth_address', 'eth_private_key', 'evt_address', 'evt_private_key'
)
My User model:
Class User(AbstractUser):
uid = models.CharField(
"uid", max_length=255, null=True, blank=True)
phone_number = models.CharField(
"Phone number", max_length=255, null=True, blank=True)
nickname = models.CharField(
"Nickname", max_length=255, null=True, blank=True)
status = models.PositiveSmallIntegerField("Status", default=0)
eth_address = models.CharField(
"Eth address", max_length=255, null=True, blank=True)
eth_private_key = models.CharField(
"Eth private key", max_length=255, null=True, blank=True)
evt_address = models.CharField(
"Evt address", max_length=255, null=True, blank=True)
evt_private_key = models.CharField(
"Evt private key", max_length=255, null=True, blank=True)
created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)
# deleted
class Meta:
db_table = "users"
pass
And here is my DRF update model view:
class update_profile(RetrieveUpdateAPIView):
permission_classes = ()
authentication_classes = (FirebaseAuthentication,)
def update(self, request):
user_data = request.data
user = User.objects.get(uid=request.user.uid)
serializer = UpdateUserSerializer(user, data=user_data, partial=True)
if user_data == {}:
raise serializers.ValidationError({'code': 400, 'data': 'Invalid JSON object'})
for key_name in user_data:
if key_name not in ['email', 'uid', 'nickname', 'eth_address', 'eth_private_key', 'evt_address', 'evt_private_key']:
raise serializers.ValidationError({'code': 400, 'data': 'Invalid input ' + key_name})
if serializer.is_valid():
updated_user = serializer.save()
return JsonResponse({'code': 200,'data': updated_user.uid}, status=200)
else:
return JsonResponse({'code': 400,'errors':serializer.errors}, status=400)
My input is as follow on POSTMAN:
{
"email": "test#gmail.com",
"uid": "dqwdqwd3123123",
"nickname":"Alan",
"eth_address": "dwdw",
"eth_private_key": "fwef",
"evt_address": "dwqdqwf",
"evt_private_key": "dwqdqqd"
}
I want to test with conditions of wrong input so i input wrong email like wrongemail.com and it validated correctly:
{
"code": 400,
"errors": {
"email": [
"Enter a valid email address."
]
}
}
But when i try to do wrong input to other type like "nickname": 4123414, it still pass validation even when in the model i set nickname = models.CharField("Nickname", max_length=255, null=True, blank=True) i don't know why the input value of number passed the validation without raising error.
First of all, I think most of the stuff you are doing here, like checking for correct fields, are done by the serializer itself. You just have to use is_valid(raise=True) and django will take care of returning the proper HTTP response (if you are using the default django error handler - read more in the docs)
So here is how your view should look like:
class update_profile(RetrieveUpdateAPIView):
permission_classes = ()
authentication_classes = (FirebaseAuthentication,)
def update(self, request):
user_data = request.data
user = User.objects.get(uid=request.user.uid)
serializer = UpdateUserSerializer(user, data=user_data, partial=True)
if serializer.is_valid(raise_exception=True):
updated_user = serializer.save()
return JsonResponse({'code': 200,'data': updated_user.uid}, status=200)
However, I also think the nick example is actually correct. Number can be cast as string and that's what the serializer is doing -> it changes 4123414 to '4123414'. If you think about it, it's a totally valid nick. You should try other examples, like providing a negative number for status.
I know on this topic people asked a question before but my case is different and I have implemented almost all the solutions which I found but none of them are worked for me.
First I have defined three classes in models:
models.py
class User(AbstractBaseUser, PermissionsMixin):
""" User Model """
username = None
email = models.EmailField(max_length=255, unique=True)
name = models.CharField(max_length=255)
agency = models.ForeignKey('agency.Agency', on_delete=models.CASCADE, null=True)
weekly_email = models.NullBooleanField()
is_create_new_password = models.NullBooleanField(default=True)
is_active = models.BooleanField(default=True)
last_login_time = models.DateTimeField(null=True)
last_login_from = models.CharField(max_length=255, null=True)
created_at = models.DateField(default=timezone.now)
updated_at = models.DateField(default=timezone.now)
created_by = models.IntegerField(null=True)
updated_by = models.IntegerField(null=True)
""" The `USERNAME_FIELD` property tells us which field we will use to log in.
In this case, we want that to be the email field. """
USERNAME_FIELD = "email"
REQUIRED_FIELDS = ["username"]
""" Tells Django that the UserManager class defined above should manage
objects of this type. """
objects = UserManager()
class Role(models.Model):
""" Role Model """
name = models.CharField(max_length=255, unique=True)
class UserRole(models.Model):
""" User Role Model """
user = models.ForeignKey(User, on_delete=models.CASCADE)
role = models.ForeignKey(Role, on_delete=models.CASCADE)
Then I have defined my serializer for user module:
serializers.py
class RegistrationSerializer(serializers.ModelSerializer):
""" Serializers registration requests and creates a new user. """
user_id = serializers.IntegerField(required=False)
email = serializers.EmailField(max_length=255)
name = serializers.CharField(max_length=255)
agency_id = serializers.IntegerField(source='agency.id', required=False)
role = serializers.CharField(source='role.name')
weekly_email = serializers.NullBooleanField()
last_login_time = serializers.DateTimeField(required=False)
last_login_from = serializers.CharField(max_length=255, required=False)
class Meta:
model = User
fields = (
'role', 'user_id', 'email', 'name', 'agency_id', 'weekly_email', 'last_login_time',
'last_login_from'
)
And At the end, I have defined my view file for user creation:
views.py
class UserCreateAPIView(APIView):
""" User create Api view class """
#Allow any user (authenticated or not) to hit this endpoint.
permission_classes = (IsAuthenticated,)
serializer_class = RegistrationSerializer
def post(self, request):
""" create user using following logic. """
request.data['user_id'] = request.user.id
serializer = self.serializer_class(data=request.data)
serializer.is_valid(raise_exception=True)
serializer.save(user=request.user)
return Response({'message': response['user']['created'], 'data': serializer.data},
status=status.HTTP_201_CREATED)
Now when I run it everything works fine like user is created, role is created as per my expectations. My view, serializer and models excuted but at the end on this line:
return Response({'message': response['user']['created'], 'data': serializer.data},
status=status.HTTP_201_CREATED)
I am facing error like,
AttributeError: Got AttributeError when attempting to get a value for field `role` on serializer `RegistrationSerializer`.
The serializer field might be named incorrectly and not match any attribute or key on the `User` instance.
Original exception text was: 'User' object has no attribute 'role'.
I think you need to use ModelSerializer
class RegistrationSerializer(serializers.Serializer):
to
class RegistrationSerializer(serializers.ModelSerializer):