How to show GenericRelation object field value in list_display? - django

models.py
class ModelA(models.Model):
name = models.CharField(max_length=40)
class ModelB(models.Model):
name = models.CharField(max_length=100)
model_c = GenericRelation("modelc")
class ModelC(models.Model):
model_a = models.ForeignKey(ModelA, on_delete=models.CASCADE)
content_type = models.ForeignKey(ContentType,
limit_choices_to={"model__in":["modelb", "modelx", "modely"]},
on_delete=models.CASCADE)
object_id = models.PositiveIntegerField()
details = GenericForeignKey("content_type","object_id")
admin.py
class AdminModelB(admin.ModelAdmin):
list_display = ("name", "model_a")
#staticmethod
def model_a(obj):
return obj.model_c.model_a # 'GenericRelatedObjectManager' object has no attribute 'model_a'
I have ModelB having GenericRelation in field model_c where ModelC contain ContentType as ForeignKey. Now I want to display ModelA.name in list_display of ModelB. I have tried like other foreignkey fields but it gives me an error 'GenericRelatedObjectManager' object has no attribute 'model_a'.

Related

Django many to many field add with through model fields

I have the models below, and I want to add a member to a group in a view. How could I do this, also adding the date_joined and invite_reason correctly. I am using forms without the generics views.
from django.db import models
class Person(models.Model):
name = models.CharField(max_length=128)
def __str__(self):
return self.name
class Group(models.Model):
name = models.CharField(max_length=128)
members = models.ManyToManyField(Person, through='Membership')
def __str__(self):
return self.name
class Membership(models.Model):
person = models.ForeignKey(Person, on_delete=models.CASCADE)
group = models.ForeignKey(Group, on_delete=models.CASCADE)
date_joined = models.DateField()
invite_reason = models.CharField(max_length=64)
To create the reltationship you have to base your form on the relationship model:
class MembershipForm(ModelForm):
class Meta:
fields = ['person', 'group', 'date_joined']
model = Membership
This form will be composed of a select for the persons, a select for the group and a datefield for the date_joined

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

Django REST framework: AttributeError: 'User' object has no attribute 'books'

http://127.0.0.1:8000/app_restFramework/users/ , return text
AttributeError at /app_restFramework/users/
'User' object has no attribute 'books'
models.py
class User(models.Model):
username = models.CharField(max_length=100)
class Book(models.Model):
name = models.CharField(max_length=100)
author = models.CharField(max_length=100)
publisher = models.CharField(max_length=100)
time = models.CharField(max_length=100)
owner = models.ManyToManyField(User)
serializers.py
from app_restFramework.models import Book,User
class UserSerializer(serializers.ModelSerializer):
books = serializers.PrimaryKeyRelatedField(many = True, read_only = True)
class Meta:
model = User
fields = ('id', 'username', 'books')
views.py
class UserList(generics.ListCreateAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
urls.py
url(r'^app_restFramework/users/$', app_restFramework.views.UserList.as_view() ),
You have not specified the related_name in the ManyToManyField. By default it will be book_set. Therefore you can do:
book_set = serializers.PrimaryKeyRelatedField(many=True, read_only=True)
If you want to use books in the serializers, you can do this in the Book model:
owner = models.ManyToManyField(User, related_name="books")

Get a default value for null ForeignKey in 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.

How to specify fields to use of form in view?

I have model:
class ModelA(models.Model):
field_1 = models.CharField(blank=True, null=True)
field_2 = models.CharField(blank=True, null=True)
field_3 = models.CharField(blank=True, null=True)
field_4 = models.CharField(blank=True, null=True)
field_5 = models.CharField(blank=True, null=True)
and I must generate three forms:
class Form1(forms.ModelForm):
class Meta:
model = ModelA
fields = ['field_1', 'field_2', 'field_3']
class Form2(forms.ModelForm):
class Meta:
model = ModelA
fields = ['field_1', 'field_2', 'field_4']
class Form3(forms.ModelForm):
class Meta:
model = ModelA
fields = ['field_1', 'field_2', 'field_5']
How convert it into one form and influence the "fields" in view? I show all this forms in one template.
Are you using class based views? I would suggest using CreateView/UpdateView to do this. You won't need to create a form at all since the class handles that, and you can just specify the fields attribute on the view for whichever fields you want for that particular view. The django doc has a really good example of this: https://docs.djangoproject.com/en/1.6/topics/class-based-views/generic-editing/#model-forms
class AuthorUpdate(UpdateView):
model = Author
fields = ['name']
So for your example it could be:
class View1(CreateView):
model= ModelA
fields = ['field_1', 'field_2', 'field_3']
class View2(CreateView):
model= ModelA
fields = ['field_1', 'field_2', 'field_4']
class View3(CreateView):
model= ModelA
fields = ['field_1', 'field_2', 'field_5']