Get a default value for null ForeignKey in Django - django

How can I get a default value for null ForeignKey in Django. For ex:
class Owner(models.Model)
name = models.CharField(max_length=200, unique=True)
class Entity(models.Model):
name = models.CharField(max_length=200, unique=True)
owner = models.ForeignKey(Owner)
I am using DRF, so I tried this serializer:
class EntitySerializer(serializers.ModelSerializer):
owner = serializers.SerializerMethodField(read_only=True)
def get_owner(self, obj):
if obj.owner:
return obj.owner_id
return -1
class Meta:
model = Entity
fields = ('id', 'name', 'owner')
This works if I change the key owner to owner_id or something else. But I cannot do it as it has dependencies elsewhere.

Related

multiple ManyToOne relations serializer

sorry my english is not good.
Get request book_id(pk)
How do I serialize ManyToOne fields using BookSerializer to retrieve something
class Book(TimeStampedModel):
name = models.CharField(max_length=25, null=False)
owner = models.ForeignKey(User, on_delete=models.DO_NOTHING,unique=True)
...
class Meta:
db_table = 'books'
class BookMember(TimeStampedModel):
user = models.ForeignKey(User, on_delete=models.DO_NOTHING, null=False)
book = models.ForeignKey(Book, on_delete=models.CASCADE, null=False)
class Meta:
db_table = 'book_member'
class User(AbstractBaseUser, PermissionsMixin):
username = models.CharField(max_length=20, unique=True)
email = models.EmailField(verbose_name=_('email'))
...
class Meta:
db_table = 'user'
class BookSerializer(serializers.ModelSerializer):
user = UserDetailSerializer(read_only=True, many=True, required=False)
owner = UserDetailSerializer(read_only=True, many=True, required=False)
class Meta:
model = Book
fields = '__all__'
I need to book retrieve
class BookViewSet(ModelViewSet):
permission_classes = [AllowAny]
queryset = Book.objects.all()
serializer_class = BookSerializer
renderer_classes = [JSONRenderer]
def retrieve(self, request, *args, **kwargs):
instance = get_object_or_404(self.queryset, many=True)
serializer = self.get_serializer(instance)
return serializer.data
You can span a ManyToManyField [Django-doc] over you BookMember model:
from django.conf import settings
class Book(TimeStampedModel):
# …
owner = models.OneToOneField(
settings.AUTH_USER_MODEL,
on_delete=models.DO_NOTHING
)
members = models.ManyToManyField(
settings.AUTH_USER_MODEL,
through='BookMember'
)
# …
class Meta:
db_table = 'books'
class BookMember(TimeStampedModel):
user = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.DO_NOTHING
)
book = models.ForeignKey(
Book,
on_delete=models.CASCADE
)
class Meta:
db_table = 'book_member'
Then you can serialize with:
class BookSerializer(serializers.ModelSerializer):
user = UserDetailSerializer(read_only=True, many=True, required=False)
members = UserDetailSerializer(read_only=True, many=True, required=False)
class Meta:
model = Book
fields = '__all__'
Note: It is normally better to make use of the settings.AUTH_USER_MODEL [Django-doc] to refer to the user model, than to use the User model [Django-doc] directly. For more information you can see the referencing the User model section of the documentation.
Note: Usually it is better to work with a OneToOneField [Django-doc]
instead of a ForeignKey that has unique=True. A OneToOneField is a ForeignKey with unique=True and some small
modifications: for example it uses by default the name of the model in lowercase as
related_name=… [Django-doc]
and makes accessing the relation in reverse more convenient since that does not require a manager in between.
Note: Specifying null=False [Django-doc] is not necessary: fields are by default not NULLable.

Serialize and create one-to-one relation with parent_link true in django and django rest framework

How to save the object with one-to-one relation and having parent_link=True using serializer. Below are my models and serializer having some fields from the actual model that I wanted to implement. I am not able to save the 'user' relation in the database. It is throwing the integrity error.
class Audit(models.Model):
is_active = models.BooleanField(default=True)
created_at = models.DateTimeField(auto_now_add=True, null=True)
updated_at = models.DateTimeField(auto_now=True, null=True)
class Meta:
abstract = True
class User(Audit):
class Meta:
db_table = 'user'
email = models.EmailField(unique=True)
password = models.TextField()
is_active = models.BooleanField(default=False)
class UserProfile(User):
class Meta:
db_table = 'user_profile'
user = models.OneToOneField(User, on_delete=models.CASCADE, parent_link=True,
primary_key=True)
address = models.TextField(null=True)
dob = models.DateField()
language = models.CharField(max_length=50, null=True)
class UserProfileSerializer(serializers.ModelSerializer):
class Meta:
model = UserProfile
fields = ['user', 'address', 'dob', 'language']
And the requested data looks like this.
{
"email": "abc#pqr.com",
"password": "1234",
"dob": "2021-12-11",
"language" : "English"
}
You can pass user when saving serializer :
serializer.save(user=<USER>)
Note that if you want to create user when creating user profile, you should override create() method in your serializer, first create your user, then create user profile, and pass created user to it

