Unique together with something related by a foreign key - django

class ExamSectionMixin(models.Model):
exam_section = models.ForeignKey('fipi_exam_sections.ExamSection',
blank=True,
null=True,
on_delete=models.CASCADE,
)
class Meta:
abstract = True
class PriorityMixin(models.Model):
priority = models.PositiveIntegerField(blank=False,
default=0,
null=False,
db_index=True)
class NameMixin(models.Model):
name = models.CharField(max_length=255,
null=False,
default="")
def __str__(self):
return self.name
class Meta:
abstract = True
class TaskDescription(NameMixin,
PriorityMixin,
ExamSectionMixin):
class Meta:
constraints = [
models.UniqueConstraint(fields=['exam_section__exam_part', 'name', ],
name='exam_section-name'),
models.UniqueConstraint(fields=['exam_section__exam_part', 'priority', ],
name='exam_section-priority')
]
This code blows up when migrating. That is makemigrations is done. But not migrate.
fipi_task_descriptions.TaskDescription: (models.E012) 'constraints' refers to the nonexistent field 'exam_section__exam_part'.
Could you tell me whether it is possible to organise unique together of exam_part and name and exam_part and priority respectively?

Related

Display field from another model in django admin

Let say I have two model.
I want to make subject field in Program model appear in UserProgramAdmin.
What is the best way to do that?
class Program(models.Model):
name = models.CharField(max_length=15, blank=False)
summary = models.CharField(max_length=200, blank=True)
subject = models.ManyToManyField(Subject, related_name='all_subjects')
is_active = models.BooleanField(default=True)
created_at = models.DateTimeField(auto_now_add=True, editable=False)
updated_at = models.DateTimeField(auto_now=True, editable=False)
def __str__(self) -> str:
return self.name
class UserProgram(models.Model):
user = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
)
program = models.ForeignKey(
Program,
on_delete=models.CASCADE,
)
is_active = models.BooleanField(default=True)
is_finish = models.BooleanField(default=False, editable=False)
/admin.py
class UserProgramAdmin(admin.ModelAdmin):
list_display = ('user', 'program' , 'is_active', 'is_finish')
Thanks in advance
You should define a method on UserProgram and then call it in your UserProgramAdmin list_display attribute
models.py
class UserProgram(models.Model):
#...model attributes
def get_subject(self):
subject = self.program.subject.all()
return subject
admin.py
class UserProjectAdmin(admin.ModelAdmin):
list_display = ('get_subject', 'attribute_to_display')
The best way to do this would be to also show subject in the __str__ in Program field like this:
class Program(models.Model):
#Your other code
def __str__(self):
return f'{self.name} - {self.subject}'
Then the subject of Program shows up in the admin of UserProgram.

DRF 2-way nested serialization with many to many relationship

