How to do custom validation in my Django Modelform? - django

I have a ModelForm for this model, with this unique_together:
class Registration(models.Model):
student_name = models.CharField(max_length=50)
selected_season = models.CharField(max_length=2)
selected_subject = models.ForeignKey(Subject, on_delete=models.CASCADE)
student_address = models.TextField()
student_phone = models.CharField(max_length=11)
class Meta:
unique_together = (('student_name', 'selected_season', 'selected_subject'),)
The modelform is like this:
class RegistrationForm(forms.ModelForm):
student_address = forms.CharField(label='', widget=forms.Textarea(attrs={'class':'materialize-textarea'}))
class Meta:
model = Registration
fields = '__all__'
How do I raise a validation error if the unique_together requirement is not met?

Related

How do I pull in data from multiple models into a specific model serializer?

I have this model that represents a bookmark or favorite. It has multiple foreign keys to other models. In the api I would like to pull in the data from each of the models that is referenced in the particular bookmark.
The model:
class Bookmark(models.Model):
marktype = models.CharField(max_length=10)
post = models.OneToOneField(Post, on_delete=models.CASCADE, null=True, blank=True)
question = models.OneToOneField(Question, on_delete=models.CASCADE, null=True, blank=True)
owner = models.ForeignKey(User, on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add=True, verbose_name="created at")
updated_at = models.DateTimeField(auto_now=True, verbose_name="updated at")
class Meta:
verbose_name = "bookmark"
verbose_name_plural = "bookmarks"
ordering = ["created_at"]
db_table = "bookmarks"
def __str__(self):
return "{}'s bookmark".format(self.owner.username)
I tried to use a SerializerMethodField but I get an error: 'NoneType' object has no attribute 'id'
Here is the serializer
class BookmarkSerializer(serializers.ModelSerializer):
post = serializers.SerializerMethodField()
question = serializers.SerializerMethodField()
class Meta:
model = Bookmark
fields = '__all__'
def get_post(self, obj):
obj = Post.objects.get(id=obj.post.id)
post = ShortPostSerializer(obj)
return post.data
def get_question(self, obj):
obj = Question.objects.get(id=obj.question.id)
question = ShortQuestionSerializer(obj)
return question.data
what am I doing wrong please?
You can update your serializer like the following (You can short it as you want or use your ShortQuestionSerializer as well instead of QuestionSerializer),
class QuestionSerializer(serializers.ModelSerializer):
class Meta:
model = Question
fields = '__all__'
class PostSerializer(serializers.ModelSerializer):
class Meta:
model = Post
fields = '__all__'
class BookmarkSerializer(serializers.ModelSerializer):
post = PostSerializer()
question = QuestionSerializer()
class Meta:
model = Bookmark
fields = '__all__'

Create objects in multiple nested serializer in django

I have 3 models which are related to each other via ManytoMany relation like this:
class DemandEvents(models.Model):
date = models.DateTimeField(blank=True, null=True)
quantity = models.IntegerField(default=0)
class DemandFlows(models.Model):
events = models.ManyToManyField(DemandEvents)
flow = models.ForeignKey(Flow, on_delete=models.CASCADE)
kit = models.ForeignKey(Kit, on_delete=models.CASCADE)
monthly_quantity = models.IntegerField(default=0)
class Demand(models.Model):
demand_flows = models.ManyToManyField(DemandFlows)
delivery_month = models.DateTimeField(blank=True, null=True)
owner = models.ForeignKey(User, on_delete=models.CASCADE)
I am trying to create the serializers for this but keep getting confused how to handle the multi-level nesting
Serializer.py
class DemandEventsSerializer(serializers.ModelSerializer):
class Meta:
model = DemandEvents
fields = "__all__"
class DemandFlowsSerializer(serializers.ModelSerializer):
class Meta:
model = DemandFlows
fields = "__all__"
class DemandSerializer(serializers.ModelSerializer):
demand_flows = DemandFlowsSerializer(many=True)
class Meta:
model = Demand
fields = "__all__"
def create(self, validated_data):
items_objects = validated_data.pop('form_list', None)
prdcts = []
for item in items_objects:
i = DemandFlows.objects.create(**item)
prdcts.append(i)
instance = Demand.objects.create(**validated_data)
instance.demand_flows.set(prdcts)
return instance
How do I add events data to this DemandFlows?

Nested Serializer (depth/level 3)

