How to specify fields to use of form in view? - django

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']

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__'

How do I access the value of the parent class in Django?

So I have two models here
class ProductType(models.Model):
product_type = models.CharField(max_length=50)
def __str__(self):
return self.product_type
class Product(models.Model):
product_name = models.CharField(max_length=50)
product_type = models.ForeignKey(ProductType, on_delete=models.CASCADE)
product_image = models.ImageField(blank=False, null=False, upload_to="products")
product_price = models.FloatField()
product_description = models.TextField(default="Product Description")
def __str__(self):
return self.product_name
And I have created an api using django-rest-framework to be consumed by the React frontend. However, when I try to get the product_type, it'd just give me a number instead of the name as shown below. So, how can I replace that when retrieving the data with Product.objects.all() in the view?
If you want to only show product_type instead of id you can use serializers.SerializerMethodField() in your ProductSerializer and with defining source in that method you can tell serializer to return your desired field.
Example:
class ProductSerializer(serializers.ModelSerializer):
product_type = serializers.SerializerMethodField(source='product_type__product_type')
class Meta:
model = Product
fields = ('id', 'product_name', 'product_image', 'product_price', 'product_description', 'product_type')
But if you want to serialize all the ProductType itself you can define a serializer for this model and then use this serializer in your ProductSerializer to serialize the whole object of ProductType.
Example:
class ProductTypeSerializer(serializers.ModelSerializer):
class Meta:
model = ProductType
fields = ('id', 'product_type',)
class ProductSerializer(serializers.ModelSerializer):
product_type = ProductTypeSerializer()
class Meta:
model = Product
fields = ('id', 'product_name', 'product_image', 'product_price', 'product_description', 'product_type')
The second solution is also known as nested serializers.

How to do custom validation in my Django Modelform?

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?

Django rest framework get all related foreign key

I have two models Organization and Departments. I would like to get all the department related particular organization id by using DRF, how can I do this
class Organization(models.Model):
name = models.CharField(max_length=30, unique=True)
description = models.CharField(max_length=100)
class Departments(models.Model):
name = models.CharField(max_length=30, unique=True)
description = models.CharField(max_length=100)
email= models.CharField(max_length=30, unique=True)
phone= models.CharField(max_length=30)
org_linked=models.ForeignKey(Organization)
user_linked=models.ForeignKey(User)
class OrganizationAndDepartmentSerializer(serializers.ModelSerializer):
org_department=facilitesntSerializer(many=True)
class Meta:
model = facilites
fields=('org_department',)
class OrganizationAndDepartmentViewSet(viewsets.ModelViewSet):
serializer_class =OrganizationAndDepartmentSerializer
If you want the full nested representation; declare a nested serializer as follows:
class DepartmentSerializer(serializers.ModelSerializer):
class Meta:
model = Departments
fields = ('__all__')
class OrganizationSerializer(serializers.ModelSerializer):
departments = DepartmentsSerializer(many=True, source='org_linked_set', read_only=True)
class Meta:
model = Organization
fields = (
'name',
'description',
'departments'
)

Django REST Framework join table results in attribute exception

I am building an API in Django using REST Framework but am running into an issue.
Serializers:
class SquadSerializer(serializers.Serializer):
class Meta:
model = Squad
fields = ('name')
id = serializers.IntegerField(read_only=True)
name = serializers.CharField(style={'base_template': 'textarea.html'})
class MembershipSerializer(serializers.Serializer):
class Meta:
model = Membership
fields = ('employee_id', 'squad_id')
squad = SquadSerializer()
employee = EmployeeSerializer()
class EmployeeSerializer(serializers.HyperlinkedModelSerializer):
habitat = HabitatSerializer()
class Meta:
model = Employee
fields = ('id', 'first_name', 'last_name', 'function',
'start_date', 'end_date', 'visible_site', 'habitat')
Models:
class Employee(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=40)
function = models.CharField(max_length=50)
start_date = models.DateField()
end_date = models.DateField(null=True, blank=True)
visible_site = models.BooleanField()
habitat = models.ForeignKey(Habitat, on_delete=models.SET_NULL, null=True, blank=True)
class Squad(models.Model):
name = models.TextField(max_length=40)
class Membership(models.Model):
class Meta:
unique_together = (('employee', 'squad'))
employee = models.ForeignKey(Employee, on_delete=models.CASCADE, null=False, blank=True, default=1)
squad = models.ForeignKey(Squad, on_delete=models.CASCADE, null=False, blank=True, default=1)
The problem is that I keep running into this error:
AttributeError: Got AttributeError when attempting to get a value for field `name` on serializer `SquadSerializer`.
The serializer field might be named incorrectly and not match any attribute or key on the `Membership` instance.
Original exception text was: 'Membership' object has no attribute 'name'.
When executing this test (and a couple others)
def test_membership_serializer_id_name_field_content(self):
"""
The name field of a squad should contain an id
"""
serializer = create_membership_serializer(self.membership, '')
self.assertEqual(serializer.data['id'], self.membership.id)
I've seen multipe people with the same issues here on Stack Overflow but the often suggest solution (to add many=True to SquadSerializer() and EmployeeSerializer()) doesn't work. I hope anyone here has any knowledge on why this happens.
If you want to map your seriailizer to your model, you should use ModelSerializer. In tupple, if it has only one value, you should write it as (1,) not (1). Your SquadSerializer should be like
class SquadSerializer(serializers.ModelSerializer):
class Meta:
model = Squad
fields = ('name',) # or ('id', 'name')
id = serializers.IntegerField(read_only=True)
name = serializers.CharField(style={'base_template': 'textarea.html'})
Your MembershipSerializer should be like
class MembershipSerializer(serializers.ModelSerializer):
class Meta:
model = Membership
fields = ('employee', 'squad')
squad = SquadSerializer()
employee = EmployeeSerializer()