Creating ModelForm with EmbeddedModelField and customize fields within EmbeddedModelField - django

I have a model (parentmodel) which is having a EmbeddedModelField (embedmodel). This is basically a document in MongoDB. Below is the Model classes
class embedmodel(models.Model):
sendto = models.CharField(max_length=10)
sendtouser = models.CharField(max_length=15)
sendtogroup = models.CharField(max_length=15)
class parentmodel(models.Model):
name = models.CharField(max_length=30, unique=True, primary_key=True)
type = models.CharField(max_length=11)
enabled = models.BooleanField()
rule = models.EmbeddedModelField(model_container=embedmodel)
class Meta:
managed = False
db_table = 'parentmodel'
And this is how my document in mongodb looks like
{
'name': 'rule1',
'type': 'static',
'enabled': True,
'rule': {
'sendto': 'external',
'sendtouser': 'sam',
'sendtogroup': 'vendor'
}
}
I am trying to create a form which helps me create new rules and this is what i have in forms.py where i want to customize the form fields as well.
class RulesForm(forms.ModelForm):
name = forms.CharField(max_length=30, required=True)
type = forms.CharField(max_length=11, required=True)
enabled = forms.BooleanField(widget=forms.CheckboxInput)
class Meta:
model = parentmodel
fields = ['name', 'type', 'enabled', 'rule']
How to do customize the fields being displayed from embedmodel? I tried the below but no luck.
class RulesForm(forms.ModelForm):
name = forms.CharField(max_length=30, required=True)
type = forms.CharField(max_length=11, empty_value="UserDefined", required=True
enabled = forms.BooleanField(widget=forms.CheckboxInput)
sendto = forms.ChoiceField(widget=forms.Select, choices=[(1, 'External'), (2, 'Internal')])
sendtouser = forms.CharField(max_length=30, required=False)
sendtogroup = forms.CharField(max_length=30, required=False)
class Meta:
model = Rules
fields = ['name', 'type', 'enabled', 'rule']
and
class RulesForm(forms.ModelForm):
name = forms.CharField(max_length=30, required=True)
type = forms.CharField(max_length=11, empty_value="UserDefined", required=True
enabled = forms.BooleanField(widget=forms.CheckboxInput)
embedmodel.sendto = forms.ChoiceField(widget=forms.Select, choices=[(1, 'External'), (2, 'Internal')])
embedmodel.sendtouser = forms.CharField(max_length=30, required=False)
embedmodel.sendtogroup = forms.CharField(max_length=30, required=False)
class Meta:
model = Rules
fields = ['name', 'type', 'enabled', 'rule']

I was able to solve this by following https://medium.com/#SiddyZen/create-embedded-models-using-django-admin-3ecc38a00879 (in Section with heading The ‘embedded model’)Thanks to the author SiddyZen :). Did the below change in models.py
from django import forms
class embedmodel(models.Model):
sendto = models.CharField(max_length=10)
sendtouser = models.CharField(max_length=15)
sendtogroup = models.CharField(max_length=15)
class embedmodelForm(forms.ModelForm):
sendto = forms.ChoiceField(widget=forms.Select, choices=[(1, 'External'), (2, 'Internal')])
sendtouser = forms.CharField(max_length=15, required=False)
sendtogroup = forms.CharField(max_length=15, required=False)
class Meta:
model = embedmodel
fields = ['sendto', 'sendtouser', 'sendtogroup']
class parentmodel(models.Model):
name = models.CharField(max_length=30, unique=True, primary_key=True)
type = models.CharField(max_length=11)
enabled = models.BooleanField()
rule = models.EmbeddedModelField(model_container=embedmodel, model_form_class=embedmodelForm)
class Meta:
managed = False
db_table = 'parentmodel'

Related

KeyError Post DjangoRestFramework

I'm new on Django Rest Framework and when I want to POST data I get a error: KeyError: 'id_area' I do not know what I'm doing wrong. Here's my code:
in my models.py
class Area(models.Model):
id_area = models.AutoField(primary_key=True)
APM = 'apm'
BUSINESS = 'business'
DESARROLLO = 'desarrollo'
SISTEMAS = 'sistemas'
ATENTUSIANOS_CHOICES = (
(APM, 'Apm'),
(BUSINESS, 'Business'),
(DESARROLLO, 'Desarrollo'),
(SISTEMAS, 'Sistemas'),
)
nombre = models.CharField(max_length=255, choices=ATENTUSIANOS_CHOICES)
class Meta:
verbose_name = 'Área'
verbose_name_plural = 'Áreas'
def __str__(self):
return self.nombre
class Atentusiano(models.Model):
id_atentusiano = models.AutoField(primary_key=True)
nombre = models.CharField(max_length=255, blank=False, null=False)
apellido = models.CharField(max_length=255, blank=False, null=False)
correo = models.CharField(max_length=255, blank=False, null=False, unique=True)
anexo = models.CharField(max_length=255, blank=True, null=True)
area = models.ForeignKey(Area, related_name='areas', on_delete=models.CASCADE)
class Meta:
verbose_name = 'Atentusiano'
verbose_name_plural = 'Atentusianos'
ordering = ['nombre']
def __str__(self):
return self.nombre + ' ' + self.apellido
in my serializers.py
class AreaSerializer(serializers.ModelSerializer):
areas = serializers.CharField(read_only=True)
class Meta:
model = Area
fields = ('id_area', 'nombre', 'areas')
class AtentusianoSerializer(serializers.ModelSerializer):
atentusianos = serializers.CharField(read_only=True)
area = serializers.CharField(source='area.nombre', read_only=True)
id_area = serializers.CharField(source='area.id_area')
class Meta:
model = Atentusiano
fields = ['id_atentusiano', 'nombre', 'apellido', 'correo', 'anexo', 'id_area', 'area', 'atentusianos']
def create(self, validated_data):
area_data = validated_data.pop('id_area')
area = models.Area.objects.create(**area_data)
atentusiano = models.Atentusiano.objects.create(area=area, **validated_data)
return atentusiano
And in my views.py
class AtentusianoView(viewsets.ModelViewSet):
queryset = Atentusiano.objects.all()
serializer_class = AtentusianoSerializer
class AreaView(viewsets.ModelViewSet):
queryset = Area.objects.all()
serializer_class = AreaSerializer
The problem is that when I want to Post data, for example:
{
"nombre": "name",
"apellido": "lastname",
"correo": "email#gmail.com",
"anexo": "1364",
"id_area": "1"
}
i got this error area_data = validated_data.pop('id_area')
KeyError: 'id_area'
I need help please
you should pop like this,
class AtentusianoSerializer(serializers.ModelSerializer):
.....
.....
class Meta:
model = Atentusiano
fields = ['id_atentusiano', 'nombre', 'apellido', 'correo', 'anexo', 'id_area', 'area', 'atentusianos']
def create(self, validated_data):
id_area = validated_data.pop('area')['id_area'] # here the correction
area = Area.objects.create(id_area=id_area) # an additional correction
atentusiano = Atentusiano.objects.create(area=area, **validated_data)
return atentusiano
EDIT: As id_area value, you are passing a string instead of an integer which will through another error. Also not,
area = models.Area.objects.create(**area_data)
it should be,
area = Area.objects.create(id_area=id_area)

Django - Custom ModelAdmin form not overriding default models

I have a model defined
class subnet(models.Model):
subnet_id = models.AutoField(primary_key=True)
subnet_pod = models.ForeignKey(pod, null=True, on_delete=models.SET_NULL, verbose_name='Select Pod')
subnet_number = models.IntegerField(verbose_name='VLAN/SVI Number')
subnet_description = models.CharField(max_length=10, verbose_name='Subnet Description')
LAYER_CHOICES = (
('Layer2', 'Layer2'),
('Layer3', 'Layer3'),
)
subnet_layer = models.CharField(max_length=50, choices=LAYER_CHOICES,verbose_name='Layer2/3')
subnet_ip = models.CharField(max_length=50, verbose_name='Gateway IP/Mask')
vrf = models.ForeignKey(vrf,blank=True, null=True, on_delete=models.SET_NULL, verbose_name='Select VRF')
class Meta:
verbose_name = 'Subnet'
verbose_name_plural = 'Subnets'
def __str__(self):
return self.subnet_number
I want to override the subnet_ip and add a label and placeholder to it using a custom form, so I have:
class subnetForm(forms.ModelForm):
class Meta:
model = subnet
fields = ['subnet_number', 'subnet_description', 'subnet_layer', 'vrf']
widgets = {
'subnet_ip': forms.TextInput(attrs={'placeholder': 'e.g,: x.x.x.x/x'}),
}
However the placeholder does not get applied to the model and does not show in front-end.
I also have a admin.py:
class subnetAdmin(admin.ModelAdmin):
list_display = ('subnet_number','subnet_description','subnet_layer','subnet_ip','vrf')
ordering = ('-subnet_number',)
Any help is appreciated!!
Try this !
class subnetForm(forms.ModelForm):
subnet_number = <use same model field datatype> forms.CharField(label = 'subnet_number', widget = forms.TextInput(attrs = {'placeholder' : 'subnet number'}))
class Meta:
model = subnet
fields = ['subnet_number', __other_fields__]

How to do a relationship using DRF to another table without foreignKey

I can not do relatioships between two tables without relationships.
My models are :
class exampleModel(models.Model):
quantity = models.IntegerField(blank=False, null=True)
comment = models.CharField(max_length=100 , blank=True, null=True)
class Meta:
db_table = "example"
class Logger(models.Model):
id_table = models.IntegerField()
table = models.CharField(max_length=20 , blank=True, null=True)
comment = models.CharField(max_length=100 , blank=True, null=True)
action = models.CharField(max_length=100 , blank=True, null=True)
date_created = models.DateTimeField(auto_now_add=True)
class Meta:
db_table = "logger"
I already have filled logger Model, but , I have not be able made the exampleSerializer.
My serializers are:
class LoggerSerializer(serializers.ModelSerializer):
class Meta:
db_table = u'logger'
model = Logger
fields = '__all__'
class exampleSerializer(serializers.ModelSerializer):
last_log = LoggerSerializer(read_only=True)
class Meta:
db_table = 'example'
model = ExampleModel
fields = ( 'id' , 'last_log' , 'quantity')
in logger saves :
id_table : 'primary key of example',
table : 'example'
comment : 'custom comment',
action : "CRUD"
You can query last logger in view, then pass it to serializer in context.
Then do something like:
class exampleSerializer(serializers.ModelSerializer):
last_log = serializers.SerializerMethodField()
class Meta:
db_table = 'example'
model = ExampleModel
fields = ('id', 'last_log', 'quantity')
def get_last_log(self, obj):
last_log = obj.state(self.context['last_log'])
last_log_serializer = LoggerSerializer(last_log)
return last_log_serializer.data
You pass to context, with something like:
exampleSerializer(queryset, context ={'last_log': last_log_object})
Also You can do the query in exampleSerializer:
class exampleSerializer(serializers.ModelSerializer):
last_log = serializers.SerializerMethodField()
class Meta:
db_table = 'example'
model = ExampleModel
fields = ('id', 'last_log', 'quantity')
def get_last_log(self, obj):
logger_queryset =Logger.objects.filter(table = self.Meta.db_table, id_table = obj.id)
return LoggerSerializer(logger_queryset).data

Nested serializers in drf throws error with one to one field

My input json is :
{
"availability": "Current",
"drive_type": [{
"drive_name": "drive1",
"requirements": {
"performance_unit": "by_iops",
}
}]
}
I am getting error Cannot assign "
OrderedDict([('performance_unit', 'Basic')])":
"DriveType.requirements" must be a "Requirements" instance
.I am not able to figure it out to map in create method for one to one fields in tables
Below are my models.py
class ProductLine(models.Model):
availability = models.CharField(max_length=20, blank=True, null=True)
class Meta:
db_table = "product_line"
class DriveType(models.Model):
drive_name = models.CharField(max_length=20, blank=True, null=True)
product_line = models.ForeignKey(ProductLine, related_name="drive_type")
class Meta:
db_table = "drive_type"
class Requirements(models.Model):
performance_unit = models.CharField(max_length=100, blank=True, null=True)
drive_type = models.OneToOneField(DriveType,on_delete=models.CASCADE,primary_key=True,related_name="requirements")
class Meta:
db_table = "requirements"
Serializers.py :
class DriveTypeSerializer(serializers.ModelSerializer):
requirements = RequirementsSerializer(many = True)
class Meta:
model = DriveType
fields = (
"drive_name","workload_type")
class ProductLineSerializer(serializers.ModelSerializer):
drive_type = DriveTypeSerializer(many=True)
class Meta:
model = ProductLine
fields = ('availability', "drive_type")
def create(self, validated_data):
print("validate_data",validated_data)
drive_type_data = validated_data.pop("drive_type")
product_line = ProductLine.objects.create(**validated_data)
for drive_data in drive_type_data:
drive_type = DriveType.objects.create(product_line=product_line, **drive_data)
return product_line
You have one to one relationship of DriveType and Requirements
So remove many = True from DriveTypeSerializer for RequirementsSerializer
class DriveTypeSerializer(serializers.ModelSerializer):
requirements = RequirementsSerializer()
class Meta:
model = DriveType
fields = ("drive_name","workload_type")
Your input json has only one object of requirements not a list

Nested Serializers with multiple tables not working

I have the below tables in models.py.
class ProductLine(models.Model):
availability = models.CharField(max_length=20, blank=True, null=True)
series = models.CharField(max_length=20, blank=True, null=True)
model = models.CharField(max_length=20, blank=True, null=True)
class Meta:
db_table = "product_line"
class DriveType(models.Model):
drive_name = models.CharField(max_length=20, blank=True, null=True)
product_line = models.ForeignKey(ProductLine, related_name="drive_type")
class Requirements(models.Model):
performance_unit = models.CharField(max_length=100, blank=True, null=True)
drive_type = models.OneToOneField(DriveType,on_delete=models.CASCADE,primary_key=True)
class Meta:
db_table = "requirements"
class WorkloadType(models.Model):
workload_type_options = models.CharField(max_length=50, blank=True, null=True)
drive_type = models.OneToOneField(DriveType,on_delete=models.CASCADE,primary_key=True)
class Meta:
db_table = "workload_type"
I have below serializers:
class WorkloadTypeSerializer(serializers.ModelSerializer):
class Meta:
model = WorkloadType
fields = "__all__"
class RequirementsSerializer(serializers.ModelSerializer):
class Meta:
model = Requirements
fields = "__all__"
class DriveTypeSerializer(serializers.ModelSerializer):
requirements = RequirementsSerializer(many = False, read_only = True)
workload_type = WorkloadTypeSerializer(many=False,read_only=True)
class Meta:
model = DriveType
fields = (
"drive_name", "available_drive_type", "capacity", "raid_type", "raid_size", "workload", "workload_percentage",
"raid_groups", "compression", "compression_value","requirements","workload_type")
class ProductLineSerializer(serializers.ModelSerializer):
drive_type = DriveTypeSerializer(many=True, read_only=True)
class Meta:
model = ProductLine
fields = ('availability','series','model','drive_type')
In my views I have this:
class SnippetDetail(generics.RetrieveUpdateDestroyAPIView):
def get_queryset(self):
return ProductLine.objects.filter(id=self.kwargs.get("pk"))
serializer_class = ProductLineSerializer
I am getting output as below :
{
"availability": "Current",
"series": "3000",
"model": "2000",
"drive_type": [
{
"drive_name": "drive1",
"requirements": {
"drive_type": 2,
"performance_unit": "by_iops",
}
}
]
}
Why I am not able to see WorkLoadType tables data in json where as I am able to see Requirements data . I don't even see the field in json. Nested serializers only support a single relation tables
Answering my own question. Have to use related_name in the models for reverse relationship.
class Requirements(models.Model):
performance_unit = models.CharField(max_length=100, blank=True, null=True)
drive_type = models.OneToOneField(DriveType,on_delete=models.CASCADE,primary_key=True,related_name=requirements)
class Meta:
db_table = "requirements"
class WorkloadType(models.Model):
workload_type_options = models.CharField(max_length=50, blank=True, null=True)
drive_type = models.OneToOneField(DriveType,on_delete=models.CASCADE,primary_key=True,related_name=workload_type)