I want to access verbose name of models to put it as a key in serializer. But I can't find a way to do it.
My models are:
class ProductCategory(models.Model):
name = models.CharField(max_length=150, unique=True)
created_at = models.DateTimeField(default=timezone.now)
modified_at = models.DateTimeField(default=timezone.now)
def __str__(self):
return self.name
class DeviceTypeCategory(ProductCategory):
product_category = models.ForeignKey(ProductCategory, on_delete=models.CASCADE,
related_name="device_types")
class Meta:
verbose_name = _("Device type")
verbose_name_plural = _("Device types")
class DeviceBrandCategory(ProductCategory):
product_category = models.ForeignKey(ProductCategory, on_delete=models.CASCADE,
related_name="device_brands")
class PartTypeCategory(ProductCategory):
product_category = models.ForeignKey(ProductCategory, on_delete=models.CASCADE, related_name="part_types")
And my serializer:
class ProductCategorySerializer(serializers.ModelSerializer):
device_types = serializers.StringRelatedField(many=True)
device_brands = serializers.StringRelatedField(many=True)
part_types = serializers.StringRelatedField(many=True)
class Meta:
model = ProductCategory
fields = ('name', 'device_types', 'device_brands', 'part_types')
Any suggestions would help. I would also be glad to hear out other ideas on how to create categories model. I've tried django-mptt, but I need product to belong to multiple subcategories. The django-polymorphic-mptt could have help. But I couldn't find proper documentation.
You can do something like the following:
class ProductCategorySerializer(serializers.ModelSerializer):
device_types = serializers.StringRelatedField(many=True)
device_brands = serializers.StringRelatedField(many=True)
part_types = serializers.StringRelatedField(many=True)
plural_name = serializers.SerializerMethodField()
def get_plural_name(self, obj):
return ProductCategory._meta.verbose_name_plural
class Meta:
model = ProductCategory
fields = ('name', 'device_types', 'device_brands', 'part_types', 'plural_name')
Related
The problem I'm having looks like:
TypeError: init() got an unexpected keyword argument 'name'
"GET /apartmentimages/ HTTP/1.1" 500 136691
I have such a model.py class:
class Apartment(models.Model):
apartment_title = models.CharField(max_length=200)
apartment_description = models.TextField()
apartment_location = models.CharField(max_length=200)
apartment_people_quantity = models.PositiveIntegerField()
apartment_price = models.CharField(max_length=200)
apartment_type = models.CharField(max_length=50, null=True)
def __str__(self):
return self.apartment_title
class ApartmentImage(models.Model):
apartment = models.ForeignKey(Apartment, on_delete=models.CASCADE)
image = models.ImageField(upload_to='images/', null=True, blank=True)
And serializers.py class:
class ApartmentSerializer(serializers.ModelSerializer):
class Meta:
model = Apartment
fields = (
'id',
'url',
'apartment_title',
'apartment_description',
'apartment_location',
'apartment_people_quantity',
'apartment_price',
'apartment_type',
)
class ApartmentImageSerializer(serializers.ModelSerializer):
class Meta:
model = ApartmentImage
fields = ('id', 'url', 'apartment', 'image',)
in views.py:
apartment_id = django_filters.CharFilter(name="apartment__id",
queryset=Apartment.objects.all())
class Meta:
model = ApartmentImage
fields = ('apartment_id',)
class ApartmentImageView(viewsets.ModelViewSet):
queryset = ApartmentImage.objects.all()
serializer_class = ApartmentImageSerializer
filter_backends = (DjangoFilterBackend,)
filter_class = ApartmentImageFilter
You have no name as an attribute in django-filters. Maybe what are you looking for is field_name and neither do you need queryset=Apartment.objects.all(). If you are looking for a field that is field_name then your CharFielter should look like this apartment_id = django_filters.CharFilter(field_name="apartment__id", lookup_expr='iexact') and maybe if you haven't overwritten the id generation it should probably be a NumberFilter() if I am not wrong.
I am learning Django so this is all very new to me. What I am trying to create is a bit of functionality in my admin panel that will allow me to create a layout like this.
Test
-Event1
--Property1
--Property2
--Property3
--Property4
-Event2
--Property1a
--Property2b
--Property3c
--Property4d
-Event3
--Property1aa
--Property2bb
--Property3cc
--Property4dd
-Event4
--Property1aaa
--Property2bbb
--Property3ccc
--Property4ddd
I want to have multiple tests. My current model setup looks like this:
from django.db import models
from django.forms import ModelForm
TYPE_CHOICES = (
("string", "string"),
("integer", "integer"),
("array", "array"),
("boolean", "boolean")
)
class Test(models.Model):
name = models.CharField(max_length=255)
description = models.CharField(max_length=255, blank=True)
class Meta:
verbose_name = 'Test'
verbose_name_plural = 'Tests'
def __str__(self):
return self.name
class Event(models.Model):
name = models.CharField(max_length=255)
test_id = models.IntegerField()
class Meta:
verbose_name = 'Event'
verbose_name_plural = 'Events'
def __str__(self):
return self.name
class Property(models.Model):
name = models.CharField(max_length=255)
property_type = models.CharField(max_length=20, choices=TYPE_CHOICES)
expected_value = models.CharField(max_length=255)
class Meta:
verbose_name = 'Property'
verbose_name_plural = 'Properties'
def __str__(self):
return self.name
class TestForm(ModelForm):
class Meta:
model = Test
fields = ['name', 'description']
I have my admin panel setup so that I can create multiple properties. But then when I go to the "Events" section in my admin panel I can only create events. I want to be able to pick the properties and add them to my event. Then I want to be able to go to the Test page and add the events to it.
A good example of what I am trying to create is a replica of this: http://jsonparser.tools/tests.php
you should define foreign keys for events and properties:
from django.db import models
from django.forms import ModelForm
TYPE_CHOICES = (
("string", "string"),
("integer", "integer"),
("array", "array"),
("boolean", "boolean")
)
class Test(models.Model):
name = models.CharField(max_length=255)
description = models.CharField(max_length=255, blank=True)
class Meta:
verbose_name = 'Test'
verbose_name_plural = 'Tests'
def __str__(self):
return self.name
class Event(models.Model):
name = models.CharField(max_length=255)
test = models.ForeignKey(Test,on_delete=models.CASCADE)
class Meta:
verbose_name = 'Event'
verbose_name_plural = 'Events'
def __str__(self):
return self.name
class Property(models.Model):
event = models.ForeignKey(Event,on_delete=models.CASCADE)
name = models.CharField(max_length=255)
property_type = models.CharField(max_length=20, choices=TYPE_CHOICES)
expected_value = models.CharField(max_length=255)
class Meta:
verbose_name = 'Property'
verbose_name_plural = 'Properties'
def __str__(self):
return self.name
class TestForm(ModelForm):
class Meta:
model = Test
fields = ['name', 'description']
this should solve your problem if not let me know happy to help.
I have 4 related models and I need to implement the functionality to consistently create instances of these models in a database in one post query. For this I use override of the APIView class post method.
models
class VendorContacts(models.Model):
contact_id = models.AutoField(primary_key=True)
vendor = models.OneToOneField('Vendors', on_delete=models.CASCADE)
contact_name = models.CharField(max_length=45, blank=True)
phone = models.CharField(max_length=45, blank=True)
email = models.CharField(max_length=80, blank=True, unique=True)
class Meta:
db_table = 'vendor_contacts'
class VendorModuleNames(models.Model):
vendor = models.OneToOneField('Vendors', on_delete=models.CASCADE, primary_key=True)
module = models.ForeignKey(Modules, models.DO_NOTHING)
timestamp = models.DateTimeField(auto_now=True)
class Meta:
db_table = 'vendor_module_names'
unique_together = (('vendor', 'module'),)
class Vendors(models.Model):
COUNTRY_CHOICES = tuple(COUNTRIES)
vendorid = models.AutoField(primary_key=True)
vendor_name = models.CharField(max_length=45, unique=True)
country = models.CharField(max_length=45, choices=COUNTRY_CHOICES)
nda = models.DateField(blank=True, null=True)
user_id = models.ForeignKey('c_users.CustomUser', on_delete=models.PROTECT)
timestamp = models.DateTimeField(auto_now_add=True)
class Meta:
db_table = 'vendors'
unique_together = (('vendorid', 'timestamp'),)
class Modules(models.Model):
MODULES_NAME =tuple(MODULES)
mid = models.AutoField(primary_key=True)
module_name = models.CharField(max_length=50, choices=MODULES_NAME)
active = models.BooleanField(default=True)
timestamp = models.DateTimeField(auto_now=True)
class Meta:
db_table = 'modules'
unique_together = (('mid', 'timestamp'),)
serializer.py
class VendorsSerializer(serializers.ModelSerializer):
class Meta:
model = Vendors
fields = ('vendor_name',
'country',
'nda',)
class VendorContactSerializer(serializers.ModelSerializer):
class Meta:
model = VendorContacts
fields = (
'contact_name',
'phone',
'email',)
class VendorModulSerializer(serializers.ModelSerializer):
class Meta:
model = VendorModuleNames
fields = ('module',)
class ModulesSerializer(serializers.ModelSerializer):
class Meta:
model = Modules
fields = ('module_name', )
views.py
class VendorsCreateView(APIView):
"""Create new vendor instances from form"""
def post(self, request, *args, **kwargs):
vendor_serializer = VendorsSerializer(data=request.data)
vendor_contact_serializer = VendorContactSerializer(data=request.data)
vendor_modules_serializer = VendorModulSerializer(data=request.data)
module_serializer = ModulesSerializer(data=request.data)
try:
vendor_serializer.is_valid(raise_exception=True) \
and vendor_contact_serializer.is_valid(raise_exception=True) \
and vendor_modules_serializer.is_valid(raise_exception=True) \
and module_serializer.is_valid(raise_exception=True)
vendor_serializer.save(user_id=request.user)
# ....
# Some new logic here ????
# ...
except ValidationError:
return Response({"errors": (vendor_serializer.errors,
vendor_contact_serializer.errors,
vendor_modules_serializer.errors
)},
status=status.HTTP_400_BAD_REQUEST)
else:
return Response(request.data, status=status.HTTP_200_OK)
There is no problem saving one Vendor model, but I can't imagine how to save cascading all related models in a single request.
save returns the newly saved object, which you can then pass into the subsequent save() methods:
vendor = vendor_serializer.save(user_id=request.user)
module = module_serializer.save()
vendor_module = vendor_modules_serializer.save(module=module, vendor=vendor)
vendor_contact = vendor_contact_serializer.save(vendor=vendor)
There are these models defined as base structures:
class Product(models.Model):
product_id = models.CharField(max_length=40, default=0, primary_key=True)
product_name = models.CharField(max_length=40, default='Generic Product')
def __str__(self):
return self.product_id
class ShoppingList(models.Model):
shop_list_id = models.CharField(max_length=20, default=0, primary_key=True)
shop_list_name = models.CharField(max_length=40, default=0)
product_id = models.ForeignKey(Product, on_delete=models.CASCADE, default=0)
session_id = models.CharField(max_length=40, default=0)
def __str__(self):
return self.shop_list_id
And there is another model that is used for checking if a Product and/or ShoppingList exist:
class ShopListCheck(models.Model):
product_id = models.ForeignKey(ShoppingList, on_delete=models.CASCADE, default=0)
shop_list_id = models.OneToOneField(ShoppingList, related_name='sid',
on_delete=models.CASCADE, default=0)
request_creation_date = models.DateTimeField(auto_now=True)
def session_id(self):
return self.product_id.session_id
def shop_list_id(self):
return self.product_id.shop_list_id
def __str__(self):
return self.product_id
Serializers are defined this way:
class ProductSerializer(serializers.ModelSerializer):
class Meta:
model = Product
fields = '__all__'
class ShoppingListSerializer(serializers.ModelSerializer):
class Meta:
model = ShoppingList
fields = '__all__'
class ShopListCheckSerializer(serializers.ModelSerializer):
session_id = serializers.SerializerMethodField()
link = serializers.SerializerMethodField()
class Meta:
model = ShopListCheck
fields = ('product_id', 'shop_list_id', 'session_id',
'request_creation_date', 'link')
def get_session_id(self, obj):
return obj.product_id.session_id
def get_link(self, obj):
return 'http://example.com/' + str(obj.product_id)
+ '/?session_id=' + str(obj.session_id())
Now I can send a POST request containing product_id to the ShopListCheck endpoint and I get all the product_id, shop_list_id, session_id, etc. (or error 400 if there's no given product_id in the dababase) in response.
What to do when I also want to check in the same request if given shop_list_id exists (or set "0" when I don't care about that)?
BTW, do you know any good resources I could practice this kind of relationships between models?
You can override is_valid method of drf serializers to do field-level validation on shop_list_id and also set that field afterwards. You can check the documentation from here.
In this project, I have two models Student and Parent related to each other through one to one field.
In Parent serializer, I want to add Students attributes like age. I am thinking of using SerializerMethodField for both cases is their any better way to do it?
I am not getting the queries on how to get the object attributes and little explanation would be great.
Here what I have done till now.
Models.py
class Student(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True, default=None)
batch = models.ForeignKey(Batch, on_delete=models.CASCADE, null=True, related_name='students')
email = models.EmailField(null=True)
phone_number = models.CharField(max_length=10, null=True)
dob = models.DateField(blank=True, null=True, help_text="Enter in the following format : YYYY-MM-DD")
address = models.TextField(max_length=150, null=True)
age = models.IntegerField(blank=True)
image = models.ImageField(upload_to='profile_pictures', default='student_image.png', blank=True)
#property
def remarks(self):
return self.remark_set.all()
#property
def marks(self):
return self.marks_set.all()
def __str__(self):
return self.user.firstName + ' ' + self.user.lastName
class Parent(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True, default=None)
child = models.ForeignKey(Student, on_delete=models.CASCADE)
email = models.EmailField(null=True)
phone_number = models.CharField(max_length=10, null=True)
address = models.TextField(max_length=150, null=True)
image = models.ImageField(upload_to='profile_pictures', default='student_image.png', blank=True)
def __str__(self):
return self.user.firstName + ' ' + self.user.lastName
Serilaizer.py
class ParentSerializer(serializers.HyperlinkedModelSerializer):
student_age = serializers.SerializerMethodField()
student_batch = serializers.SerializerMethodField()
parent_name = serializers.SerializerMethodField()
class Meta:
model = Parent
fields = "__all__"
def get_student_age(self, obj):
return Parent.objects.get(child__age = self.obj.user.child)
def get_student_batch(self, obj):
return Parent.objects.get(child__bacth = self.obj.user.child)
def get_parent_name(self, user):
return Parent.objects.get(user=self.request.user)
Views.py
class ParentView( mixins.ListModelMixin, mixins.RetrieveModelMixin,viewsets.GenericViewSet):
queryset = Parent.objects.all()
serializer_class = serializers.ParentSerializer
first way:
from apps.models import Student, parent
class BasicUserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = "__all__"
class BasicStudentSerializer(serializers.ModelSerializer):
class Meta:
model = Student
fields = "__all__"
class ParentSerializer(serializers.ModelSerializer):
user = BasicUserSerializer(read_only=True,many=False)
child = BasicStudentSerializer(read_only=True, many=True)
class Meta:
model = Parent
fields = '__all__'
you can do this way . its replace a serializer field that you want and if parent have several child then in child's field you have new all child's information as dictionary.
================================================================
second way is use HyperLinkModel .
class ParentSerializer(serializers.ModelSerializer):
user = serializers.HyperlinkedRelatedField(read_only=True,many=False)
child = serializers.HyperlinkedRelatedField(read_only=True, many=True)
class Meta:
model = Parent
fields = '__all__'
but notice that in first way you will have a independent serializer class that every time you need to serialize model class that related to User or Child you can use them simply.