Testing POST request throwing a KeyError in Postman - django

I am currently testing my POST request for the Tagging model. For this, I have tried to override the create() method. I am not so sure I have done this correctly but I tried everything I could think of. I even removed it and tried testing the POST request without overriding it.
I keep getting this error while testing with Postman:
KeyError at /api/tagging 'user'
How can I get rid of this error? What is my create() method missing?
serializers.py
class TaggingSerializer(serializers.ModelSerializer):
tag = StringRelatedField()
resource = serializers.PrimaryKeyRelatedField(read_only=True)
gameround = serializers.PrimaryKeyRelatedField(read_only=True)
user = CustomUserSerializer(required=False, read_only=True)
class Meta:
model = Tagging
fields = ('id', 'user', 'gameround', 'resource', 'tag', 'created', 'score', 'origin')
def create(self, validated_data):
"""Create and return a new tagging"""
tagging = Tagging(
user=validated_data["user"],
gameround=validated_data["gameround"],
resource=validated_data["resource"],
tag=validated_data["tag"],
created=validated_data["created"],
score=validated_data["score"],
origin=validated_data["origin"]
)
tagging.save()
return tagging
def to_representation(self, data):
data = super().to_representation(data)
return data
If I change the create method to:
def create(self, validated_data):
"""Create and return a new tagging"""
tagging = Tagging(
user=validated_data.get("user"),
gameround=validated_data.get("gameround"),
resource=validated_data.get("resource"),
tag=validated_data.get("tag"),
created=validated_data.get("created"),
score=validated_data.get("score"),
origin=validated_data.get("origin")
)
tagging.save()
return tagging
I am getting an
IntegrityError: null value in column "created" of relation "app_tagging" violates not-null constraint
DETAIL: Failing row contains (15, null, 0, , null, null, null, null).
This is my post request:
def post(self, request, *args, **kwargs):
tagging_serializer = TaggingSerializer(data=request.data)
if tagging_serializer.is_valid(raise_exception=True):
tagging_serializer.save(tagging=request.data)
return Response({"status": "success", "data": tagging_serializer.data}, status=status.HTTP_200_OK)
else:
return Response({"status": "error", "data": tagging_serializer.errors}, status=status.HTTP_400_BAD_REQUEST)
This is the JSON I am sending
{
"user": null,
"gameround": 1,
"resource": 602,
"tag": "RTTesttaggg",
"created": "2022-12-12T15:19:49.031000Z",
"score": 0,
"origin": ""
}
models.py
class CustomUser(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(verbose_name='email address', unique=True)
username = models.CharField(max_length=256, unique=True, blank=False)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
first_name = models.CharField(max_length=256, null=True)
last_name = models.CharField(max_length=256, null=True)
date_joined = models.DateTimeField(editable=False, default=timezone.now)
is_superuser = models.BooleanField(default=False)
date_joined = models.DateTimeField(default=timezone.now)
is_uploader = models.BooleanField(default=False)
first_name = models.CharField(max_length=256)
last_name = models.CharField(max_length=256)
updated_at = models.DateTimeField(auto_now=True)
REQUIRED_FIELDS = ['username']
objects = CustomUserManager()
USERNAME_FIELD = 'email'
def get_username(self):
return self.username
def __str__(self):
return f'{self.email} ({self.username})' or ''
class Resource(models.Model):
id = models.PositiveIntegerField(null=False, primary_key=True)
hash_id = models.CharField(max_length=256)
creators = models.ManyToManyField(Creator)
titles = models.ManyToManyField(Title)
created_start = models.DateField(null=True)
created_end = models.DateField(null=True)
location = models.CharField(max_length=512, null=True)
institution_source = models.CharField(max_length=512, blank=True)
institution = models.CharField(max_length=512, blank=True)
origin = models.URLField(max_length=256, null=True)
enabled = models.BooleanField(default=True)
media_type = models.CharField(max_length=256, default='picture')
objects = models.Manager()
def __str__(self):
return self.hash_id or ''
#property
def tags(self):
tags = self.taggings.values('tag').annotate(count=Count('tag'))
return tags.values('tag_id', 'tag__name', 'tag__language', 'count')
class Gameround(models.Model):
user = models.ForeignKey(CustomUser, on_delete=models.SET_NULL, null=True)
gamesession = models.ForeignKey(Gamesession, on_delete=models.CASCADE)
created = models.DateTimeField(editable=False)
score = models.PositiveIntegerField(default=0)
objects = models.Manager()
#property
def tags(self):
tags = self.taggings.values('tag')
return tags.values('tag_id', 'tag__name', 'tag__language', 'resource_id')
class Tag(models.Model):
name = models.CharField(max_length=256)
language = models.CharField(max_length=256)
objects = models.Manager()
def __str__(self):
return self.name or ''
#property
def tags(self):
tags = self.tagging.values('tag')
return tags.values('tag_id', 'tag__name', 'tag__language')
class Tagging(models.Model):
user = models.ForeignKey(CustomUser, on_delete=models.SET_NULL, null=True)
gameround = models.ForeignKey(Gameround, on_delete=models.CASCADE, related_name='taggings')
resource = models.ForeignKey(Resource, on_delete=models.CASCADE, related_name='taggings')
tag = models.ForeignKey(Tag, on_delete=models.CASCADE, related_name='tagging')
created = models.DateTimeField(editable=False)
score = models.PositiveIntegerField(default=0)
origin = models.URLField(max_length=256, blank=True, default='')
objects = models.Manager()
def __str__(self):
return str(self.tag) or ''

Related

How to get a non-pk value to be the value by which a post request is made in django rest framework

As the question states, I'd like to be able to instead of having to pass a PK inside my JSON request in the post request I could pass a different value, like a username "bob" instead of 1.
so the idea is that instead of my request containing:
{
"client": 1,
"urgent": true,
"article": 1,
"quantity": 1,
"order_to": 1
}
it should contain:
{
"client": "bob",
"urgent": true,
"article": 234,
"quantity": 1,
"order_to": 1
}
here are my relevant models:
class UserModel(models.Model):
MEMBERSHIP_TYPE = [
('NM', 'NORMAL'),
('PT', 'PLATA'),
('OR', 'ORO'),
('PL', 'PLATINO'),
]
id = models.AutoField(primary_key=True)
username = models.CharField(max_length=100, unique=True)
photo = models.ImageField(upload_to='images/', blank=True)
address = models.TextField()
client_type = models.CharField(max_length=2,
choices=MEMBERSHIP_TYPE,
default= 'NM')
def __unicode__(self):
return self.name
class ArticleModel(models.Model):
id = models.AutoField(primary_key=True)
code = models.IntegerField(unique=True)
description = models.TextField()
def __str__(self):
return str(self.code)
class SupplierModel(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=100)
address = models.TextField()
articles = models.ManyToManyField(ArticleModel)
def __str__(self):
return self.name
class OrderModel(models.Model):
id = models.AutoField(primary_key=True)
client = models.ForeignKey('UserModel', on_delete=models.CASCADE)
gen_time = models.DateTimeField(auto_now_add=True)
gen_supplied = models.DateTimeField(null=True, blank=True)
urgent = models.BooleanField()
order_to = models.ForeignKey('OrderToModel', on_delete=models.CASCADE)
article = models.ForeignKey('ArticleModel', on_delete=models.CASCADE)
quantity= models.IntegerField()
and Serializer:
class OrderCreateSerializer(serializers.ModelSerializer):
# order_to = OrderToPolymorphicSerializer()
class Meta:
model = OrderModel
fields = ('client', 'urgent', 'article', 'quantity', 'order_to')
Help is much appreciated.
Thank you in advance.
you can do this
class OrderCreateSerializer(serializers.ModelSerializer):
client = serializers.SlugRelatedField(
slug_field='username',
queryset=UserModel.objects.all()
)
article = serializers.SlugRelatedField(
slug_field='code',
queryset=ArticleModel.objects.all()
)
class Meta:
model = OrderModel
fields = ('client', 'urgent', 'article', 'quantity', 'order_to')

How to associate foreignkey data in django 3.0

How do I pull all of the users and put their full name into a context that I pass to a view? My view currently pulls all of the filtered rows and I want to replace the id of the user with their full name before I pass the context to the view. This is probably very simple, but I can't seem to make it work. The field trigger_caused_by holds the id of the user that made the change that fired the trigger.
Account models.py
class User(AbstractBaseUser):
email = models.EmailField(max_length=255, unique=True, verbose_name="Email Account")
first_name = models.CharField(max_length=50, blank=True, null=True, verbose_name="First Name")
last_name = models.CharField(max_length=50, blank=True, null=True, verbose_name="Last Name")
active = models.BooleanField(default=False, verbose_name="Is Account Active")
approved = models.BooleanField(default=False, verbose_name="Is Account Approved")
readonly = models.BooleanField(default=True, verbose_name="Read Only Account")
staff = models.BooleanField(default=False, verbose_name="Staff Account")
admin = models.BooleanField(default=False, verbose_name="Admin Account")
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
objects = UserManager()
def __str__(self):
return f"{self.email} - {self.last_name}, {self.first_name}"
def get_full_name(self):
if self.last_name and self.first_name:
full_name = self.last_name + ", " + self.first_name
return full_name
return self.email
def get_short_name(self):
return self.email
def has_perm(self, perm, obj=None):
return True
def has_module_perms(self, app_label):
return True
#property
def is_staff(self):
return self.staff
#property
def is_admin(self):
return self.admin
#property
def is_active(self):
return self.active
#property
def is_approved(self):
return self.approved
#property
def is_readonly(self):
return self.readonly
#property
def user_id(self):
return self.id
Historical models.py
class TCVBaseHistorical(models.Model):
opportunity_id = models.CharField(max_length=5, blank=True, verbose_name='Connected Oppporunity ID')
trigger_type = models.CharField(max_length=20, blank=True, verbose_name='Trigger Type')
new_trigger_value = models.CharField(max_length=40, blank=True, null=True, verbose_name='New Trigger Value')
datetime_of_trigger = models.DateTimeField(auto_now=False, blank=True, null=True,
verbose_name='Date/Time of Trigger')
new_date_value = models.DateField(auto_now=False, blank=True, null=True, verbose_name='New Date Value')
date_field_changed = models.CharField(max_length=10, blank=True, null=True, verbose_name="Date Field Changed")
money_field_changed = models.CharField(max_length=10, blank=True, null=True, verbose_name="Money Field Changed")
estimated = models.DecimalField(max_digits=12, decimal_places=2, blank=True, default=0.0,
verbose_name='Estimated')
estimated_base = models.DecimalField(max_digits=12, decimal_places=2, blank=True, default=0.0,
verbose_name='Estimated Base')
trigger_caused_by = models.CharField(max_length=5, blank=True, null=True, verbose_name='Trigger Caused By')
active = models.BooleanField(blank=True, null=True, default=True)
# def __str__(self):
# if self.trigger_type == 'tier':
# return f'{self.trigger_type} - '{self.opportunity_id} - {self.trigger_caused_by} - {self.active}'
class Meta:
verbose_name = 'Historical'
verbose_name_plural = 'Historicals'
#property
def is_active(self):
return self.active
Historical views.py
class HistoricalRoleList(ListView):
model = TCVBaseHistorical
paginate_by = 10
template_name = "Opportunity/Historical/HistRole.html"
def get_context_data(self, **kwargs):
list_historicals = super(HistoricalRoleList, self).get_context_data(**kwargs)
usersinfo = User.objects.all()
for _ in list_historicals:
caused_by = getattr(list_historicals, 'trigger_caused_by')
for _ in usersinfo:
user = getattr(usersinfo, str(User.user_id))
if caused_by == user:
list_historicals.full_name = user.get_full_name()
return list_historicals
def get_queryset(self):
qs = super().get_queryset()
cur_opp = Current_Opportunity.objects.get().current_opportunity
return qs.filter(trigger_type='role', opportunity_id=cur_opp).order_by('-datetime_of_trigger')

Django rest framework partial update with where query

I just want to update two fields of table where id_payment = 1. How to do it? It showing me the error bellow.
IntegrityError at /receivePendingPayment/
(1048, "Column 'bank_id' cannot be null")
#View
#permission_classes([IsAuthenticated])
#api_view(['PATCH'])
def receivePendingPayment(request):
id_payment = request.data['id_payment']
data = {'accountant_received_by': request.user.id, 'accounts_status': 'Received'}
BankPaymentHistory.objects.filter(id=id_payment)
serializer = BankPaymentUpdateSerializer(data=data, partial=True, many=False)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_200_OK)
else:
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
#Serializer
class BankPaymentUpdateSerializer(serializers.ModelSerializer):
class Meta:
model = BankPaymentHistory
fields = ('accounts_status','accountant_received_by')
#Model
class BankPaymentHistory(models.Model):
activation_enum = (('Active', 'Active'), ('Deactive', 'Deactive'))
accounts_status_enum = (('Pending', 'Pending'), ('Received', 'Received'))
bank = models.ForeignKey(Bank, on_delete=models.CASCADE)
project = models.ForeignKey(Project, on_delete=models.CASCADE)
file = models.ForeignKey(File, on_delete=models.CASCADE)
salesperson = models.ForeignKey(SalesPerson, on_delete=models.CASCADE)
paymentmode = models.ForeignKey(PaymentModes, on_delete=models.CASCADE)
amount = models.PositiveIntegerField()
chequeno = models.CharField(max_length=50, unique=True)
chequedate = models.DateField()
paymentdate = models.DateField()
remark = models.TextField(blank=True, null=True)
user = models.ForeignKey(User, on_delete=models.CASCADE)
accountant_received_by = models.ForeignKey(User, related_name='%(class)s_accountant_received_by', on_delete=models.CASCADE, null = True)
accountant_received_date = models.DateTimeField(default=datetime.now)
create_date = models.DateTimeField(default=datetime.now)
activation_status = models.CharField(max_length=20, choices=activation_enum, default='Active')
accounts_status = models.CharField(max_length=20, choices=accounts_status_enum, default='Pending')
Pass an instance to the serializer, so it can know that it should do an update.
instance = BankPaymentHistory.objects.filter(id=id_payment).first()
serializer = BankPaymentUpdateSerializer(instance=instance, data=data, partial=True, many=False)

