I am using Django rest framework for a project. In the project, there is a Student model, which has a foreign key referring to a user object.
class Student(models.Model):
user = models.OneToOneField(
User,
on_delete=models.CASCADE
)
When I read from Student, I would also like to get all the fields of the nested user. I can do that with nested serializers:
class StudentSerializer(serializers.ModelSerializer):
user = UserSerializer(read_only=True)
class Meta:
model = Student
fields = '__all__'
However, if I want to create a new user I cannot use the same serializer, because there is no way to pass a foreign key to the user field, and Django does no support nested create.
I am currently using an additional field user_id = serializers.IntegerField(write_only=True) to get the foreign key for write, and customized the create method to handle the logic. I also tried using two different serializers for creating and fetching data. Both way worked, but I am just wondering if there is a more intuitive way to implement this? A more convenient or standard way perhaps? Is there some syntax that works like: if read: user = UserSerializer() that avoids creating two different things for the same serializer field under different conditions?
i think u should follow docs
https://www.django-rest-framework.org/api-guide/relations/#writable-nested-serializers
class StudentSerializer(serializers.ModelSerializer):
user = UserSerializer()
class Meta:
model = Student
fields = '__all__'
def create(self, validated_data):
user_data = validated_data.pop('user')
validated_data["user"] = User.objects.create(user_data)
student = Student.objects.create(**validated_data)
return student
You can also think about doing it in one transaction.
https://docs.djangoproject.com/en/4.0/topics/db/transactions/
Related
This is just my curiosity but I will be very happy if anyone answers my question.
I am using Django Rest Framework but I'm a beginner. In serializers.py, I use ModelSerializer and "all" to fields attribute.
This is an example.
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = "__all__"
And then, I just thought
when don't we use "__all__" in serializers.py??
As long as we create models.py in advance, I think we usually use all fields in each Model.
I would like you to teach me when we omit specific fields that come from each Model.
Thank you.
So the second question is a bit harder to explain in a comment:
If we use some fields of all fields in Model, how do we store information of the rest of fields?
Various cases:
Fields with defaults:
class Log(models.Model):
message = models.TextField()
created_at = models.DateTimeField(auto_now_add=True)
class LogSerializer(serializers.ModelSerializer):
class Meta:
model = Log
fields = ('message',)
For autogenerated, think user profile models via the post_save signal or calculated fields:
class OrderLine(models.Model):
order = models.ForeignKey(Order)
name = models.CharField(max_length=200)
quantity = models.IntegerField()
price = models.DecimalField()
class OrderLineSerializer(serializers.ModelSerializer):
order = serializers.PrimaryKeyRelatedField()
product = serializers.IntegerField()
class Meta:
model = OrderLine
fields = ('quantity', 'product', 'order')
In this case, the product is a primary key for a product. The serializer will have a save method that looks up the product and put it's name and price on the OrderLine. This is standard practice as you cannot reference a product in your orders, else your orders would change if you change (the price of) your product.
And derived from request:
class BlogPost(models.Model):
author = models.ForeignKey(User)
post = models.TextField()
class BlogPostSerializer(serializers.ModelSerializer):
class Meta:
model = BlogPost
fields = ('post',)
def create(self, validated_data):
instance = BlogPost(**validated_data)
instance.author = self.context['request'].user
instance.save()
return instance
This is pretty much the common cases.
There are many cases, but I think the two main ones are:
When you don't want all fields to be returned by the serializer.
When you need some method of the serializer to know its fields. In such case, you should traverse fields array, but it doesn't work if you use __all__, only if you have an actual list of fields.
Assume i have two models. ModelA & ModelB.ModelB will have Foregin key to ModelA. i want to create each record in both tables one haveing foregin key.
models.py
Class ModalA(models.Model):
name = models.CharField(max_length=200)
location = models.CharField(max_length=200)
Class ModelB(models.Model):
modela = models.ForeignKey(ModalA,on_delete=models.CASCADE)
state = models.CharField(max_length=200)
country = models.CharField(max_length=200)
serializer,py
class ModelBSerializers(serializers.ModelSerializer):
class Meta:
model = ModelB
fields = "__all__"
class ModalASerializers(serializers.ModelSerializer):
class Meta:
model = ModalA
fields = "__all__"
def create(self, validated_data):
return ModalA(**validated_data)
I would like to know how to create bot records in tables.
There are couple of way possible to ensure how we can populate two different model with some dependency requirement. Like after insert in model A there must be an entry of model B or vice-versa. One of well recommended way is to use django-signallink (post/pre what is more suitable for scenario). I would like to add additional link if you haven't work with django-signal you can follow this post.
I feel like this is a super basic question but am having trouble finding the answer in the DRF docs.
Let's say I have a models.py set up like so:
#models.py
class Person(models.Model):
name = models.CharField(max_length=20)
address = models.CharField(max_length=20)
class House(models.Model):
name = models.CharField(max_length=20)
owner = models.ForeignKey(Person)
And I have a ModelSerializer set up like so:
#serializers.py
class House(serializers.ModelSerializer):
class Meta:
model = House
fields = '__all__'
What I want to do is to be able to POST new House objects but instead of having to supply the pk of the Person object, I want to be able to supply the name of the Person object.
E.g.
post = {'name': 'Blue House', 'owner': 'Timothy'}
The actual models I'm using have several ForeignKey fields so I want to know the most canonical way of doing this.
One solution may be to use a SlugRelatedField
#serializers.py
class House(serializers.ModelSerializer):
owner = serializers.SlugRelatedField(
slug_field="name", queryset=Person.objects.all(),
)
class Meta:
model = House
fields = '__all__'
This will also change the representation of your serializer though, so it will display the Person's name when you render it. If you need to render the Person's primary key then you could either override the House serializers to_representation() method, or you could implement a small custom serializer field by inheriting SlugRelatedField and overriding to_representation() on that instead.
Change your serializer as below by overriding the create() method
class House(serializers.ModelSerializer):
owner = serializers.CharField()
class Meta:
model = House
fields = '__all__'
def create(self, validated_data):
owner = validated_data['owner']
person_instance = Person.objects.get(owner=owner)
return House.objects.create(owner=person_instance, **validated_data)
I am trying to use DRF Django Rest Framework to create a post API to create entry for 2 models and associate foreign key relationship. How do I accomplish that ?
I have 2 models
- Employee model that OneToOne association with User, and has a ForeignKey Company
- Company model
I want to have a post to create employee model entry and also company model entry and associate the employee to the company. The employee also I want to enter in the User data (username, first_name, last_name, etc).
The following are the code excerpts:
https://gitlab.com/firdausmah/railercom/blob/master/railercomapp/models.py
class Employee(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='employee')
company = models.ForeignKey(Company)
class Company(models.Model):
name = models.CharField(max_length=50)
tel = models.CharField(max_length=15, blank=True)
https://gitlab.com/firdausmah/railercom/blob/master/railercomapp/views.py
class EmployeeWithCompanyCreateView(generics.ListCreateAPIView):
"""This class defines the create behavior of our rest api."""
queryset = Employee.objects.all()
serializer_class = EmployeeWithCompanyCreateSerializer
def perform_create(self, serializer):
"""Save the post data when creating a new bucketlist."""
serializer.save()
https://gitlab.com/firdausmah/railercom/blob/master/railercom/urls.py
urlpatterns = [
url(r'^employee/$', EmployeeWithCompanyCreateView.as_view(), name="create"),
https://gitlab.com/firdausmah/railercom/blob/master/railercomapp/serializers.py
class EmployeeWithCompanyCreateSerializer(serializers.ModelSerializer):
class Meta:
model = Employee
fields = ("id","identity_number", "tel")
Your current solution has some thing wrong: the fields list of EmployeeWithCompanyCreateSerializer class is mismatch the fields of Employee class.
In your question context ,I suggest you write the complicated view by hand.
I'm trying to create a custom class Employee that uses the default authentication. I am able to successfully register but the fields associated with Django's User class are stored in User while my custom fields are stored in Employee. How can I get everything stored in Employee?
This is my forms.py:
class UserForm(forms.ModelForm):
password = forms.CharField(widget=forms.PasswordInput())
class Meta:
model = User
fields = ('username', 'first_name', 'last_name', 'email', 'password')
class EmployeeForm(forms.ModelForm):
class Meta:
model = Employee
fields = ('sales', 'hours')
And my models.py:
class Patient(models.Model):
user = models.OneToOneField(User)
sales = models.CharField(max_length=30)
hours = models.CharField(max_length=30)
Like I said, I would prefer to use the default authentication and therefore avoid using a custom backend
What you're using is generally called a User Profile which will not store the added fields in the same table (which you have found out). MOre info on that can be found in Extending existing user model.
What you're wanting to do (and the method that I typically need to use in my projects) is Substitute a custom user model. It is a bit more complicated, but once you get the hang of it it's not too bad. It will allow you to store all your User fields in one table instead of in separate tables/models.