How to view advertises published by auser in his User serializer

I have user serializer in which i need to show in every user detail advertises which he published
models.py:
class Advertise(models.Model):
title = models.CharField(max_length=120)
publisher = models.ForeignKey(User, related_name='publisher',null=True, blank=True, on_delete=models.CASCADE)
category = models.CharField(choices=CATEGORIES, max_length=120)
description = models.TextField(max_length= 200, null=True, blank=True)
image = models.ImageField(upload_to='project_static/Advertise/img', null=True, blank=False)
price = models.DecimalField(decimal_places=2, max_digits=20)
timestamp = models.DateTimeField(auto_now_add=True)
approved = models.BooleanField(default=False)
location = models.CharField(max_length=120 , null=True, blank=True)
contact = models.CharField(max_length=120,null=True, blank=True)
def __str__(self):
"""show ad name in admin page"""
return self.title
def get_absolute_url(self):
return reverse("advertise:advertise-detail", kwargs={"pk":self.pk})
serilaizers.py:
class AdSerializer(serializers.HyperlinkedModelSerializer):
publisher = serializers.ReadOnlyField(source='publisher.username')
url = serializers.CharField(source='get_absolute_url')
class Meta:
model = Advertise
fields = ('url','id','title','publisher','category','description','price','timestamp','approved','location','contact')
class UserSerializer(serializers.HyperlinkedModelSerializer):
publisher = AdSerializer(source='publisher_set', many=True)
class Meta:
model = User
fields = ['id', 'username','publisher']
error:
Got AttributeError when attempting to get a value for field publisher on serializer UserSerializer.
The serializer field might be named incorrectly and not match any attribute or key on the User instance.
Original exception text was: 'User' object has no attribute 'publisher_set'.
ok, I solved it by making some changes:
class AdSerializer(serializers.HyperlinkedModelSerializer):
publisher = serializers.ReadOnlyField(source='publisher.username')
url = serializers.HyperlinkedIdentityField(view_name='advertise:ad_detailview', source='Advertise')
class Meta:
model = Advertise
fields = ('url','id','title','publisher','category','description','price','timestamp','approved','location','contact')
class UserSerializer(serializers.HyperlinkedModelSerializer):
publisher_of = AdSerializer(many=True)
url = serializers.HyperlinkedIdentityField(view_name='advertise:user-detail', source='User')
class Meta:
model = User
fields = ('url', 'id','username', 'email', 'publisher_of')
also in models.py publisher field got related_name="publisher_of" for more symantic
This link helped
https://www.django-rest-framework.org/tutorial/5-relationships-and-hyperlinked-apis/

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()

AttributeError when using nested relations

I'm getting an AttributeError when I try to create a nested relation between two serializers. The weird thing is that I'm doing exactly the same thing as with another API, but this time I don't get it working. Here is the code:
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = get_user_model()
fields = ('id', 'last_login','username', 'created')
class NotificationSerializer(serializers.ModelSerializer):
user_id = UserSerializer()
class Meta:
model = Notification
fields = ('id', 'user_id', 'type', 'parent_id', 'created', 'modified', 'seen')
And the associated models:
class Notification(models.Model):
user = models.ForeignKey(User)
type = models.CharField(max_length=255)
parent_id = models.IntegerField()
created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)
seen = models.SmallIntegerField(default=0)
def __unicode__(self):
return self.type
class Meta:
db_table = 'notification'
class User(AbstractBaseUser, PermissionsMixin):
username = models.CharField(max_length=255, unique=True)
id = models.IntegerField(primary_key=True)
created = models.DateTimeField(auto_now=True)
tag = models.ManyToManyField(Tag)
USERNAME_FIELD = 'username'
objects = MyUserManager()
class Meta:
db_table = 'user'
The error:
Exception Type: AttributeError
Exception Value:
'long' object has no attribute 'id'
Exception Location: /lib/python2.7/site-packages/rest_framework/fields.py in get_component, line 55
Can anyone help me with this error? A normal primary key relationship works, but I would definitely like to get a nested relationship.
Since your Notification model has a field called user, I think you should use it instead of user_id:
class NotificationSerializer(serializers.ModelSerializer):
user = UserSerializer()
class Meta:
model = Notification
fields = ('id', 'user', 'type', 'parent_id', 'created', 'modified', 'seen')
Another small note is do you really want to create:
id = models.IntegerField(primary_key=True)
in your custom User model? By default an User model already has a field called id and it is the PK.