201 Created - but no new object in SqLite database - django

Edit 25th Jan:
here's my model!
class rat(models.Model):
name = models.CharField(max_length=132, null =True)
body_colour = models.ForeignKey(BodyColour, on_delete=models.CASCADE, null = True, related_name='body_colour')
eye_colour = models.ForeignKey(EyeColour, on_delete=models.CASCADE, null = True, related_name='eye_colour')
user = models.ForeignKey(User, on_delete=models.CASCADE, null = True)
bio = models.TextField(null = True, blank = True)
born = models.DateField(auto_now_add=True)
image = models.ForeignKey(Image, on_delete=models.CASCADE, null = True, blank=True)
Adding rat.save() to the serializer gives me the following error: TypeError: int() argument must be a string, a bytes-like object or a real number, not 'dict'
I have a button that users can click on to add an object to their account. It's sent through django to my sqlite db, and in the console log there are no errors. It says "201 Created", and yet there is no new object in the database.
Someone else had the same problem as me, the solution was getting rid of some methods in the serializer, but they don't specify what they got rid off.
What's causing this?
Here is my serializer:
class RatSerializer(FlexFieldsModelSerializer, serializers.ModelSerializer):
name = serializers.CharField()
user = serializers.CharField(source='user.username', required=False)
userid = serializers.CharField(source='user.id', required=False)
body_colour = BodyColourSerializer()
eye_colour = EyeColourSerializer()
image = ImageSerializer(required=False)
class Meta:
model = rat
exclude = ['bio']
def create(self, data):
request = self.context.get("request")
user = request.user
return rat( name = data["name"],
body_colour = BodyColour(name=data["body_colour"]["name"]),
eye_colour = EyeColour(name=data["eye_colour"]["name"]),
image = Image(),
user = user)
My views:
class ratViewset(ModelViewSet, APIView):
serializer_class = RatSerializer
# queryset = rat.objects.all()
def get_queryset(self):
user = self.request.user
if user.is_anonymous:
return rat.objects.all()
return rat.objects.filter(user=user.id)
def post(self, request):
rat = request.data.get('rat')
# creates rat with the above data
serializer = RatSerializer(data=rat)
if serializer.is_valid(raise_exception=True):
serializer.save()
print(serializer.data, type(serializer.data))
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status)
Grateful for any help!

Related

django serializer field not recognizing attribute clearly defined

when i try to run a view I get this error:
AttributeError: Got AttributeError when attempting to get a value for field `inreplytouser` on serializer `ContentFeedPostCommentSerializer`.
The serializer field might be named incorrectly and not match any attribute or key on the `QuerySet` instance.
Original exception text was: 'QuerySet' object has no attribute 'inreplytouser'.
Here is my model:
class ContentFeedPostComments(models.Model):
inreplytouser = models.ForeignKey(SiteUsers, null=True, related_name='replytouser', blank=True, on_delete=models.CASCADE)
inreplytotopcomment = models.BigIntegerField(null=True, blank=True)
timecommented = models.DateTimeField(auto_now_add=True)
user = models.ForeignKey(SiteUsers, on_delete=models.CASCADE)
contentcreator = models.ForeignKey(ContentCreatorUsers, on_delete=models.CASCADE)
contentfeedpost = models.ForeignKey(ContentFeedPost, on_delete=models.CASCADE)
text = models.CharField(max_length=1000)
here is the serializer:
class ContentFeedPostCommentSerializer(ModelSerializer):
id = IntegerField()
inreplytouser = SiteusersSerializer()
user = SiteusersSerializer()
contentcreator = ContentCreatorSerializer()
class Meta:
model = ContentFeedPostComments
fields = ('id','inreplytouser', 'inreplytotopcomment', 'timecommented',
'user', 'contentcreator', 'contentfeedpost', 'text')
here is the view:
class ContentFeedPostsComments(APIView):
def get(self, request, *args, **kwargs):
postid = kwargs.get('postid')
contentfeedpost = get_object_or_404(ContentFeedPost, id=postid)
topcomments = ContentFeedPostComments.objects.filter(contentfeedpost= contentfeedpost, inreplytotopcomment= None).order_by('timecommented')
replycomments = ContentFeedPostComments.objects.filter( contentfeedpost = contentfeedpost, inreplytotopcomment__isnull = False).order_by('timecommented')
serializedtopcomments = ContentFeedPostCommentSerializer(topcomments)
serializedreplycomments = ContentFeedPostCommentSerializer(replycomments)
payload = {
'topcomments': serializedtopcomments.data,
'replycomments': serializedreplycomments.data
}
return Response(payload)
I was reading something about source being passsed into the inreplytouser field of the serializer field but that makes no sense. Your wisdom and knowledge on this situation is greatly appreciated.
Since querysets are a collection of objects, many=True..[DRF-doc] needs to be set in the serializer:
serializedtopcomments = ContentFeedPostCommentSerializer(topcomments, many=True)
serializedreplycomments = ContentFeedPostCommentSerializer(replycomments, many=True)

