I have a model Student:
class Student(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=30, verbose_name='Name')
lastname = models.CharField(max_length=100, verbose_name='Lastname')
history = HistoricalRecords()
Also I have a model:
class Class(models.Model):
id = models.AutoField(primary_key=True)
student = models.models.ForeignKey(Student,on_delete = models.CASCADE, related_name='+')
my admin.py
class ClassResource(resources.ModelResource):
class Meta:
model = Class
fields = ('student',)
def dehydrate_student(self, Class):
student= getattr(Class.student, "name")
return '%s' % (student)
class ClassExportAdmin(ImportExportModelAdmin, ClassAdmin):
resource_class = ClassResource
admin.site.register(Class, ClassExportAdmin)
Now I am executing only name, is that possible to dehydrate the same field student one more time. I need past into my 2 column the surname of the student.
To export both Student.name and Student.lastname you can directly reference a Foreign Key relation in the fields parameter (docs):
class ClassResource(resources.ModelResource):
class Meta:
model = Class
fields = ('student__name', 'student__lastname')
This means that the column names will appear in your export as:
student__name
student__lastname
If you want the name to be different, you can directly declare a field:
name = Field(
column_name='name',
attribute='name',
widget=ForeignKeyWidget(Student, 'name'))
This will then appear in the export under name.
Related
As I am using string representation of a model, it is also shown in a autocomplete_fields (Select2). But the problem is that when i try to search in the field, it is searching the model's name field, not string representation.
Here is my code example:
models.py
class Store(models.Model):
name = models.CharField(max_length=256)
class Department(models.Model):
name = models.CharField(max_length=256)
store = models.ForeignKey(Store, on_delete=models.CASCADE)
class Shelf(models.Model):
name = models.CharField(max_length=256)
department = models.ForeignKey(Department, on_delete=models.CASCADE)
def __string__(self):
return f'{self.department.store.name} {self.department.name} {self.name}'
class Product(models.Model):
name = models.CharField(max_length=256)
shelf = models.ForeignKey(Shelf, on_delete=models.CASCADE)
admin.py
#admin.register(Product)
class ProductAdmin(admin.ModelAdmin):
autocomplete_fields = ('shelf',)
list_display = ('name', 'shelf')
Is it posible to search by model string representation in this case?
First of all your string method should be __str__ instead and since the str method is not a field you cannot add it to the autocomplete field since it looks for a field and works on the DB level.
What you can do is:
#admin.register(Product)
class ProductAdmin(admin.ModelAdmin):
autocomplete_fields = ('shelf__department__store__name','shelf__department__name','name')
list_display = ('name', 'shelf')
I am trying to create a Many to Many relation with a model in between, I have a Client model, and a Zone model, each client may have access to different zones, and each zone may have multiple clients.
Therefore I created a model called Access Permission, that stores said relation, and I want to show a dropdown selector in the post form that shows the existing clients and zones, or to ask for the Id of an existing object, instead of showing the form to create new ones.
These are my models:
class Zone(models.Model):
name = models.TextField()
created = models.DateTimeField(auto_now=True)
def __str__(self):
return '%s' % (self.name)
class Client(models.Model):
name = models.TextField()
birthDate = models.DateField()
created = models.DateTimeField(auto_now=True)
def __str__(self):
return '%s' % (self.name)
class AccessPermission(models.Model):
idClient = models.ForeignKey(Client, on_delete=models.CASCADE, null=False)
idZone = models.ForeignKey(Zone, on_delete=models.CASCADE, null=False)
And these my current serializers:
class ZoneSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Zone
fields = ('name',)
class ClientSerializer(serializers.HyperlinkedModelSerializer):
zones = ZonesSerializer(source='accesspermission_set', many=True, read_only=True)
class Meta:
model = Client
fields = ('name', 'birthDate', 'zones')
class AccessPermissionSerializer(serializers.ManyRelatedField):
idClient = ClientSerializer(many=False)
idZone = ZoneSerializer(many=False)
class Meta:
model = AccessPermission
fields = ('idClient', 'idZone')
Is there any way to ask for the Id of an existing object, or show the existing ones, instead of the fields to create new ones?
You can do it like:
models
class AccessPermission(models.Model):
client = models.ForeignKey(Client, on_delete=models.CASCADE, null=False)
zone = models.ForeignKey(Zone, on_delete=models.CASCADE, null=False)
serializers
class AccessPermissionSerializer(serializers.ManyRelatedField):
id = serializers.IntegerField(read_only=True)
client_id = serializers.PrimaryKeyRelatedField(
queryset=Client.objects.all(), source='client', allow_null=False, required=True
)
zone_id = serializers.PrimaryKeyRelatedField(
queryset=Zone.objects.all(), source='zone', allow_null=False, required=True
)
class Meta:
model = AccessPermission
fields = (
'id', 'client_id', 'zone_id'
)
I have two models where employee have relation with person model but person have no relation with employee model.
Like:
class Person(models.Model):
name = models.CharField(max_length=100)
address = models.CharField(max_length=100)
class Employee(models.Model):
person = models.ForeignKey(Person, related_name='person_info')
code = models.CharField()
In such cases I want code field data in person serializer.
I can solved this with writing method in person model or using SerializerMethodField in person serializer
like this:
def get_employee_code(self):
return Employee.objects.get(person=self).id
and add this as source in person serializer
employee_code = serializers.CharField(source='get_employee_code')
Or adding employee serializer into person serialiszer
class PersonSerializer(serializers.ModelSerializer):
employee = EmployeeSerializer()
class Meta:
model = Person
fields = ('name', 'address', 'employee')
But i was trying to do this with reverse relation but i can't. I have tried like this, it gives an error
Serializer:
class PersonSerializer(serializers.ModelSerializer):
employee_code = serializers.CharField(source='person_info.code')
class Meta:
model = Person
fields = ('name', 'address', 'employee_code')
How can i solve this with reverse relation?
At the moment because you are using a ForeignKey field on the person attribute, it means that its returning a list when you access the reverse relation.
One solution would be to use a slug related field, though this must have many and read_only set to True, and will return a list because of the ForeignKey field.
class PersonSerializer(serializers.ModelSerializer):
employee_code = serializers.SlugRelatedField(
source='person_info',
slug_field='code',
many=True,
read_only=True,
)
class Meta:
model = Person
fields = ('name', 'address', 'employee_code')
The other option is to change your ForeignKey into a OneToOneField, which would still need read_only set to True but it will not return a list.
class Person(models.Model):
name = models.CharField(max_length=100)
address = models.CharField(max_length=100)
class Employee(models.Model):
person = models.OneToOneField(Person, related_name='person_info')
code = models.CharField()
class PersonSerializer(serializers.ModelSerializer):
employee_code = serializers.SlugRelatedField(
source='person_info',
slug_field='code',
read_only=True,
)
class Meta:
model = Person
fields = ('name', 'address', 'employee_code')
Or, if you don't want to change the ForeignKey, you could add a employee_code property method to the model instead to return the first employee code in the person_info relation.
class Person(models.Model):
name = models.CharField(max_length=100)
address = models.CharField(max_length=100)
#property
def employee_code(self):
employees = self.person_info.filter()
if employees.exists():
return employees.first().code
return ''
class Employee(models.Model):
person = models.OneToOneField(Person, related_name='person_info')
code = models.CharField()
class PersonSerializer(serializers.ModelSerializer):
employee_code = serializers.CharField(
read_only=True,
)
class Meta:
model = Person
fields = ('name', 'address', 'employee_code')
you can access the reverse relation with custom SerializerMethodField()
class PersonSerializer(serializers.ModelSerializer):
employee_code = serializers.SerializerMethodField()
def get_employee_code(self, obj):
return obj.person_info.code
class Meta:
model = Person
fields = ('name', 'address', 'employee_code')
I have 3 models using Django Framework:
class Student(models.Model):
name = models.CharField()
surname = models.CharField()
class Group(models.Model):
groupId = models.AutoField()
name = models.CharField()
students = models.ForeignKey(Student)
class Faculty(models.Model):
facultyId = models.AutoField()
students = models.ForeignKey(Student)
I need to get the list of all students and for each one to have the student's group and faculty.
Well, first you need to modify your model relationships. With your current models, each Faculty and Group will have a single student.
You can modify the model to this:
class Group(models.Model):
groupId = models.AutoField()
name = models.CharField()
class Faculty(models.Model):
facultyId = models.AutoField()
class Student(models.Model):
name = models.CharField()
surname = models.CharField()
group = models.ForeignKey(Group)
faculty = models.ForeighKey(Faculty)
Then to get the Group and faculty of each student you can use select_related.
Now your query will look like this:
Students.objects.all().select_related('group', 'faculty')
class Student(models.Model):
name = models.CharField()
surname = models.CharField()
class Group(models.Model):
groupId = models.AutoField()
name = models.CharField()
students = models.ForeignKey(Student, related_name="group")
class Faculty(models.Model):
facultyId = models.AutoField()
students = models.ForeignKey(Student, "related_name"="faculty")
you can get this data Student.objects.filter(group__isnull=False, faculty__isnull=False )
It will return the student who have faculty and group.
for Json data:
class Student(serializer.ModelSerializer):
class Meta:
model = Student
fields = ('name', 'surname' , 'group', 'faculty')
Is it possible to access the fields in a parent Model through a filter query?
For example if I have the following Model structure:
class Space(models.Model):
name = models.CharField(max_length=500)
ident = models.CharField(max_length=4)
# Meta
class Meta:
abstract = True
class Airwaves(Space):
#cached_property
def stations(self):
name_substr = self.name
if " " in name_substr:
name_substr = name_substr[:name_substr.index(" ")]
return Station.objects.filter(Q(ident__contains=self.ident) |
Q(name__contains=self.name) |
Q(name__contains=name_substr))
class Radio(models.Model):
# The fields I would like to access from Airwaves
ident = models.CharField(max_length=4)
name = models.CharField(max_length=500)
# Meta
class Meta:
abstract = True
class Station(Radio):
frequency = models.DecimalField(max_digits=8, decimal_places=2)
With the existing code I get the error Cannot resolve keyword 'ident' into field. Choices are: frequency, id.
How can I access the ident and name fields for the filter query in Airwaves?