I have a many-to-many relationship between my Student and Macro models, using an intermediary model
class Person(models.Model):
# cf/NIN optional by design
cf = models.CharField(_('NIN'), unique=True, blank=True, null=True, max_length=16)
first_name = models.CharField(_('first name'), blank=False, max_length=40)
last_name = models.CharField(_('last name'), blank=False, max_length=40)
date_of_birth = models.DateField(_('date of birth'), blank=False)
class Meta:
ordering = ['last_name', 'first_name']
abstract = True
def __str__(self):
return self.first_name + ' ' + self.last_name
class Macro(models.Model):
name = models.CharField(_('name'), unique=True, blank=False, max_length=100)
description = models.TextField(_('description'), blank=True, null=True)
class Meta:
ordering = ['name']
def __str__(self):
return self.name
class Student(Person):
enrollment_date = models.DateField(_('enrollment date'), blank=True, null=True)
description = models.TextField(_('description'), blank=True, null=True)
macro = models.ManyToManyField(Macro, through='MacroAssignement')
class MacroAssignement(models.Model):
student = models.ForeignKey(Student, related_name='macros', on_delete=models.CASCADE)
macro = models.ForeignKey(Macro, related_name='students', on_delete=models.CASCADE)
def __str__(self):
return str(self.student)
I configure serializers in order to exploit the nested serialization when I serialize students
class PersonSerializer(serializers.ModelSerializer):
class Meta:
model = Person
fields = ('id',
'cf',
'first_name',
'last_name',
'date_of_birth')
abstract = True
class StudentSerializer(PersonSerializer):
macro = serializers.StringRelatedField(many=True, read_only=True)
class Meta(PersonSerializer.Meta):
model = Student
fields = PersonSerializer.Meta.fields + ('enrollment_date',
'description',
'macro')
extra_kwargs = {'enrollment_date': {'default': date.today()},
'description': {'required': False}}
class MacroSerializer(serializers.ModelSerializer):
students = StudentSerializer(many=True, read_only=True)
class Meta:
model = Macro
fields = ('id',
'name',
'description',
'students')
Untill here no problem, when I request student data, the macro related information comes along with it. Here's an example
{
"id": 18,
"cf": "ciaciacia",
"first_name": "Paolo",
"last_name": "Bianchi",
"date_of_birth": "2020-05-01",
"enrollment_date": null,
"description": null,
"macro": [
"macro1"
]
},
Now, on the contrary, when I request for a macro, I would like to view also the related students list. I've tried to implement nested serialization also in the MacroSerializer
class MacroSerializer(serializers.ModelSerializer):
students = StudentSerializer(many=True, read_only=True)
This doesn't work, as I get the following error
AttributeError: Got AttributeError when attempting to get a value for field `first_name` on serializer `StudentSerializer`.
The serializer field might be named incorrectly and not match any attribute or key on the `MacroAssignement` instance.
Original exception text was: 'MacroAssignement' object has no attribute 'first_name'.
[NOTE: first_name is a field of Student model inherited from Person model]
Of course I could implement a function to query the database and get the name of students assigned to a given macro, but I'm wondering if there's a buil-in django way of doing it. Kind of like 2-way nested serialization
As stated in previous helpful comments, the fix is about using related_name. My code has been modified as following
serializers.py
class StudentSerializer(PersonSerializer):
macro = serializers.StringRelatedField(many=True, read_only=True)
class Meta(PersonSerializer.Meta):
model = Student
fields = PersonSerializer.Meta.fields + ('enrollment_date',
'description',
'macro')
extra_kwargs = {'enrollment_date': {'default': date.today()},
'description': {'required': False}}
class MacroSerializer(serializers.ModelSerializer):
students = StudentSerializer(many=True, read_only=True)
class Meta:
model = Macro
fields = ('id',
'name',
'description',
'students')
models.py
class Student(Person):
enrollment_date = models.DateField(_('enrollment date'), blank=True, null=True)
description = models.TextField(_('description'), blank=True, null=True)
macro = models.ManyToManyField(Macro, through='MacroAssignement', related_name='students')
Note that what I wrote in my question is actually a poor design decision, because it would lead to a circular dependency. Indeed, StudentSerializer would need MacroSerializer and viceversa. I highly suggest to read this question about dependencies in serializers
************ EDITED ************
Quick fix: set depth = 1 in the related model serializer (in this case, StudentSerializer) Thanks to #neverwalkaloner answer on this question

DRF need values instead of ID

This is my serializer class
class ProjectSerializer(ModelSerializer):
class Meta:
model = Project
exclude = ['deleted_at']
This is Models.py
class MandatoryFields(SoftDeletionModel):
created_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="%(app_label)s_%(class)s_created",null=True)
updated_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="%(app_label)s_%(class)s_updated",null=True)
created_date = models.DateTimeField(auto_now_add=True,null=True)
modified_date = models.DateTimeField(auto_now=True)
class Meta:
abstract = True
class Project(MandatoryFields, Model):
project_name = models.CharField(max_length=255, blank=True)
project_areas = models.CharField(max_length=255, blank=True)
project_manager = models.ForeignKey(
settings.AUTH_USER_MODEL, on_delete=models.CASCADE, blank=True, null=True,
related_name="%(app_label)s_%(class)s_project_manager")
start_date = models.DateField(null=True, blank=True)
end_date = models.DateField(null=True, blank=True)
REQUIRED_FIELDS = []
def __str__(self):
return self.project_name
I am getting Id's for the foreign keys created_by,updated_by,project_manager .But I need the values instead of Id.
for example I am getting
created_by : 1
But I need
created_by: Alex
I have tried the following
class ProjectSerializer(ModelSerializer):
created_by = SlugRelatedField(read_only=True, slug_field='created_by')
class Meta:
model = Project
exclude = ['deleted_at']
But I am getting null values.
I think that's achievable by specifying source attribute for serializer field
Somthing like this:
class ProjectSerializer(ModelSerializer):
created_by = CharField(source="created_by.first_name")
class Meta:
model = Project
exclude = ['deleted_at']
Reference : https://www.django-rest-framework.org/api-guide/fields/#source

