Django Rest Framework search_fields viewset from genericforeignkey field model - django

All models (Customer, Provider, Contact, Employee) have the same name field to search, in the main or generic model (Comments) have generic foreign key. I need search the field in the main model. It's that posible?
Models:
class Customer(TimeStampedModel):
name = models.CharField()
class Provider(TimeStampedModel):
name = models.CharField()
class Contact(TimeStampedModel):
name = models.CharField()
class Employee(TimeStampedModel):
name = models.CharField()
class Comment(TimeStampedModel):
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.PositiveIntegerField()
commentator = GenericForeignKey('content_type', 'object_id')
Viewset
class CommentsViewSet(BaseViewSet):
queryset = Comments.objects.all()
serializer_class = CommentsSerializer
search_fields = ["commentator__name",]
Message error:
django.core.exceptions.FieldError: Field 'commentator' does not generate an automatic reverse relation and therefore cannot be used for reverse querying. If it is a GenericForeignKey, consider adding a GenericRelation.

You need to add a GenericRelation field to each of your models that are able to receive comments, for instance:
class Customer(TimeStampedModel):
name = models.CharField()
comments = GenericRelation('Comment', related_query_name='customer')
class Provider(TimeStampedModel):
name = models.CharField()
comments = GenericRelation('Comment', related_query_name='provider')
class Contact(TimeStampedModel):
name = models.CharField()
comments = GenericRelation('Comment', related_query_name='contact')
class Employee(TimeStampedModel):
name = models.CharField()
comments = GenericRelation('Comment', related_query_name='employee')
Then you define your search_fields property as the list of all the related_query_names in this way:
search_fields = ["customer__name", "provider__name", "contact__name", "employee__name"]
Please refer to this part of the documentation to know more about GenericRelation

You need to add a GenericRelation to each of your models.
class Customer(TimeStampedModel):
name = models.CharField()
comment = GenericRelation(Comment, related_query_name='customer')
class Provider(TimeStampedModel):
name = models.CharField()
comment = GenericRelation(Comment, related_query_name='provider')
...
search_fields = ["customer__name", "provider__name", "contact__name", "employee_name"]

Related

Django Check for duplicates with 2 model fields

I have a model that looks like this:
class UssdCode(models.Model):
title = models.CharField(max_length=100)
code = models.CharField(max_length=100)
product = models.CharField(max_length=100)
How can I get the admin to alert me and reject my entry when I try to add a new object that has the same 'code' and 'product' as an object already in the database.
You make it unique together. Since django-2.2, you can use the UniqueConstraint [Django-doc] of the Django Constraint framework [Django-doc] for that:
# since Django-2.2
class UssdCode(models.Model):
title = models.CharField(max_length=100)
code = models.CharField(max_length=100)
product = models.CharField(max_length=100)
class Meta:
constraints = [
models.UniqueConstraint(fields=['code', 'product'], name='code_product')
]
Prior to django-2.2, you can use the unique_together meta option [Django-doc]:
# before Django-2.2 (still works on Django-3.0)
class UssdCode(models.Model):
title = models.CharField(max_length=100)
code = models.CharField(max_length=100)
product = models.CharField(max_length=100)
class Meta:
unique_together = [['code', 'product']]

Get data of foreign key relations in a Serializer Django:Rest Framework

I have the following models
class Task(models.Model):
task_name = models.CharField(max_length=255)
task_description = models.TextField(blank=True, null=True)
project_id = models.ForeignKey('Project')
class Project(models.Model):
project_name = models.CharField(max_length=255)
project_description = models.CharField(max_length=255)
I am writing a serializer for task
class TaskSerializer(serializers.ModelSerializer):
class Meta:
model = Task
fields = (
'id',
'task_name',
'task_description',
'project_id',
)
But i want the project name as well in the TaskSerializer which can be accessed using the project_id. How do i achieve this?
Specify a serializer for your project_id field, eg you might have a ProjectSerializer which is a very basic modelserializer. Use that like so:
class ProjectSerializer(serializers.ModelSerializer):
class Meta:
model = Project
fields = ('project_name', )
class TaskSerializer(serializers.ModelSerializer):
project_id = ProjectSerializer()
class Meta:
model = Task
fields = (
'id',
'task_name',
'task_description',
'project_id')
Also might worht noting: when naming foreignkey relation its generally a good practice to just go with the realted model name instead of something different. project_id would in this case just become project. source: Working with models in django

How to set SlugRelated field to a field within an object field