Django rest framework test does not create instances in test database

I'm having an issue in DRF tests when creating instance of a model, the status code in response is 'HTTP_201_CREATED' but the instance it self does not exist in the testing db.
here is my model :
class Item(SafeDeleteModel):
owner = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, verbose_name=_("Owner"))
name = models.CharField(_("Name"), max_length=150)
category = TreeForeignKey('merssis.ItemCategory', on_delete=models.SET_NULL, null=True, verbose_name=_("Category"))
fixed_price = models.FloatField(_("Fixed price"), default=0)
main_pic = ProcessedImageField(verbose_name=_("Main picture"), upload_to='item_pics', processors=[ItemWatermarker()],format='JPEG')
main_pic_thumbnail = ImageSpecField(source='main_pic',
processors=[ResizeToFill(384, 256)],
format='JPEG',
options={'quality': 100})
geo_location = models.PointField(srid=4326, null=True, blank=True, verbose_name=_("Geolocation"))
_safedelete_policy = SOFT_DELETE_CASCADE
def __str__(self):
return self.name
Serializer :
class ItemCreateSerializer(GeoFeatureModelSerializer):
PRICE_TYPE_CHOICES = (
('fixed', _('Fixed') ),
('open', _('Open') ),
)
owner = serializers.HiddenField(default=serializers.CurrentUserDefault())
price_type = serializers.ChoiceField(choices=PRICE_TYPE_CHOICES)
category = serializers.PrimaryKeyRelatedField(queryset=ItemCategory.objects.all(), many=False)#ItemCategorySerializer(many=False)
main_pic = serializers.ImageField(use_url='item_pics')
def validate(self, data):
user = self.context['request'].user
geo_data = data.get('geo_location')
#Validate fixed price value
if data['price_type'] == 'fixed':
if data.get('fixed_price') == None or int(data.get('fixed_price')) <= 0:
raise serializers.ValidationError({"fixed_price" :INVALIDE_PRICE_ERROR})
#Price type is open should explicitly set fixed price to 0
if data['price_type'] == 'open':
data['fixed_price'] = 0
#Validate geo_location
#geo_location post data form ====> {"type":"Point", "coordinates":[37.0625,-95.677068]}
if geo_data:
if not validate_in_country_location(user, geo_data):
raise serializers.ValidationError({"geo_location":OUTSIDE_COUNTRY_MSG})
return data
def create(self, validated_data):
#Remove price_type value since it is not a field in the model
#We used to determine th price type on the serializer only
validated_data.pop('price_type')
return Item(**validated_data)
class Meta:
model = Item
geo_field = 'geo_location'
fields = ( 'owner',
'name',
'price_type',
'category',
'fixed_price',
'main_pic',
'geo_location',
)
The view :
class ItemCreateAPIView(CreateAPIView):
queryset = Item.objects.all()
serializer_class = ItemCreateSerializer
permission_classes = [permissions.IsAuthenticated]
def perform_create(self, serializer, *args, **kwargs):
self.check_object_permissions(self.request, self.request.user)
serializer.save()
The test case :
class ItemTestCase(APITestCase):
def test_create_new_item(self):
"""
Testing Add new item functionality
"""
self.client_1 = APIClient()
self.user_1 = create_new_user(email='tester1#gmail.com', username='tester_1', password='qsdf654654', gender='male')
self.client_1.login(username='tester_1',password='qsdf654654')
image_file = create_test_image()
category = ItemCategory.objects.create(name='SomeCat')
new_item_data = {
'name': 'New Item',
'price_type' : 'open',
'category': str(category.pk),
'main_pic': image_file,
}
response = self.client_1.post(url, new_item_data, format='multipart')
items = Item.objects.filter(name='New Item')
print(response.status_code)
self.assertEqual( response.status_code, status.HTTP_201_CREATED)
self.assertEqual( items.count(), 1)
and when i run the test i get '201' printed in console AND AssertionError: 0 != 1
i'm fvkin confused
In the serializer create() the object was never saved so change:
return Item(**validated_data)
to:
return Item.objects.create(**validated_data) # create the object

