Django CreateView get_initial Foreign Key - python

I have a form and I am trying to use the get_initial method to set a foreign key. The model is
class CardioRecord(models.Model):
date_uploaded = models.DateField(auto_now=True)
client = models.ForeignKey(User, on_delete=models.CASCADE)
run_dist = models.FloatField(blank=True, null=True)
run_time = models.FloatField(blank=True, null=True)
The form is
class CardioRecordForm(forms.ModelForm):
class Meta:
model = CardioRecord
fields = [
'client',
'run_dist',
'run_time',
]
labels = {
'run_dist': 'Distance (km)',
'run_time': 'Time (min)',
}
widgets = {
'client': forms.HiddenInput()
}
The view is
class CardioCreateView(CreateView):
model = CardioRecord
form_class = CardioRecordForm
template_name = 'training/cardio_form.html'
def get_initial(self):
initial = super(CardioCreateView, self).get_initial()
initial['client'] = self.request.user.pk
return initial
and the error that I am getting is
null value in column "client_id" violates not-null constraint
which looks like the initial value is not being passed to the form. How do I pass the Foreign Key to the form?

Using a hidden field doesn't stop the user from editing the value. If you want to set the value in the view, then remove it from fields in the form:
class CardioRecordForm(forms.ModelForm):
class Meta:
model = CardioRecord
fields = [
'run_dist',
'run_time',
]
Then set the value on the form's instance in the form_valid method:
class CardioCreateView(CreateView):
def form_valid(self, form):
form.instance.client = self.request.user
return super(CardioCreateView. self).form_valid(form)
You can then remove your get_initial method.

Related

Django serializer not returning all fields in response

I have following serializer in Django. The serializer is however not returning all the fields in the response. 'amount' and 'amount_ordered' are not returned, all other fields are.. key point: these are the only 2 fields I have in my model. So I thought I only need to add them in the fields list?
class AdminOrderItemSerializer(serializers.Serializer):
purchase_order = serializers.CharField(source="get_purchase_order")
reference = serializers.CharField(source="get_reference")
class Meta:
model = OrderItem
fields = [
"purchase_order",
"reference",
"amount",
"ordered_amount",
]
def create(self, validated_data):
pass
def update(self, instance, validated_data):
pass
Model:
class OrderItem(models.Model):
ordered_amount = models.IntegerField(validators=[MinValueValidator(0)])
amount = models.IntegerField(default=0)
order = models.ForeignKey(
Order, on_delete=models.CASCADE, related_name="order_items"
)
def get_purchase_order(self):
return self.order.purchase_order
def get_reference(self):
return self.order.reference
Use serializers.ModelSerializer instead of serializers.Serializer as
class AdminOrderItemSerializer(serializers.ModelSerializer):
# your code

Django Rest Framework I can't use Serializer save model of have foreign key

I'm a Django Rest Framework and Django newbie
i can use random data to make stages but i can't use serializer to add new stages.
My model and serializer
class Stage(models.Model):
class Meta:
db_table = 'stage'
stage_id = models.AutoField(primary_key=True)
stage_name = models.CharField(max_length=64, null=False)
company = models.ForeignKey(
Company,
db_column='id',
on_delete=models.CASCADE,
)
class StageSerializer(ModelSerializer):
stage_id = IntegerField(read_only=True)
class Meta:
model = Stage
fields = [
'stage_id',
'stage_name',
'company',
]
def update(self, instance, validated_data):
pass
def create(self, validated_data):
# create stages
stage = create_stage(**validated_data)
return stage
view.py
class StageListAPIView(APIView):
def post(self, request, company_id):
data = request.data.copy()
company = get_company_by_id(company_id)
data['company'] = company.pk
serializer = StageSerializer(data=data)
if not serializer.is_valid(raise_exception=True):
return Response(serializer.errors, status=HTTP_400_BAD_REQUEST)
new_data = serializer.validated_data
serializer.save(company=company)
return Response(new_data, status=HTTP_200_OK)
request.data
<QueryDict: {'stage_name': ['kAkSdKq9Gt'], 'company': [6]}>
i will receive error:
TypeError: Object of type Company is not JSON serializable
i can't understand it and i don't know how to use serializer to save foreign key.
You need to serialize the Company instance before you can include it in your StageSerializer.
A simple example would be something like
class CompanySerializer(ModelSerializer):
class Meta:
model = Company
fields = '__all__'
And then to include that in your StageSerializer:
class StageSerializer(ModelSerializer):
stage_id = IntegerField(read_only=True)
company = CompanySerializer(source='company', read_only=True)
class Meta:
model = Stage
fields = [
'stage_id',
'stage_name',
'company',
]