I have the following models:
class Category(models.Model):
name = models.CharField()
... # fields omitted
class Prediction(models.Model):
conversation = models.ForeignKey(Conversation)
category = models.ForeignKey(Category)
... # fields omitted
class Conversation(models.Model):
sid = models.CharField()
... # fields omitted
Now I'm trying to create a model serializer for Category that would return me the following serialized object:
{
"name":"blah",
"conversations":[
"2af22188c5c97256", # This is the value of the sid field
"073aef6aad0883f8",
"5d3dc73fc8cf34be",
]
}
Here is what I have in my serializer:
class CategorySerializer(serializers.ModelSerializer):
conversations = serializers.SlugRelatedField(many=True,
read_only=True,
source="prediction_set",
slug_field='conversation.sid')
class Meta:
model = models.Class
fields = ('class_name', 'conversations')
However, this doesn't work because somehow django doesn't allow me to set slug_field to be a field that's within an object field. Any suggestions on how to accomplish this?
You are modelling a Many-to-Many relationship between Categorys and Conversations with a explicit table called Prediction. The django way of doing this would be to explicitly state the Many-to-Many on either side of the relationship and specify Prediction as the "through-model":
Shamelessly stolen example from this question:
class Category(models.Model):
name = models.CharField(max_length=255)
slug = models.SlugField(unique=True, max_length=255, blank=True,default=None)
desc = models.TextField(blank=True, null=True )
...
class Post(models.Model):
title = models.CharField(max_length=255)
pub_date = models.DateTimeField(editable=False,blank=True)
author = models.ForeignKey(User, null=True, blank=True)
categories = models.ManyToManyField(Category, blank=True, through='CatToPost')
...
class CatToPost(models.Model):
post = models.ForeignKey(Post)
category = models.ForeignKey(Category)
...
This shows a good way to set up the relationship.
Equally shamelessly stolen from the answer by #Amir Masnouri:
class CategorySerializer(serializers.ModelSerializer):
class Meta:
model = Category
fields = ('name','slug')
class PostSerializer(serializers.ModelSerializer):
class Meta:
model = Post
fields = ('id','{anything you want}','categories')
depth = 2
This shows a nice way of achieving the nested serialization behavior that you would like.

Django REST Framework -- is multiple nested serialization possible?

I would like to do something like the following:
models.py
class Container(models.Model):
size = models.CharField(max_length=20)
shape = models.CharField(max_length=20)
class Item(models.Model):
container = models.ForeignKey(Container)
name = models.CharField(max_length=20)
color = models.CharField(max_length=20)
class ItemSetting(models.Model):
item = models.ForeignKey(Item)
attribute_one = models.CharField(max_length=20)
attribute_two = models.CharField(max_length=20)
serializers.py
class ItemSettingSerializer(serializers.ModelSerializer):
class Meta:
model = ItemSetting
class ItemSerializer(serializers.ModelSerializer):
settings = ItemSettingSerializer(many=True)
class Meta:
model = Item
fields = ('name', 'color', 'settings')
class ContainerSerializer(serializers.ModelSerializer):
items = ItemSerializer(many=True)
class Meta:
model = Container
fields = ('size', 'shape', 'items')
When I do nesting of only one level (Container and Item) it works for me. But when I try to add another level of nesting with the ItemSetting, it throws an AttributeError and complains 'Item' object has no attribute 'settings'
What am I doing wrong?
Multiple nested serialization works for me. The only major difference is that I specify a related_name for the FK relationships. So try doing this:
class Item(models.Model):
container = models.ForeignKey(Container, related_name='items')
class ItemSetting(models.Model):
item = models.ForeignKey(Item, related_name='settings')
Hope this works for you.

Django REST-framework Serializer pk field?

What is the pk field in the Serializer class in Django-REST-framework?
I assume that it is the primary key, but is the name 'pk' a reserved term?
How does the Serializer class know that is to be the primary key of the Snippet model?
I see no field in the Snippet model named 'pk'.
class SnippetSerializer(serializers.Serializer):
pk = serializers.Field() # Note: `Field` is an untyped read-only field.
title = serializers.CharField(required=False,
max_length=100)
code = serializers.CharField(widget=widgets.Textarea,
max_length=100000)
linenos = serializers.BooleanField(required=False)
language = serializers.ChoiceField(choices=LANGUAGE_CHOICES,
default='python')
style = serializers.ChoiceField(choices=STYLE_CHOICES,
default='friendly')
....class SnippetSeralizer continues
class Snippet(models.Model):
created = models.DateTimeField(auto_now_add=True)
title = models.CharField(max_length=100, blank=True, default='')
code = models.TextField()
linenos = models.BooleanField(default=False)
language = models.CharField(choices=LANGUAGE_CHOICES,
default='python',
max_length=100)
style = models.CharField(choices=STYLE_CHOICES,
default='friendly',
max_length=100)
class Meta:
ordering = ('created',)
pk is a property that lives on the base Model class in django.db.models:
class Model(object):
...
pk = property(_get_pk_val, _set_pk_val)
...
which is used to identify the primary key for the model. I haven't used Django-REST, but they probably just map that to the field on the model.
And if you are using generic views in Django REST Framework, and you would like to use a different name for the pk field — say id, you can set lookup_field in your view to id.