How to deal with .errors for Django API framework

I have the following codes:
models.py
class Device(models.Model):
hostname = models.CharField(max_length=50, unique = True)
ipaddr = models.GenericIPAddressField(protocol='ipv4', unique=True, verbose_name='mangement IP') ##Use for mgt_id_addr
date_added = models.DateTimeField(default=timezone.now)
def __str__(self):
return self.hostname
class DeviceDetail(models.Model):
SUBNET_CHOICES = (
('16','16'),
('17', '17'),
('18','18'),
('19','19'),
('20','20'),
('21', '21'),
('22', '22'),
('23', '23'),
('24', '24'),
('25', '25'),
('26', '26'),
('27', '27'),
('28', '28'),
('29', '29'),
('30', '30'),
)
DEV_MODS =(
('Catalyst 9606R', 'Catalyst 9606R'),
('C9300L-48T-4X', 'C9300L-48T-4X')
)
mgt_interface = models.CharField(max_length=50)
subnetmask = models.CharField(max_length=2, choices = SUBNET_CHOICES)
ssh_id = models.CharField(max_length=50)
ssh_pwd = models.CharField(max_length=50)
enable_secret = models.CharField(max_length=50)
dev_mod=models.CharField(max_length=50, choices = DEV_MODS) ##device_model replacement
DD2DKEY = models.ForeignKey(Device, on_delete=models.CASCADE) ##The key to link up the tables
def __str__(self):
return self.hostname
serializers.py
from rest_framework import serializers
from .models import Device, DeviceDetail
class DeviceSerializers(serializers.ModelSerializer):
class Meta:
model=Device
fields = '__all__'
class DeviceDetailSerializers(serializers.ModelSerializer):
class Meta:
model = DeviceDetail
fields = ['mgt_interface', 'subnetmask', 'ssh_id', 'ssh_pwd', 'enable_secret', 'dev_mod']
views.py
#api_view(['POST'])
def create_device(request):
device = Device()
devicedetail = DeviceDetail()
deviceserializer = DeviceSerializers(device, data = request.data)
devdserializer = DeviceDetailSerializers(devicedetail, data = request.data)
if deviceserializer.is_valid() and devdserializer.is_valid():
device_instance = deviceserializer.save()
devdserializer.save(DD2DKEY=device_instance)
results = {
"device":deviceserializer.data,
"device_details" : devdserializer.data,
}
return Response(results, status=status.HTTP_201_CREATED)
else:
errors = {
"device":deviceserializer.errors,
"device_details" : devdserializer.errors,
}
return Response(errors, status=status.HTTP_400_BAD_REQUEST)
I am facing the following error: AssertionError: You must call .is_valid() before accessing .errors.
How do i correct this to fixed the issue in case my codes enter the else condition so it will show the errors of the serializers? Because no matter what I still have to return a response if it failes
If deviceserializer.is_valid() fails, then the if condition will shortcircuit and thus not call devdserializer.is_valid(). You thus should ensure that it calls devdserializer.is_valid() as well:
if deviceserializer.is_valid() and devdserializer.is_valid():
device_instance = deviceserializer.save()
devdserializer.save(DD2DKEY=device_instance)
results = {
"device":deviceserializer.data,
"device_details" : devdserializer.data,
}
return Response(results, status=status.HTTP_201_CREATED)
else:
# &downarrow; ensure that is_valid() is called
devdserializer.is_valid()
errors = {
"device":deviceserializer.errors,
"device_details" : devdserializer.errors,
}
return Response(errors, status=status.HTTP_400_BAD_REQUEST)