DRF post request multiple inner serializers

i have three models named Smoker,Switch,Survey i have smoker as foreign key in Switch model and switch as foreign key in Survey model
class Smoker(models.Model):
first_name = models.CharField(max_length=50, blank=True, null=True)
last_name = models.CharField(max_length=50, blank=True, null=True)
mobile = models.IntegerField(null=True, blank=True)
gender = models.BooleanField(blank=True, null=True)
age = models.ForeignKey(Age,models.DO_NOTHING,blank=True, null=True)
occupation = models.ForeignKey(Occupation, models.DO_NOTHING, blank=True, null=True)
class Switch(models.Model):
time = models.TimeField(blank=True, null=True)
count_outers = models.IntegerField(blank=True, null=True)
count_packs = models.IntegerField(blank=True, null=True)
smoker = models.ForeignKey(Smoker, models.DO_NOTHING, blank=True, null=True)
new_brand = models.ForeignKey(NewBrand, models.DO_NOTHING, blank=True, null=True)
new_sku = models.ForeignKey(NewSku, models.DO_NOTHING, blank=True, null=True)
# def __str__(self):
# return self.time.strftime("%H:%M")
class Survey(models.Model):
user = models.ForeignKey(User, models.DO_NOTHING, blank=True, null=True)
date = models.DateField(null=True, blank=True)
bool_switch = models.BooleanField(null=True, blank=True)
reason = models.ForeignKey(Reason, models.DO_NOTHING, null=True, blank=True)
shift = models.ForeignKey(ShiftingTime, models.DO_NOTHING, null=True, blank=True)
current_brand = models.ForeignKey(CurrentBrand, models.DO_NOTHING, null=True, blank=True)
current_sku = models.ForeignKey(CurrentSku, models.DO_NOTHING, null=True, blank=True)
pos = models.ForeignKey(Pos, models.DO_NOTHING, null=True, blank=True)
switch = models.ForeignKey(Switch, models.DO_NOTHING, null=True, blank=True)
and here i have my serializers:
class SmokerSerializer(serializers.ModelSerializer):
class Meta:
model = Smoker
fields = '__all__'
class SwitchSerializer(serializers.ModelSerializer):
smoker = SmokerSerializer()
class Meta:
model = Switch
fields = '__all__'
def create(self, validated_data):
smoker_data = validated_data.pop('smoker', None)
if smoker_data:
smoker = Smoker.objects.create(**smoker_data)
validated_data['smoker'] = smoker
return Switch.objects.create(**validated_data)
class SurveySerializer(serializers.ModelSerializer):
switch = SwitchSerializer()
class Meta:
model = Survey
fields = '__all__'
def create(self, validated_data):
switch_data = validated_data.pop('switch', None)
if switch_data:
switch = Switch.objects.create(**switch_data)
validated_data['switch'] = switch
return Survey.objects.create(**validated_data)
and i make a generic for for Creating and listing all the survey
class SurveyCreateAPIView(generics.ListCreateAPIView):
def get_queryset(self):
return Survey.objects.all()
serializer_class = SurveySerializer
for each displayed survey i have to display switch data related to it and inside the switch object i need to display the smoker object inside it so each survey object must look like this
{
"id": 11,
"switch": {
"id": 12,
"smoker": {
"firstname":"sami",
"lastname:"hamad",
"mobile":"7983832",
"gender":"0",
"age":"2",
"occupation":"2"
},
"time": null,
"count_outers": 5,
"count_packs": 7,
"new_brand": 2,
"new_sku": 2
},
"date": "2018-12-08",
"bool_switch": true,
"user": 7,
"reason": 3,
"shift": 2,
"current_brand": 6,
"current_sku": 4,
"pos": 2
},
but when i make a POST request it is giving me this error
ValueError at /api/v2/surveysync/ Cannot assign
"OrderedDict([('first_name', 'aline'), ('last_name', 'youssef'),
('mobile', 7488483), ('gender', False), ('age', ),
('occupation', )])": "Switch.smoker" must be
a "Smoker" instance.
so please help and thank you so much!
You're going along the right path but you're saving the switch objects manually instead of allowing the SwitchSerializer do it for you. Same thing with create method in switch serializer. It should be this way:
class SmokerSerializer(serializers.ModelSerializer):
class Meta:
model = Smoker
fields = '__all__'
class SwitchSerializer(serializers.ModelSerializer):
smoker = SmokerSerializer()
class Meta:
model = Switch
fields = '__all__'
def create(self, validated_data):
smoker_data = validated_data.pop('smoker', None)
if smoker_data:
serializer = SmokerSerializer(data=smoker_data, context=self.context)
if serializer.is_valid():
validated_data['smoker'] = serializer.save()
return super().create(validated_data)
class SurveySerializer(serializers.ModelSerializer):
switch = SwitchSerializer()
class Meta:
model = Survey
fields = '__all__'
def create(self, validated_data):
switch_data = validated_data.pop('switch', None)
if switch_data:
serializer = SwitchSerializer(data=switch_data, context=self.context)
if serializer.is_valid():
validated_data['switch'] = serializer.save()
return super().create(validated_data)
In SwitchSerializer you defined the create function as a method of the inner Meta class and not as a member of SwitchSerializer class. Try this
class SwitchSerializer(serializers.ModelSerializer):
smoker = SmokerSerializer()
class Meta:
model = Switch
fields = '__all__'
def create(self, validated_data):
smoker_data = validated_data.pop('smoker', None)
if smoker_data:
smoker = Smoker.objects.create(**smoker_data)
validated_data['smoker'] = smoker
return Switch.objects.create(**validated_data)

