I have two models, which look like this:
class Item(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=60)
sku = models.CharField(max_length=60)
description = models.TextField()
price = models.DecimalField(max_digits=6, decimal_places=2)
location = models.CharField(max_length=60)
serial_number = models.CharField(max_length=60)
def __str__(self):
return self.name
class Warehouse(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=60)
def __str__(self):
return self.name
and they have two serializers which look like this:
class ItemSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Item
fields = ('id', 'name', 'sku', 'description', 'price', 'location', 'serial_number')
#we need a validator that checks if location is in the list of warehouses
#we need a validator that checks if sku is in the list of products
class WarehouseSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Warehouse
fields = ('id', 'name')
I need a way to ensure that the location field for newly created items matches an existing name field from a warehouse. I also need the deletion of a warehouse to trigger the deletion of all items in that warehouse, or, failing that; if the warehouse has items, it cannot be deleted.
I'm brand new to python and django, so any help would be massively appreciated!
for reference, my views class looks like
class ItemViewSet(viewsets.ModelViewSet):
queryset = Item.objects.all().order_by('name')
serializer_class = ItemSerializer
class WarehouseViewSet(viewsets.ModelViewSet):
queryset = Warehouse.objects.all().order_by('name')
serializer_class = WarehouseSerializer
if that helps, but from what I can see I don't expect it to.
Thanks in advance!
I think the problem here is your data models. It's clear that a warehouse and an item have a one to many relationship. With that, you would have something like this in your models.
from django.db import models
class Warehouse(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=60)
def __str__(self):
return self.name
class Item(models.Model):
id = models.AutoField(primary_key=True)
warehouse = models.ForeignKey(Warehouse, related_name="items", on_delete=models.CASCADE)
name = models.CharField(max_length=60)
sku = models.CharField(max_length=60)
description = models.TextField()
price = models.DecimalField(max_digits=6, decimal_places=2)
location = models.CharField(max_length=60)
serial_number = models.CharField(max_length=60)
def __str__(self):
return self.name
The on_delete=models.CASCADE will ensure that all items related to a warehouse are deleted when a warehouse is deleted. The foreign key relationship will ensure that warehouse id you provide when creating the item, exists before the item is created.
The other files will look as follows.
serializers.py
from rest_framework import serializers
from .models import Warehouse, Item
class ItemSerializer(serializers.ModelSerializer):
class Meta:
model = Item
fields = ('id', 'name', 'sku', 'description', 'price', 'location', 'serial_number', "warehouse")
class WarehouseSerializer(serializers.HyperlinkedModelSerializer):
items = serializers.StringRelatedField(many=True, required=False)
class Meta:
model = Warehouse
fields = ('id', 'name', 'items')
views.py
from .models import Item, Warehouse
from .serializers import ItemSerializer, WarehouseSerializer
from rest_framework import viewsets
class ItemViewSet(viewsets.ModelViewSet):
queryset = Item.objects.all().order_by('name')
serializer_class = ItemSerializer
class WarehouseViewSet(viewsets.ModelViewSet):
queryset = Warehouse.objects.all().order_by('name')
serializer_class = WarehouseSerializer
Related
I am trying to create nested relationship from more than two models in Django Rest Framework.
Thank you in advance for helping me.
I succeed with two models but when I'm trying with three models unable to create nested serialization.
from django.db import models
class Project(models.Model):
project_id = models.AutoField(primary_key=True)
project_name = models.CharField(max_length=255)
def __str__(self):
return self.name
class Site(models.Model):
site_id = models.AutoField(primary_key=True)
site_name = models.CharField(max_length=255)
project_id= models.ForeignKey(Project, related_name="projectid", on_delete=models.CASCADE)
def __str__(self):
return self.site_name
class Aggin(models.Model):
assign_id = models.AutoField(primary_key=True)
site_id = Models.ForeginKey(Site, relate_name="siteid", on_delete=models.CASCADE)
from rest_framework import serializers
from .models import Song, Artist
class ProjectSerializer(serializers.ModelSerializer):
class Meta:
model = Project
fields = ('__all__')
class SiteSerializer(serializers.ModelSerializer):
class Meta:
model = Site
fields = ('__all__')
class AggignSerializer(serializers.ModelSerializer)
class Meta:
model = Aggin
fields = ('__all__')
I think you don't need to primary id field if you wanna use the Django's default foreign key setting. And related_name should be defined from the view of the counterpart model.
from django.db import models
class Project(models.Model):
project_name = models.CharField(max_length=255)
def __str__(self):
return self.name
class Site(models.Model):
site_name = models.CharField(max_length=255)
project = models.ForeignKey(Project, related_name="sites", on_delete=models.CASCADE)
def __str__(self):
return self.site_name
class Aggin(models.Model):
site = Models.ForeginKey(Site, relate_name="assigns", on_delete=models.CASCADE)
And then, in serializer, you can set like the following.
from rest_framework import serializers
from .models import Song, Artist
class ProjectSerializer(serializers.ModelSerializer):
sites = SiteSerializer(read_only = True, many = True)
class Meta:
model = Project
fields = ('id', 'project_name', 'sites')
class SiteSerializer(serializers.ModelSerializer):
assigns = AggignSerializer(read_only = True, many = True)
class Meta:
model = Site
fields = ('id', 'site_name', 'assigns')
class AggignSerializer(serializers.ModelSerializer):
class Meta:
model = Aggin
fields = ('id')
models.py:
class Book(models.Model):
name = models.CharField(max_length=100)
description = models.TextField(max_length=500)
image = models.ImageField(height_field="height_field", width_field="width_field")
height_field = models.IntegerField(default=255)
width_field = models.IntegerField(default=255)
price = models.FloatField()
edition = models.CharField(max_length=100)
no_of_page = models.IntegerField()
country = models.CharField(max_length=50)
publication = models.ForeignKey(Publication, on_delete=models.CASCADE)
authors = models.ManyToManyField(Author, through='AuthorBook')
ratings = GenericRelation(Rating, related_query_name='books')
class AuthorBook(models.Model):
author = models.ForeignKey(Author, on_delete=models.CASCADE)
book = models.ForeignKey(Book, on_delete=models.CASCADE)
class Author(models.Model):
name = models.CharField(max_length=100)
biography = models.TextField(max_length=500)
image = models.ImageField(height_field="height_field", width_field="width_field")
height_field = models.IntegerField(default=255)
width_field = models.IntegerField(default=255)
serializers.py
class AuthorListSerializer(ModelSerializer):
url = author_detail_url
class Meta:
model = Author
fields = [
'url',
'id',
'name',
]
class BookCreateUpdateSerializer(ModelSerializer):
authors = AuthorListSerializer(many=True, read_only=True)
def create(self, validated_data):
#code
def update(self, instance, validated_data):
#code
class Meta:
model = Book
fields = [
'name',
'description',
'price',
'edition',
'no_of_page',
'country',
'publication',
'authors',
]
views.py
class BookCreateAPIView(CreateAPIView):
queryset = Book.objects.all()
serializer_class = BookCreateUpdateSerializer
I am working for implementing Django REST Framework. I have two models Book and Author. But django create api view don't show authors field drop down. I checked many solution DRF for many to many field. Please help me to show authors field and write create() and update function. If you see DRF api page, it will be clear.
This is because of read_only=True. Try to remove this argument for bookserializer's authors field:
class BookCreateUpdateSerializer(ModelSerializer):
authors = AuthorListSerializer(many=True)
serializers.py
After adding this two variables (category,type_units) for dropdown post method not working. it through 500 server error And also added my view.py models.py
class ProductSerializer(serializers.HyperlinkedModelSerializer):
category = serializers.CharField(source='category.category', read_only=True)
type_units = serializers.CharField(source='type_units.type', read_only=True)
class Meta:
model = Product
fields = ('id','image','pro_name','description','category','sales','cost','taxable','type_units','hsn')
Models.py
class Units(models.Model):
type = models.CharField(max_length=10)
class Category(models.Model):
category = models.CharField(max_length=10)
class Product(models.Model):
image = models.ImageField(upload_to = "images/",blank=True,null=True)
pro_name = models.CharField(max_length=25)
description = models.CharField(max_length=150)
category = models.ForeignKey(Category,on_delete=models.CASCADE)
sales = models.CharField(max_length=25)
cost = models.CharField(max_length=25)
taxable = models.BooleanField(default=False, blank=True)
type_units = models.ForeignKey(Units, on_delete=models.CASCADE)
hsn = models.CharField(max_length=10)
views.py
class ProductViewSet(viewsets.ModelViewSet):
"""
API endpoint that allows groups to be viewed or edited.
"""
queryset = Product.objects.all()
serializer_class = ProductSerializer
class UnitsViewSet(viewsets.ModelViewSet):
"""
API endpoint that allows groups to be viewed or edited.
"""
queryset = Units.objects.all()
serializer_class = UnitsSerializer
class CategoryViewSet(viewsets.ModelViewSet):
"""
API endpoint that allows groups to be viewed or edited.
"""
queryset = Category.objects.all()
serializer_class = CategorySerializer
I have just started learning Django Rest Framework and trying to make a simple API using Django rest Framework.
This is my models.py
from __future__ import unicode_literals
from django.db import models
class Student(models.Model):
created = models.DateTimeField(auto_now_add=True)
name = models.CharField(max_length=150, blank=False)
student_id = models.CharField(max_length=20, primary_key=True)
father_name = models.CharField(max_length=150)
mother_name = models.CharField(max_length=150)
class Meta:
ordering = ('student_id',)
class Subject(models.Model):
created = models.DateTimeField(auto_now_add=True)
subject_id = models.CharField(max_length=20, primary_key=True)
name = models.CharField(max_length=150)
class Meta:
ordering = ('subject_id',)
class Result(models.Model):
created = models.DateTimeField(auto_now_add=True)
grade = models.DecimalField(max_digits=5, decimal_places=3, blank=False)
student_id = models.ForeignKey(Student, on_delete=models.CASCADE)
subject_id = models.ForeignKey(Subject, on_delete=models.CASCADE)
class Meta:
ordering = ('created',)
And this is my serializers.py
from rest_framework import serializers
from models import *
class StudentSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Student
fields = ('student_id', 'name', 'father_name', 'mother_name')
class SubjectSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Subject
fields = ('subject_id', 'name')
class ResultSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Result
fields = ('grade', 'student_id', 'subject_id')
In my "Result" model, I have two foreign keys; student_id and subject_id. This is how it looks like:
My questions is, how can I show the "name" field in the drop down menu in stead of showing "Student Object" and "Subject Object"?
I have tried with
STUDENT_CHOICES = [(each.student_id, each.name) for each in Student.objects.all()]
SUBJECT_CHOICES = [(each.subject_id, each.name) for each in Subject.objects.all()]
in the model's "choices=" field but it didn't work out.
Thanks in advance.
I think you're looking for this part of the DRF documentation.
Basically, your Django model's own representation is used. So for example, in your Student model you can add __str__ method:
# this is for Python 3, use __unicode__ on Python 2
def __str__(self):
return self.name
Meta options documentation for Django is here, look for model methods.
from django.db import models
class Customer(models.Model):
cust_firstname=models.TextField(max_length=50)
cust_lastname=models.TextField(max_length=50)
cust_company=models.TextField(max_length=100)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
cust_contact_number = models.IntegerField()
cust_email = models.TextField(max_length=100)
cust_address=models.TextField(max_length=200,default=None)
class Employee(models.Model):
employee_firstname = models.TextField(max_length=50)
employee_lastname = models.TextField(max_length=50)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
employee_contact_number = models.IntegerField()
employee_email = models.TextField(max_length=100)
employee_designation = models.TextField(max_length=50)
employee_address=models.TextField(max_length=200, default=None)
class ProjectDetails(models.Model):
customer = models.ForeignKey(Customer)
employee=models.ForeignKey(Employee)
project_name = models.TextField(max_length=50)
project_startdate = models.DateTimeField(auto_now=False, default=None)
project_status = models.TextField(default="Initial")
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
The above code is my model declaration
and my Serializer class is
from ProjectTemplate.models import Customer, Employee, ProjectDetails
from rest_framework import serializers
class CustomerSerializers(serializers.ModelSerializer):
class Meta:
model=Customer
fields = ('id','cust_firstname','cust_lastname','cust_company','created_at','updated_at','cust_contact','cust_email','cust_address')
read_only_fields = ('created_at', 'updated_at')
class EmployeeSerializer(serializers.ModelSerializer):
class Meta:
model=Employee
fields = ('id','employee_firstname','employee_lastname','created_at','updated_at','employee_contact','employee_email','employee_designation','employee_address')
read_only_fields = ('created_at', 'updated_at')
class ProjectDetailsSerializer(serializers.ModelSerializer):
customer = CustomerSerializers(many=True, read_only=True)
employee = EmployeeSerializer(many=True, read_only=True)
class Meta:
model = ProjectDetails
fields = ('id','project_name','project_startdate','created_at','updated_at','project_status','customer','employee')
read_only_fields = ('created_at', 'updated_at')
In my view i have the below code
def get(self, request, format=None):
queryset = ProjectDetails.objects.all()
projectid = self.request.query_params.get('pk', None)
if projectid is not None:
queryset = queryset.get(id=projectid)
serializer = ProjectDetailsSerializer(queryset, many=False)
return Response(serializer.data)
else:
serializer = ProjectDetailsSerializer(queryset, many=True)
return Response(serializer.data)
And my URL for the above view is
url(r'^api/v1/projects/$', ProjectListView.as_view()),
And when i try to access the URL on my Browser i get TypeError. Im trying to get all the Customers and Employees who belong to a project. But it fails can any one help me to fix this.
I'm trying to get all the Customers and Employees who belong to a project.
I am not sure what do you want to achieve here because looking at your model, an instance of ProjectDetail will only have one customer and one employee:
class ProjectDetails(models.Model):
customer = models.ForeignKey(Customer)
employee=models.ForeignKey(Employee)
Considering this, using many=True doesn't make any sense in the serializer. So this is what causing the error:
class ProjectDetailsSerializer(serializers.ModelSerializer):
customer = CustomerSerializers(many=True, read_only=True)
employee = EmployeeSerializer(many=True, read_only=True)
UPDATE: To show a specific field from the related object:
Based on the comments in the answer the OP want to show the name of customer or employee instead of id.
It can be achieved using a SlugRelatedField:
class ProjectDetailsSerializer(serializers.ModelSerializer):
customer = serializers.SlugRelatedField(slug_field='cust_firstname', read_only=True)
employee = serializers.SlugRelatedField(slug_field='employee_firstname ', read_only=True)
# other fields
Do note that using SlugRelatedField you can get only one field as in the example above you would get firstname for both.