pass username from token to save username in model

This is my model file which has the owner field name
class PotholeImages(models.Model):
"""Upload images with details """
image = models.ImageField(
upload_to='photos/%Y/%m/%d',
)
owner = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
default = 'unknown',
)
state_name = models.CharField(
blank = False,
max_length = 30,
default = 'unknown',
)
country_name = models.CharField(
blank = False,
max_length = 30,
default = 'unknown',
)
name = models.CharField(default=uuid.uuid4, max_length=40)
cordinate_X = models.DecimalField(max_digits=22, decimal_places=16)
cordinate_Y = models.DecimalField(max_digits=22, decimal_places=16)
created_date = models.DateTimeField(auto_now_add=True)
road_name = models.CharField(max_length = 100, default = 'unknown')
def __str__(self):
return self.name
Serializer file
class ImageSerializer(serializers.ModelSerializer):
"""Uploading Pothoele Images"""
class Meta:
model = PotholeImages
fields = ('image','state_name',
'country_name','cordinate_X',
'cordinate_Y','road_name',)
def to_representation(self, instance):
rep = super(ImageSerializer, self).to_representation(instance)
rep['owner'] = instance.owner.username
# print(rep)
return rep
views file
class ImageViewSet(viewsets.ModelViewSet):
authentication_classes = (TokenAuthentication,)
permission_classes = (IsAuthenticated,)
queryset = PotholeImages.objects.all()
serializer_class = serializers.ImageSerializer
def perform_create(self, serializer):
print(self.request.user)
serializer.save(user=self.request.user)
I want whenever a person sends a post request on
http://127.0.0.1:8000/images_api/imageView/
Then from the token, username gets detected and it should be passed in the owner field name.
Could anyone please help
Thanks
Finally, I have found the answer I have made through APIView
class ImageAPIView(APIView):
authentication_classes = (TokenAuthentication,)
def post(self, request):
## username
user = request.user
is_tokened = Token.objects.filter(user = user)
print("user name is ", user)
data = request.data
data['owner'] = user.id
serializer = serializers.ImageSerializer(data=data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=200)
ResponseData = "{} image sent by user".format(user.id)
return Response(ResponseData, status=status.HTTP_200_OK)

"This field is required." when sending JSON using POST with Django REST Framework

