I have a model called Reporter and a straight-forward ReporterForm and a formset based on it called ReporterFormset as below:
class Reporter(models.Model):
name = models.CharField(max_length=100)
class ReporterForm(forms.ModelForm):
class Meta:
model = Reporter
fields = '__all__'
ReporterFormset = modelformset_factory(Reporter, form=ReporterForm, extra=1, can_delete=True)
I want to save new data coming as list of dictionaries like:
data = [
{'name': 'x'},
{'name': 'y'}
]
So, I tried to do:
reporters_formset = ReporterFormset(initial=data)
But it shows that the formset is not valid after executing reporters_formset.is_valid() and with empty reporters_formset.errors.
How can I achieve such?
Related
I am trying to make a nested serializer but when I run the following code it gives me an empty list. I tried to replicate the solution of this question and my problem is exactly similar
The only difference is in that answer serializer.Serializer is used but I am using Model Serializer
class hhhSerializer(serializers.Modelserializer):
id = serializers.IntegerField(read_only=True)
name = serializers.CharField(read_only=True)
class Meta:
model = ItemBatch
fields = ('id','name')
class dispatchhistorySerializer(serializers.ModelSerializer):
truck_name = ReadOnlyField(source='truck_name.name')
truck_type = ReadOnlyField(source='truck_type.name')
items = hhhSerializer(many=True)
class Meta:
model = DispatchPlan
fields = "__all__"
Output:
"id": 35,
"truck_name": "24 ft mxl 14 Ton",
"truck_type": "Container",
"items": [
{},
{},
{},
{},
{},
{},
{},
{},
{},
{}
],
You have to declare the field explicitly at DispatchHistorySerializer.Meta.fields; now, as personal recommendation avoid always "all" in the field list
This code should work (I had renamed your classes to comform python convention)
class HhhSerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True)
name = serializers.CharField(read_only=True)
class Meta:
model = ItemBatch
fields = ('id','name')
class DispatchHistorySerializer(serializers.ModelSerializer):
truck_name = ReadOnlyField(source='truck_name.name')
truck_type = ReadOnlyField(source='truck_type.name')
items = HhhSerializer(many=True) # 2) here we say how to serialize 'items'
class Meta:
model = DispatchPlan
fields = ('id', 'truck_name', 'truck_type', 'items',) # 1) here we say: include 'items' please
EDIT: if using ModelSerializer, define which model in the Meta class; if it isn't a ModelSerializer, use a simple Serializer instead
TL;DR: What could be the reason the incoming data for one of my serializers does not get processed?
I'm working on a serializer for a nested relationship. The serializer should get a list of UUIDs, so that I can make many to many relationships. Here is the model:
class Order(
UniversallyUniqueIdentifiable,
SoftDeletableModel,
TimeStampedModel,
models.Model
):
menu_item = models.ForeignKey(MenuItem, on_delete=models.CASCADE)
custom_choice_items = models.ManyToManyField(CustomChoiceItem, blank=True)
price = models.ForeignKey(MenuItemPrice, on_delete=models.CASCADE)
amount = models.PositiveSmallIntegerField(
validators=[MinValueValidator(MINIMUM_ORDER_AMOUNT)]
)
Here is the data (my post body) with which I hit the route in my tests:
data = {
"checkin_uuid": self.checkin.uuid,
"custom_choice_items": [],
"menu_item": self.menu_item.uuid,
"price": self.menu_item_price.uuid,
"amount": ORDER_AMOUNT,
}
response = self.client.post(self.order_consumer_create_url, self.data)
Note that the empty list for custom_choice_items does not change anything. Even if I fill it with values the same error occurs. And last but not least here are the serializers:
class CustomChoiceItemUUIDSerializer(serializers.ModelSerializer):
"""Serializer just for the uuids, which is used when creating orders."""
class Meta:
model = CustomChoiceItem
fields = ["uuid"]
....
# The serializer that does not work
class OrderSerializer(serializers.ModelSerializer):
menu_item = serializers.UUIDField(source="menu_item.uuid")
custom_choice_items = CustomChoiceItemUUIDSerializer()
price = serializers.UUIDField(source="price.uuid")
wish = serializers.CharField(required=False)
class Meta:
model = Order
fields = [
"uuid",
"menu_item",
"custom_choice_items",
"price",
"amount",
"wish",
]
The problem is now, that when I leave out many=True, I get the error:
{'custom_choice_items': [ErrorDetail(string='This field is required.', code='required')]}
And If I set many=True I just simply don't get any data. By that I mean e.g. the value of validated_data["custom_choice_items"] in the serializers create() method is just empty.
What goes wrong here?
I even checked that the data is in the request self.context["request"].data includes a key custom_choice_items the way I pass the data to this view!
EDIT: Here is the data I pass to custom_choice_items:
data = {
“checkin_uuid”: self.checkin.uuid,
“custom_choice_items”: [{“uuid”: custom_choice_item.uuid}],
“menu_item”: self.menu_item.uuid,
“price”: self.menu_item_price.uuid,
“amount”: ORDER_AMOUNT,
}
self.client.credentials(HTTP_AUTHORIZATION=“Token ” + self.token.key)
response = self.client.post(self.order_consumer_create_url, data)
When you post data using the test api client, if the data contains nested structure you should use format=json, like this:
response = self.client.post(self.order_consumer_create_url, data, format='json')
Did you override .create method in the serializer? Something like this should work:
from django.db import transaction
class OrderSerializer(serializers.ModelSerializer):
# your fields and Meta class here
#transaction.atomic
def create(self, validated_data):
custom_choice_items = validated_data.pop('custom_choice_items')
order = super().create(validated_data)
order.custom_choice_items.add(*custom_choice_items)
return order
By the way you don't really need to define CustomChoiceItemUUIDSerializer if is just the primary key of that.
I have a many to many field linked with my model1. Now, I created a form for this model1 and added this many to many field as a form field and used FilteredSelectMultiple widget to edit this. Now, the problem is the related many to many field has a soft delete option, which I am tracking with active field in the model2. So, now in the form all the objects are displayed even if they are deleted, is there any way I can show the objects which have active as true in this form field.
My model form looks as follows:
class Editform(form.ModelForm):
class Media:
css = ..
js = ..
class Meta:
Model = model1
fields = [ "x", "y", "ManytoManyfield"]
widgets = {
'ManytoManyfield': FilteredSelectMultiple("Displaay name", False)
}
This answer is close to what you want. I think this may work.
You create an extra field in your ModelForm, populating it with a query.
class Editform(form.ModelForm):
many_to_many_field_active = forms.ChoiceField(choices=[(m2m.id, m2m.name) for m2m in Model2.objects.filter(active=True)])
class Meta:
#...
widgets = {
'many_to_many_field_active': Select(attrs={'class': 'select'}),
I solved this using the multiplechoicefield in my model form as follows.
def __init__(self, *args, **kwargs):
many_to_m_initial = kwargs['instance'].model2.all()
choices = [(m2m.id, m2m.name) for m2m in Model2.objects.filter(active=True)]
self.fields['my_field'] = forms.MultipleChoiceField(choices = choices, widget=FilteredSelectMultiple("verbose name", is_stacked=False, choices=choices))
self.initial['my_field'] = [ m2m.pk fpr m2m in many_to_m_initial ]
I want to store JSON fragments in TextField of my model with JSON:
class A(models.Model):
name = models.CharField(max_length=200)
people = models.TextField()
I have serializer class:
class ASerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = A
fields = ('name', 'people')
How can I told Django REST Framework to treat people string like JSON, not like string. E.g. when people is [ {"name":"A", "surname":"B"}] I want have in JSON generated by Django REST framework
"people" : [ {"name":"A", "surname":"B"}]
and not
"people" : "[ {\"name\":\"A\", \"surname\":\"B\"}]"
Edit: I change ASerializer class and used JSONField from django-jsonfield and everything works. New code below, transform_people method serves to serialization and validate_people to deserialization:
class ASerializer(serializers.ModelSerializer):
def transform_people(self, obj, value):
if obj is None:
return obj
else:
return obj.people
def validate_people(self, attrs, source):
return attrs
class Meta:
model = A
Convert your response to json object
import json
## In this case lets say
response = [{"name":"A", "surname":"B"}]
data = json.dumps(response)
print data
You could use serializers.JSONField
class ASerializer(serializers.HyperlinkedModelSerializer):
people = serializers.JSONField()
class Meta:
model = A
fields = ('name', 'people')
I am writing a view that uses POST data to display multiple forms with differing prefilled FK's
I have a ModelForm in forms.py
class SurveyForm(forms.ModelForm):
class Meta:
model = Survey
who's model looks like this...
class Survey(models.Model):
student = models.ForeignKey(Student)
surveyset = models.ForeignKey(SurveySet)
cei_0 = models.BooleanField()
cei_1 = models.BooleanField()
My view looks kind of like this so far
# ... after building a list from POST we essentially have:
list_of_studentids = [1,3,2,6,7,45]
students = []
for i in list_of_student_ids:
students.append(Student.objects.filter(id=i))
SurveyFormSet = formset_factory(SurveyForm, extra=6)
formset = SurveyFormSet(initial=[
{'surveyset': SurveySet.create(),
'student': ?????,}
])
How do I return a bunch of forms with different student FK's and the same surveyset FK?
You need to pass an instance attribute to the form:
prefilled_survey = Survey(student=student_instance, surveyset=surveyset_instance)
form = SurveyForm(request.POST or None, instance=prefilled_survey)