Trying to add 3rd nested serializer using django rest framework
how to add 3rd nested realation in given code -
models.py
class Category(models.Model):
cate_id = models.AutoField(primary_key=True)
cate_name = models.CharField(max_length=45)
class Meta:
managed = False
db_table = 'category'
class SubCategory(models.Model):
sub_cate_id = models.AutoField(primary_key=True)
sub_cate_name = models.CharField(max_length=45)
sub_fk = models.ForeignKey('Category', models.CASCADE, db_column='sub_fk')
class Meta:
managed = False
db_table = 'sub_category'
class Products(models.Model):
pro_id = models.AutoField(primary_key=True)
pro_name = models.CharField(max_length=45)
description = models.CharField(max_length=45, blank=True, null=True)
price = models.IntegerField()
quantity = models.IntegerField()
pro_cate_fk = models.ForeignKey('Category', models.CASCADE, db_column='pro_cate_fk')
pro_sub_fk = models.ForeignKey('SubCategory', models.CASCADE, db_column='pro_sub_fk')
image = models.CharField(max_length=205)
class Meta:
managed = False
db_table = 'products'
from rest_framework import serializers
from .models import Category,SubCategory,Products
class ProductsSerializer(serializers.ModelSerializer):
# x= ChildTable.objects.all().values
class Meta:
model = Products
fields = ('pro_id','pro_name','description','price','quantity','image')
class SubCategorySerializer(ProductsSerializer):
products_set = ProductsSerializer(many=True, read_only=True)
class Meta:
model = SubCategory
fields = ('sub_cate_name','sub_cate_id','products_set')
class CategorySerializer(SubCategorySerializer):
subcategory_set = ProductsSerializer(many=True, read_only=True,)
# pro_subcate_set = SubCategorySerializer(many=True, read_only=True)
class Meta:
model = Category
fields = ('cate_name','cate_id','subcategory_set')
Got this error while attempting -
Got AttributeError when attempting to get a value for field `pro_name` on serializer `ProductsSerializer`. The serializer field might be named incorrectly and not match any attribute or key on the `SubCategory` instance. Original exception text was: 'SubCategory' object has no attribute 'pro_name'.
Is it possible to connect 2 already connected serializer to another serializer?
Make a test and see if it works.
class CategorySerializer(serializers.ModelSerializer):
class Meta:
model = Category
fields = ('cate_id', 'cate_name')
class SubCategorySerializer(serializers.ModelSerializer):
class Meta:
model = SubCategory
fields = ('sub_cate_id', 'sub_cate_name', 'sub_fk')
def to_representation(self, instance):
response = super().to_represntation(instance)
response['sub_fk'] = CategorySerializer(instance.sub_fk).data
return response
class ProductSerializer(serializers.ModelSerializer):
class Meta:
model = Products
fields = ('pro_id', 'pro_name', 'description', 'price', 'quantity', 'pro_cate_fk', 'pro_sub_fk', 'image')
def to_representation(self, instance):
response = super().to_representation(instance)
response['pro_cate_fk'] = CategorySerializer(instance.pro_cate_fk).data
response['pro_sub_fk'] = ProductSerializer(instance.pro_sub_fk).data
return response

DetailSerializer to have listserializer property

I want to add json data from the listserializer to the DetailSerializer class. The serializer looks something like this:
serializer.py
class ListSerializer(serializers.ModelSerializer):
class Meta:
model = Fastest_laps
fields = '__all__'
class DetailSerializer(serializers.ModelSerializer):
listserializer = ListSerializer( read_only=True, many=True)
class Meta:
model = Driver
fields =
('place_of_birth','driver','listserializer','picture')
But i dont really see the data once i view it, i only see the detailserializer data( Driver model)
class Fastest_laps(models.Model):
driver_name = models.CharField(max_length=25, null=True)
grand_prix = models.CharField(max_length=15, blank=True)
car_model = models.CharField(max_length=50)
time_taken = models.CharField(blank=True, max_length=8)
def __str__(self):
return self.driver_name
class Driver(models.Model):
place_of_birth = models.CharField(max_length=25)
driver = models.ForeignKey(Fastest_laps,
db_column='driver_name')
picture = models.ImageField(blank=True, null=True)
def __str__(self):
return str(self.driver)
api.py
class FastLapsSet(ModelViewSet):
queryset = Fastest_laps.objects.all()
serializer_class = ListSerializer
class DriverSet(ModelViewSet):
queryset = Driver.objects.all()
serializer_class = DetailSerializer
you should rename your property as model name field:
class DetailSerializer(serializers.ModelSerializer):
driver = ListSerializer(read_only=True)
# ^^^
class Meta:
model = Driver
fields =
('place_of_birth','driver','driver','picture')
or add the source attribute:
class DetailSerializer(serializers.ModelSerializer):
listserializer = ListSerializer(source='driver', read_only=True)
#^^^^
class Meta:
model = Driver
fields =
('place_of_birth','driver','listserializer','picture')

How to specify fields to use of form in view?

I have model:
class ModelA(models.Model):
field_1 = models.CharField(blank=True, null=True)
field_2 = models.CharField(blank=True, null=True)
field_3 = models.CharField(blank=True, null=True)
field_4 = models.CharField(blank=True, null=True)
field_5 = models.CharField(blank=True, null=True)
and I must generate three forms:
class Form1(forms.ModelForm):
class Meta:
model = ModelA
fields = ['field_1', 'field_2', 'field_3']
class Form2(forms.ModelForm):
class Meta:
model = ModelA
fields = ['field_1', 'field_2', 'field_4']
class Form3(forms.ModelForm):
class Meta:
model = ModelA
fields = ['field_1', 'field_2', 'field_5']
How convert it into one form and influence the "fields" in view? I show all this forms in one template.
Are you using class based views? I would suggest using CreateView/UpdateView to do this. You won't need to create a form at all since the class handles that, and you can just specify the fields attribute on the view for whichever fields you want for that particular view. The django doc has a really good example of this: https://docs.djangoproject.com/en/1.6/topics/class-based-views/generic-editing/#model-forms
class AuthorUpdate(UpdateView):
model = Author
fields = ['name']
So for your example it could be:
class View1(CreateView):
model= ModelA
fields = ['field_1', 'field_2', 'field_3']
class View2(CreateView):
model= ModelA
fields = ['field_1', 'field_2', 'field_4']
class View3(CreateView):
model= ModelA
fields = ['field_1', 'field_2', 'field_5']