How do I filter data with two parameter from two different Django models

I want to create a JSON object which will
Search the particular Projects from the model "EmpProject" by a specific emp_id
Search whose project status is "Pending" from the model "Project" with the help of (1.) Search result
I am using JSON Parser (no models or generic view)
Models
Below are my models I have not use many to many field instead I created a Intermediate Table if the solution is also possible by using manytomanyfield than also suggest
class Employee(models.Model):
employeeid = models.IntegerField()
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
phone_no = models.CharField(max_length=10)
date_of_birth = models.DateField()
email = models.EmailField(unique=True)
password = models.CharField(max_length=50)
designation = models.CharField(max_length=50)
dept_id = models.ForeignKey(Department, on_delete=models.SET_NULL, null=True, blank=True)
class Meta:
ordering = ('id',)
def __str__(self):
return self.emp_name
class Project(models.Model):
projectname = models.CharField(max_length=50, unique=True,)
project_status = models.CharField(max_length=50)
description = models.TextField()
start_date = models.DateField(auto_now_add=True)
due_date = models.DateField()
class Meta:
ordering = ('id',)
def __str__(self):
return self.projectname
class EmpProject(models.Model):
emp_id = models.ForeignKey(Employee,on_delete=models.SET_NULL, null=True, blank=True)
project_id = models.ForeignKey(Project, on_delete=models.SET_NULL, null=True, blank=True)
class Meta:
unique_together = [['emp_id','project_id']]
ordering = ('project_id',)
def __str__(self):
return self.emp_id
Serializer
class EmployeeSerializer(serializers.ModelSerializer):
dept_id = serializers.SlugRelatedField(queryset=Department.objects.all(), slug_field='dept_name')
class Meta:
model = Employee
fields = [
'id',
'employeeid',
'first_name',
'last_name',
'phone_no',
'date_of_birth',
'email',
'password',
'designation',
'dept_id',
]
class ProjectSerializer(serializers.ModelSerializer):
class Meta:
model = Project
fields = [
'id',
'projectname',
'project_status',
'description',
'start_date',
'due_date' ,
]
class EmpProjectSerializer(serializers.ModelSerializer):
emp_id=serializers.SlugRelatedField(queryset=Employee.objects.all(),slug_field='employeeid')
project_id=serializers.SlugRelatedField(queryset=Project.objects.all(),slug_field='projectname')
class Meta:
model = EmpProject
fields = [
'emp_id',
'project_id',
]
You can try something like this:
Project.objects.filter(id__in=EmpProject.objects.filter(id__in=emp_id).values("project_id"), project_status="Pending")
Few points worth mentioning:
It's good idea to use a intermediate table when we want to have extra data related to association. But for that kindly have a look at through attribute supported in ManyToManyField https://docs.djangoproject.com/en/2.2/ref/models/fields/#django.db.models.ManyToManyField.through
project_status is CharField, I think you should consider ChoiceField, charfield may introduce lots of dirty data in database.

Serializers in Foreign Key Django