Django rest framework - cant serialize query set

I try to serialize query set
def do(self):
reservations = Reservation.objects.all()
serializer = ReservationSerializer(data=reservations, many=True)
if serializer.is_valid():
encoded_data = json.dumps(serializer.data)
r = requests.post('http://httpbin.org/post', headers={'Content-Type': 'application/json'}, data=encoded_data)
print(r.text)
else:
print(serializer.errors)
And I always get error of
{u'non_field_errors': [u'Expected a list of items but got type "QuerySet".']}
I tried to use values() on query set, and then convert to list, but this way I get objects without nested models
model
class Reservation(models.Model):
start = models.DateField(verbose_name='Заезд', auto_now=False, auto_now_add=False, blank=False)
end = models.DateField(verbose_name='Выезд', auto_now=False, auto_now_add=False, blank=False)
check_in_time = models.TimeField(verbose_name='Время заезда', blank=False)
check_out_time = models.TimeField(verbose_name='Время выезда', blank=False)
has_refund = models.BooleanField(verbose_name='Возвратная бронь', default=True)
payed = models.BooleanField(verbose_name='Оплачено', default=False)
reserved_days = models.ManyToManyField(Day, blank=False)
additional_services = models.ManyToManyField(AdditionalService)
guest_name = models.CharField(verbose_name='Имя гостя', max_length=200, blank=True)
reservation_number = models.CharField(verbose_name='Номер брони', max_length=200, blank=True)
class AdditionalService(models.Model):
payment_date = models.CharField(verbose_name='Дата оплаты', max_length=200, blank=True)
payment_type = models.CharField(verbose_name='Форма оплаты', max_length=200, blank=False)
service = models.CharField(verbose_name='Услуга', max_length=200, blank=False)
quantity = models.IntegerField(blank=False)
price = models.FloatField(blank=False)
class Day(models.Model):
date = models.DateField(auto_now=False, auto_now_add=False)
price = models.FloatField()
payment_method = models.CharField(max_length = 200, blank=True)
payment_date = models.CharField(max_length=200, blank=True)
room = models.ForeignKey(Room, null=True, blank=True, verbose_name='Номер', on_delete=models.CASCADE)
class Room(models.Model):
name = models.CharField(max_length = 200, null=True)
id = models.AutoField(primary_key=True)
room_id = models.CharField(max_length = 200, null=False)
def __unicode__(self):
return self.name
serializers
class ReservationSerializer(serializers.ModelSerializer):
reserved_days = DaySerializer(many=True)
additional_services = AdditionalServicesSerializer(many=True)
class Meta:
model = Reservation
fields = [
'start',
'end',
'check_in_time',
'check_out_time',
'reserved_days',
'additional_services',
'has_refund',
'payed',
'guest_name',
'reservation_number',
]
class DaySerializer(serializers.ModelSerializer):
room = RoomSerializer()
class Meta:
model = Day
fields = [
'date',
'price',
'payment_method',
'payment_date',
'room',
]
class AdditionalServicesSerializer(serializers.ModelSerializer):
class Meta:
model = AdditionalService
fields = [
'payment_date',
'payment_type',
'service',
'quantity',
'price',
]
class RoomSerializer(serializers.ModelSerializer):
class Meta:
model = Room
fields = [
'room_id',
]
For serialization you don't need to use data keyword, just pass queryset as first positional argument:
serializer = ReservationSerializer(reservations, many=True)
return serializer.data