I have the following JSON I'm trying to post:
[
{
"action_alert_details": [],
"action_email": [
{
"tskmail_attach": null,
"tskmail_id": 4444,
"tskmail_memo": "TEST!",
"tskmail_priority": 1,
"tskmail_subject": "TEST!",
"tskmail_to_ext": "blah#blah.com",
"tskmail_to_int": null
}
],
"action_job_details": [],
"action_log_details": [],
"action_snmp_details": [],
"action_variable_details": [],
"nodmst_name": null,
"owner_name": "Operations ",
"servicemst_name": null,
"tskmst_desc": null,
"tskmst_id": 4444,
"tskmst_lstchgtm": "2014-09-17T16:02:29",
"tskmst_name": "act_test ",
"tskmst_public": "Y",
"tskmst_type": 1
}
]
When sending it through the following view, it's complaining:
[
{
"action_email": [
{
"tskmail_id": "This field is required."
}
]
}
]
But as you can see in my JSON at the top, it's there. So, why does my view not seem to recognize that it's there during serialization?
def put(self, request, format=None):
data = request.DATA
owner = data[0]['owner_name']
ownerid = Owner.objects.filter(owner_name=owner).values_list('owner_id', flat=True)[0]
data[0].update({'owner_id': ownerid})
actid = data[0]['tskmst_id']
actname = data[0]['tskmst_name']
if data[0]['nodmst_name'] == None:
data[0].update({'nodmst_id': None})
else:
nodname = data[0]['nodmst_name']
nodid = Nodmst.objects.filter(nodmst_name=nodname).values_list('nodmst_id', flat=True)[0]
data[0].update({'nodmst_id': nodid})
if data[0]['servicemst_name'] == None:
data[0].update({'servicemst_id': None})
else:
servicename = data[0]['servicemst_name']
serviceid = Servicemst.objects.filter(servicemst_name=servicename).values_list('servicemst_id', flat=True)[0]
data[0].update({'servicemst_id': serviceid})
if Tskmst.objects.filter(tskmst_name=actname).exists():
data[0]['tskmst_id'] = Tskmst.objects.filter(tskmst_name=actname).values_list('tskmst_id', flat=True)[0]
data[0]['action_email'][0]['tskmail_id'] = Tskmst.objects.filter(tskmst_name=actname).values_list('tskmst_id', flat=True)[0]
else:
maxtskid = Tskmst.objects.latest('tskmst_id').tskmst_id
data[0]['tskmst_id'] = maxtskid + 1
data[0]['action_email'][0]['tskmail_id'] = maxtskid + 1
Tblcnt.objects.filter(tblcnt_tblname='tskmst').update(tblcnt_lstid=(maxtskid +1))
Tblcnt.objects.filter(tblcnt_tblname='tskmail').update(tblcnt_lstid=(maxtskid +1))
serializer = self.get_serializer_class()(data=request.DATA, many=True)
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)
Here is my serializers that are pulling the data together:
class ActionMailSerializer(serializers.ModelSerializer):
class Meta:
model = Tskmail
resource_name = 'tskmail'
class ActionPUTSerializer(serializers.ModelSerializer):
owner_id = serializers.Field(source='owner_id')
action_email = ActionMailSerializer()
class Meta:
model = Tskmst
resource_name = 'tskmst'
depth = 1
fields = ('tskmst_id', 'tskmst_name', 'tskmst_desc', 'tskmst_type', 'owner_id', 'tskmst_public',
'tskmst_lstchgtm', 'nodmst_id', 'servicemst_id', 'action_email', 'action_alert_details',
'action_snmp_details', 'action_job_details', 'action_log_details', 'action_variable_details')
Posting this for the potential that other people might experience this issue which seems to be pertaining to it being a legacy DB. The problem lies in the fact that the PK field in "tskmail" table is also a FK to "tskmst".
See Multi-Column Primary Key support for more info.
What I ended up doing is making another set of models strictly for PUT that has no FK relationship but is strictly an Integer Field.
class TskmailPOST(models.Model):
tskmail_id = models.IntegerField(primary_key=True)
tskmail_to_int = models.TextField(blank=True)
tskmail_to_ext = models.TextField(blank=True)
tskmail_subject = models.TextField(blank=True)
tskmail_memo = models.TextField(blank=True) # This field type is a guess.
tskmail_priority = models.SmallIntegerField(blank=True, null=True)
tskmail_attach = models.TextField(blank=True)
class Meta:
managed = False
db_table = 'tskmail'
Instead of -
class TskmailPOST(models.Model):
tskmail_id = models.ForeignKey(Tskmst, db_column='tskmail_id', primary_key=True)
tskmail_to_int = models.TextField(blank=True)
tskmail_to_ext = models.TextField(blank=True)
tskmail_subject = models.TextField(blank=True)
tskmail_memo = models.TextField(blank=True) # This field type is a guess.
tskmail_priority = models.SmallIntegerField(blank=True, null=True)
tskmail_attach = models.TextField(blank=True)
class Meta:
managed = False
db_table = 'tskmail'
Then I had to call 2 separate serializers and using the POST data, break it into 2 separate dict files and validate the first, load it then validate the second and load it.