I have 2 models
class CustomUser(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(unique=True)
employee_id = models.CharField(max_length=13, unique=True)
class UserRole(models.Model):
employee_id = models.ForeignKey(CustomUser, to_field='employee_id', unique=True, on_delete=models.CASCADE)
supervisor_id = models.CharField(max_length=20, null=True)
and have defined seriallizers for both models
class UserSerializer(serializers.ModelSerializer):
class Meta:
fields = '__all__'
model = models.CustomUser
class UserRoleSerializer(serializers.ModelSerializer):
class Meta:
fields = '__all__'
model = models.UserRole
consider i have 5 records in both tables
How to fetch all records from both tables (email, employee_id, supervisor_id )
like, where CustomUser.employee_id = UserRole.employee_id
I tried with
models.CustomUser.objects.select_related('UserRole')
But, not able to fetch records from UserRole table.
UserRole.objects.select_related('employee_id')
-- this is fetching only userRole records
Thanks in Advance
You don't get automatic joins in Django, no need for it because you can just follow the ForeignKey relation on the object (the_object_you_get.its_foreign_key). Now, of course, that will hit the DB twice. if you'd rather avoid that, you can use something like .prefetch_related('employee_id') on whatever queryset you need to use. This will prevent you from hitting the DB multiple times (at the price of one larger initial query of course).
Finally, if you wanna serialize a ForeignKey relation, the answer Shakil gave is pretty comprehensive. Only thing is that you don't necessarily need to set the employee_id field as read_only=True (a bit of a limitation). You can also override the UserRoleSerializer .create() the method so that it calls the .create() method of UserSerializer.
I think from UserRole you want to all information about employe's too. What i am thinking you want to get all details information of employee_id foreign_key relation. This can be done by
UserRole.objects.all()
with the following serializers.
class UserSerializer(serializers.ModelSerializer):
class Meta:
fields = ('email','employee_id',)
model = models.CustomUser
class UserRoleSerializer(serializers.ModelSerializer):
employee_id = UserSerializer()
class Meta:
fields = ('employee_id','supervisor_id',)
model = models.UserRole
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.
I am trying to implement a serializer that returns a parent record with its children embedded in the response json object.
My model for the parent and child are both based on database views:
class ProductContributorView(models.Model): # its a model of a view
id = models.IntegerField(primary_key=True)
product_id = models.ForeignKey('ProductTitleView', on_delete=models.DO_NOTHING, related_name='contributors')
sequenceNumber = models.IntegerField()
name = models.CharField(max_length=180)
role = models.CharField(max_length=8, null=True)
description = models.CharField(max_length=1408)
class Meta:
managed = False
ordering = ['sequenceNumber',]
class ProductTitleView(models.Model):
id = models.IntegerField(primary_key=True)
isbn = models.CharField(max_length=80)
titleText = models.CharField(max_length=300)
class Meta:
managed = False
ordering = ['titleText', 'isbn',]
Here are the serializers:
class ProductContributorViewSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = ProductContributorView
fields = ('id', 'product_id', 'sequenceNumber', 'name', 'role', 'description')
def create(self, validated_data):
contributor = ProductContributorView.objects.create(
id=validated_data['id'],
product_id=validated_data['product_id'],
sequenceNumber=validated_data['sequenceNumber'],
name=validated_data['name'],
role=validated_data['role'],
description=validated_data['description'])
return contributor
class ProductTitleViewSerializer(serializers.HyperlinkedModelSerializer):
contributors = serializers.PrimaryKeyRelatedField(many=True, read_only=True)
class Meta:
model = ProductTitleView
fields = ('id', 'isbn', 'titleText', 'contributors')
Here are the views:
class ProductTitleViewList(generics.ListAPIView):
queryset = ProductTitleView.objects.all()
serializer_class = ProductTitleViewSerializer
class ProductContributorViewList(generics.ListAPIView):
queryset = ProductContributorView.objects.all()
serializer_class = ProductContributorViewSerializer
The basic idea is to have the contributors - author, illustrator, etc - returned with the book title based on the FK in the ProductContributorView view matching the id in the ProductTitleView.
When I run this, however, I get the following error:
1054, "Unknown column 'jester_productcontributorview.product_id_id' in 'field list'"
I didn't specify product_id_id in the field list, and I've also tried referring to the field as just product in the field list, but it still repeats the _id_id suffix. Hoping someone will point me to documentation where the FK naming conventions are explained or tell me what to change in the field list. Thanks!
You may just want to try renaming that product_id ForeignKey to just product.
This hints to why it may be broken, I suspect it's breaking somewhere in the serializers inspection of your models regarding the naming of the product_id field on the model.
When you define a ForeignKey on a model there are two properties available for that field. One is the property you define, the ForeignKey object, and you should use this to get the related model. Behind the scenes Django also creates another property which appends _id to the the foreign key's name, this property represents the IntegerField on the database which stores the relation. If you were to view the table in psql you will see the _id columns (and in your case, _id_id).
I am trying to add a search field to the Django admin model CreditsAdmin that will allow me to search the email of related customer objects. The Customer object has a generic foreign key to many different typed of object all of which have an email.
I've already tried defining the function customer_email on the Customer object and using it as a search field, but this gives the error Related Field got invalid lookup: customer_email
class Customer(models.Model):
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey('content_type', 'object_id')
#property
def customer_email(self):
return str(self.content_object.email)
class Credits(models.Model):
credits_remaining = models.IntegerField()
current_period_start = models.DateTimeField()
current_period_end = models.DateTimeField()
customer = models.ForeignKey(Customer, on_delete=models.CASCADE)
class CreditsAdmin(admin.ModelAdmin):
list_display = (
'current_period_start',
'current_period_end',
'customer_name',
'credits_remaining',
)
search_fields = ('customer__customer_email',)
I'd like to be able to search the emails of related generic objects on the Customer model from the CreditsAdmin interface. In particular, one of the content_types that the customer objects relate to is django's auth.User model, but there are also others.
You cannot use property in search_fields, because it looks for columns in database level.
GenericRelation might be a solution. You can create fields in related(by content type) models. For example:
class CntObject(models.Model):
customers = GenericRelation(Customer, related_query_name='cnt_objects')
And in admin panel for Credits:
class CreditsAdmin(admin.ModelAdmin):
list_display = (
'current_period_start',
'current_period_end',
'customer_name',
'credits_remaining',
)
search_fields = ('customer__cnt_objects__email',)
There is a not best thing with this answer. You must be sure that all related content_objects will have email field. May be issues with performance, didn't test it.
Other solution might be, your custom get_search_results method in admin class.
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 have a user table and want to create a backup table named deleted_users that is a clone of the user table. When a user gets deleted I want to move the record from the user table to the deleted_users table.
class LCUser(models.Model):
email = models.EmailField(max_length=100,unique=True)
password = models.CharField(max_length=100)
first_name = models.CharField(max_length=100)
last_name=models.CharField(max_length=100)
class Meta:
db_table = "user"
class LCUserDeleted(LCUser):
deleted_at = models.DateTimeField(auto_now_add=True,null=True)
class Meta:
db_table = "deleted_users"
I tried as above but this creates the user table with all the fields and a deleted_users table with 2 fields ( lcusers_ptr_id and deleted_at ), How can I create the 2nd table with all the fields without typing everything one by one ?
to achieve what you're looking for you actually need 3 models, one abstract one and two actual models:
class BaseLCUser(models.Model):
email = models.EmailField(max_length=100,unique=True)
password = models.CharField(max_length=100)
first_name = models.CharField(max_length=100)
last_name=models.CharField(max_length=100)
class Meta:
abstract = True
class LCUser(BaseLCUser):
class Meta:
db_table = "user"
class LCUserDeleted(BaseLCUser):
deleted_at = models.DateTimeField(auto_now_add=True,null=True)
class Meta:
db_table = "deleted_users"
By using an abstract model as a common parent Django will actually create full tables for each of the models.
Edit:
Regarding the unique E-mail, you might want to avoid setting it to unique on a database level, and control it through your forms, because if you create and account with email example#example.org, delete it, create another one with the same email and delete than new account, you will be trying to have two deleted users with the same email.
another option would be to remove the email field from the abstract Model, and put it in each of the child models, being unique only in the not deleted user.