Related field id in POST request in Django Rest Framework

I am creating the object with just only related field id. I have searched a lot but couldn't get the answer. Here is my code
models.py:
class Resturant(models.Model):
name = models.CharField(_('name'), max_length=100)
class Menu(models.Model):
resturant_id = models.OneToOneField(Resturant, related_name='resturant', on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now=True)
serializers.py:
class MenuSerializer(serializers.ModelSerializer):
resturant_id = serializers.PrimaryKeyRelatedField(read_only=True)
class Meta:
model = Menu
fields = ['id', 'created_at', 'resturant_id']
views.py:
class CreateMenuAPIView(APIView):
def post(self, request, *args, **kwargs):
serializer = MenuSerializer(data=request.data)
if serializer.is_valid(raise_exception=True):
serializer.save()
return Response(serializer.data, status=status.HTTP_200_OK)
return Response(status=status.HTTP_400_BAD_REQUEST)
I am getting this error while sending { "resturant_id": 2 } in POST request.
DETAIL: Failing row contains (14, 2018-04-02 09:36:43.261849+00, null).
The above exception (null value in column "resturant_id" violates not-null constraint
Any help would be appreciated !
you can override method create for find Restaurant object or create if not exist. and only edit serializer.
serializer.py
class MenuSerializer(serializers.ModelSerializer):
resturant_id = serializers.PrimaryKeyRelatedField(read_only=True)
class Meta:
model = Menu
fields = ['id', 'created_at', 'resturant_id']
def create(self, validated_data):
id_param = validated_data.pop('resturant_id')
resturant = Resturant.objects.get_or_create(id=id_param)[0]
menu = Menu.objtects.create(resturant_id=resturant.id)
return menu
if not work you can delete this line:
resturant_id = serializers.PrimaryKeyRelatedField(read_only=True)
returant_id = serializers.PrimaryKeyRelatedField(read_only=True)
Could you try giving read_only=False
Could you check the spelling,
returant_id is used in serializers field,'s' is missing.
'resturant_id' is used in fields list
You are using a model serializer and have overridden 'returant_id'.
class MenuSerializer(serializers.ModelSerializer):
returant_id = serializers.PrimaryKeyRelatedField(queryset=Resturant.objects.all())
try to change the serializer to
class MenuSerializer(serializers.ModelSerializer):
resturant_id = serializers.PrimaryKeyRelatedField()
class Meta:
model = Menu
fields = ['id', 'created_at', 'resturant_id']
if read_only=True then it will not write into database.

is not a valid value for a primary key - ManyToManyField

When i try to save ModelForm with models.ManyToManyField it throws an error 'Value is not a valid value for a primary key'.
Also the initial values that I set in 'def __init__' only works in admin panel, but not in frontend.
And how do i configure it to show only if no data in database, but if data is in it will shows initial in form (to edit)? By the wa there is no little '+' near the field, so how user will add values?
forms.py:
class UserprojectForm(forms.ModelForm):
class Meta:
model = Userproject
fields = ['name', 'user', 'description', 'vk_groups', 'source_name', 'date_updated', 'date_until'] #'date_created', cannot add django.core.exceptions.FieldError: Unknown field(s) (date_created) specified for Userproject
# widgets = {
# 'vk_groups': forms.Textarea(attrs={'cols': 80, 'rows': 10}),
# 'source_name': forms.Textarea(attrs={'cols': 80, 'rows': 5}),
# }
def __init__(self, *args, **kwargs):
super(UserprojectForm, self).__init__(*args, **kwargs)
#vk_groups = [(v.id,v.buid) for v in Userproject.objects.exclude(buid='').order_by('buid')]
vk_groups = (('https://vk.com/southitpark','https://vk.com/southitpark'), ('https://vk.com/graphgrail', 'https://vk.com/graphgrail'))
source_names = (('Вконтакте', 'Вконтакте'), ('Facebook', 'Facebook'), ('Twitter (скоро)', 'Twitter (скоро)'))
self.fields['vk_groups'].choices = vk_groups
self.fields['source_name'].choices = source_names
models.py:
class Userproject(models.Model):
class Meta:
verbose_name = u'Проект мониторинга'
verbose_name_plural = u'Проекты мониторинга'
vk_groups = models.ManyToManyField(Vkgroupstomonitor, null=True, blank=True, related_name="vkgroups", verbose_name=_("Группы Вконтакте"))
source_name = models.ManyToManyField(Sourcetomonitor, null=True, blank=True, related_name="sourcename", verbose_name=_("Название источника"))
name = models.CharField(u'Название проекта', unique=True, max_length=255)
.......
views.py:
class UserprojectCreate(CreateView):
model = Userproject
template_name = 'userproject_form.html'
success_url = reverse_lazy('userproject_list')
fields = ['name', 'description', 'vk_groups', 'source_name', 'date_updated']
def form_valid(self, form):
form.instance.user = self.request.user
return super(UserprojectCreate, self).form_valid(form)
Consider to specify queryset instead of choices. The latter does not seem to be a part of design of this field class at all.
BTW, in my opinion, it would be better to include this into explicit declaration of the form`s fields rather than patch them in init method.

Over-riding update method in django modelViewSet

I'm having trouble defining an update method on a serializer class in django. This is my basic model
class Category(models.Model):
category = models.CharField(max_length = 100)
def __str__(self):
return self.category
class Items(models.Model):
category = models.ForeignKey(Category)
item = models.CharField(max_length = 100)
rate = models.DecimalField(max_digits = 20,decimal_places =2)
def __str__(self):
return self.item
and the below is my serializer:
class ItemSerializer(serializers.ModelSerializer):
category = serializers.CharField(source = 'category.category',read_only = True)
category_pk = serializers.IntegerField(source = 'category.pk')
class Meta:
model = Items
fields = ('pk','category','category_pk','item','rate',)
def update(self,instance,validated_data):
category_pk = validated_data.get('category_pk',instance.category_pk)
instance.category = Category.objects.get(pk = category_pk)
instance.item = validated_data.get('item',instance.item)
instance.rate = validated_data.get('rate',instance.rate)
instance.save()
return instance
I'm getting an error when using the PUT method from AJAX stating that the Item object does not have a category_pk field (but i'm not including that in the instance.save() method)
below is my AJAX request
$('#update-item').on('click',function(){
var dat = {
'category':$("#category-box").find('option[value='+cat_pk+']').text(),
'category_pk':$('#category-box').val(),
'item':$('#Items').val(),
'rate':$('#Rate').val()
};
console.log(dat);
$.ajax({
type : 'PUT',
url: 'http://127.0.0.1:8000/billing/items/'+pk+'/',
data : JSON.stringify(dat),
contentType: 'application/json',
crossDomain:true,
success : function(json){
alert('ok');
},
error : function(json){
alert('error with PUT')
}
});
});
I'm over-riding the update method because rest framework threw an error intially stating that it cant write nested fields.
KJ
By default DRF will use the pk for the category field on a ModelSerializer, but in your case you are setting the category field as read_only=True, and on your model is no category_pk field. I would change the serializer like this, and then post the pk to the category field and not the category_pk field. You can then also remove the update method override.
class ItemSerializer(serializers.ModelSerializer):
# I assume you changed the category field to readonly to display the text of the category
category_name = serializers.ReadOnlyField(source='category.category')
class Meta:
model = Items
fields = ('pk','category','category_name','item','rate',)

Categories

Resources