i need to get information from Reservation, ReservationDetails and Product, but just get Reservation and ReservationDetails
i have 3 models
class Reservation(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
userReservation = models.ForeignKey(User, on_delete=models.CASCADE, default=1)
dateStart = models.DateTimeField(null=False, blank=False, default=datetime.now)
dateFinish = models.DateTimeField(null=False, blank=False, default=datetime.now)
date_Created = models.DateTimeField(auto_now_add=True)
date_Modified = models.DateTimeField(auto_now=True, db_index=True)
def __str__(self):
return str(self.id)
class DetailsReservation(models.Model):
Reservation = models.ForeignKey(Reservation, blank=False, on_delete=models.CASCADE, null=True, related_name='reservation_details')
product = models.ForeignKey(Product, blank=False, on_delete=models.CASCADE, null=True, related_name='products_reservation')
Quantity = models.IntegerField(null=False, blank=False, default=0)
userbyReserva = models.ForeignKey(User, editable=False, on_delete=models.CASCADE, default=1)
class Product(models.Model):
product_Description = models.CharField(max_length=255)
Quantity = models.IntegerField(null=False, blank=False, default=0)
Quantity_Max_Reservation = models.IntegerField(null=False, blank=False, default=0)
product_Comments = models.CharField(max_length=255)
size = models.CharField(max_length=10, null=True)
product_Status = models.BooleanField(default=True)
category = models.ForeignKey(Category, on_delete=models.CASCADE, null=True, related_name='products')
date_Created = models.DateTimeField(default=datetime.now, blank=True)
date_Modified = models.DateTimeField(default=datetime.now, blank=True)
And i tried to create serializers
class ReservationDetailsSerializers(serializers.ModelSerializer):
products = serializers.PrimaryKeyRelatedField(queryset=Product.objects.all(), required=False)
class Meta:
model= DetailsReservation
fields = ['Reservation', 'Quantity', 'userbyReserva', 'products']
class ReservationDetailsListSerializer(serializers.ModelSerializer):
reservation_details = ReservationDetailsSerializers(many=True)
class Meta:
model = Reservation
fields = ['id', 'userReservation', 'dateStart', 'dateFinish', 'reservation_details']
but the response does not show this field
[
{
"id": "6d87ba1c-61bc-41bd-80c8-31a51df8d32f",
"userReservation": 1,
"dateStart": "2018-09-16T17:19:34-05:00",
"dateFinish": "2018-09-16T17:19:35-05:00",
"reservation_details": [
{
"Reservation": "6d87ba1c-61bc-41bd-80c8-31a51df8d32f",
"Quantity": 1,
"userbyReserva": 1
>>"here should show this information product"
}
]
},
{
"id": "0ed26395-2579-4c40-9a63-460f5095ac51",
"userReservation": 2,
"dateStart": "2018-09-16T19:21:24-05:00",
"dateFinish": "2018-09-16T19:21:24-05:00",
"reservation_details": [
{
"Reservation": "0ed26395-2579-4c40-9a63-460f5095ac51",
"Quantity": 1,
"userbyReserva": 2
}
]
}
]
and it is my views.py
class getAllReservationDetails(generics.ListCreateAPIView):
queryset = Reservation.objects.prefetch_related('reservation_details')
print(queryset.query)
serializer_class = ReservationDetailsListSerializer
def get_object(self):
queryset = self.queryset()
obj = get_object_or_404(queryset)
return obj
I review this Link, but i don't know, why doesn't show the information product.
But, that is not working as I wanted.
What should I do?
Did you try creating a serializer for the Product model and use it on the ReservationDetailsSerializers?
class ProductSerializer(serializers.ModelSerializer):
class Meta:
model = Product
fields = '__all__'
class ReservationDetailsSerializers(serializers.ModelSerializer):
products = ProductSerializer(source='product', required=False)
class Meta:
model= DetailsReservation
fields = ['Reservation', 'Quantity', 'userbyReserva', 'products']
You can find more about this topic on Specifying nested serialization
The DetailsReservation model has not attribute products, but it has product. So remove the "s" from products or use source = 'product' in ReservationDetailsSerializers serializer
Method - 1 : removal of "s"
class ReservationDetailsSerializers(serializers.ModelSerializer):
product = serializers.PrimaryKeyRelatedField(queryset=Product.objects.all(), required=False)
class Meta:
model= DetailsReservation
fields = ['Reservation', 'Quantity', 'userbyReserva', 'product']
Method - 2 : speciying source argument
class ReservationDetailsSerializers(serializers.ModelSerializer):
products = serializers.PrimaryKeyRelatedField(queryset=Product.objects.all(),
required=False, source='product')
class Meta:
model = DetailsReservation
fields = ['Reservation', 'Quantity', 'userbyReserva', 'products']
UPDATE
I think you need nested serializer representation. If so, you've to define a seperate serializer (say ProductSerializer) and add it to ReservationDetailsSerializers instead of serializers.PrimaryKeyRelatedField()
#new serializer class
class ProductSerializer(serializers.ModelSerializer):
class Meta:
model = Product
fields = '__all__' # you can specify the fields here
Hence Method-1 become
class ReservationDetailsSerializers(serializers.ModelSerializer):
product = ProductSerializer(required=False)
class Meta:
model= DetailsReservation
fields = ['Reservation', 'Quantity', 'userbyReserva', 'product']
and the Method-2 become
class ReservationDetailsSerializers(serializers.ModelSerializer):
products = ProductSerializer(required=False, source='product')
class Meta:
model = DetailsReservation
fields = ['Reservation', 'Quantity', 'userbyReserva', 'products']