When I open the model, one field value is replaced automatically - django

Have a stupid issue: When I open the employee model (in django admin), one field (employee_type) value is replaced automatically, idk why...
Example: I create employee, define employee type as manager, save. In DB value is manager. After that, I open employee and see employee type as sewer and if I save, that value will saved in DB.
I created text choices for this field, and In DB field is defined as enum.
I tried to research the issue, value isn't used from DB, always first value from text choices is used.
By the way, I created same fields (enum in DB and text choices in the model) in other model. And all works properly.
How can I fix it???
Models.py with the issue:
class Employee(models.Model):
class EmployeeType(models.TextChoices):
SEWER = 'SEWER', _('Sewer')
MANAGER = 'MANAGER', _('Manager')
UNDEFINED = 'UNDEFINED', _('Undefined')
user = models.OneToOneField(User,
models.CASCADE,
db_column='user',
verbose_name=_('User'),
primary_key=True)
employee_type = models.CharField(db_column='Employee type',
verbose_name=_('Employee type'),
max_length=9,
choices=EmployeeType.choices,
default=EmployeeType.UNDEFINED)
phone = models.CharField(db_column='Phone',
verbose_name=_('Phone'),
max_length=255)
work_xp = models.IntegerField(db_column='Work XP',
verbose_name=_('Work XP'),
blank=True,
null=True)
Another one models.py. With same fields but without issues:
class Order(models.Model):
class OrderStatus(models.TextChoices):
CREATED = 'Created', _('Created')
CANCELLED = 'Cancelled', _('Cancelled')
IN_PROGRESS = 'In progress', _('In progress')
COMPLETED = 'Completed', _('Completed')
PASSED_TO_CLIENT = 'Passed to the client', _('Passed to the client')
RETURNED_FOR_REWORK = 'Returned for rework', _('Returned for rework')
class Urgency(models.TextChoices):
LOW = 'Low', _('Low urgency')
MEDIUM = 'Medium', _('Medium urgency')
HIGH = 'High', _('High urgency')
VERY_HIGH = 'Very high', _('Very high urgency')
class LabourIntensity(models.TextChoices):
LOW = 'Low', _('1-3 days')
MEDIUM = 'Medium', _('4-6 days')
HIGH = 'High', _('7-9 days')
VERY_HIGH = 'Very high', _('10+ days')
class PaymentStatus(models.TextChoices):
PENDING = 'Pending payment', _('Pending payment')
PREPAYMENT_MADE = 'Prepayment made', _('Prepayment made')
PAID = 'Paid', _('Paid')
id_service = models.ForeignKey(Service,
models.SET_NULL,
db_column='id_Service',
verbose_name=_('Service'),
blank=True,
null=True)
status = models.CharField(db_column='Status',
verbose_name=_('Status'),
max_length=20,
choices=OrderStatus.choices,
default=OrderStatus.CREATED)
payment_status = models.CharField(db_column='Payment status',
verbose_name=_('Payment status'),
max_length=15,
choices=PaymentStatus.choices,
blank=True,
null=True)
prepayment = models.DecimalField(db_column='Prepayment',
verbose_name=_('Prepayment'),
max_digits=19,
decimal_places=2,
blank=True,
null=True)
cost = models.DecimalField(db_column='Cost',
verbose_name=_('Cost'),
max_digits=19,
decimal_places=2,
blank=True,
null=True)
start_date = models.DateTimeField(db_column='Start date',
verbose_name=_('Start date'),
blank=True,
null=True)
end_date = models.DateTimeField(db_column='End date',
verbose_name=_('End date'),
blank=True,
null=True)
id_client = models.ForeignKey(Client,
models.SET_NULL,
db_column='id_Client',
verbose_name=_('Client'),
blank=True,
null=True)
id_employee = models.ForeignKey(Employee,
models.SET_NULL,
db_column='id_Employee',
verbose_name=_('Employee'),
blank=True,
null=True)
labour_intensity = models.CharField(db_column='Labour intensity',
verbose_name=_('Labour intensity'),
max_length=9,
choices=LabourIntensity.choices,
default=LabourIntensity.LOW)
urgency = models.CharField(db_column='Urgency',
verbose_name=_('Urgency'),
max_length=9,
choices=Urgency.choices,
default=Urgency.LOW)
materials = models.ManyToManyField(Material, through='OrderMaterials')
comment = models.TextField(db_column='Comment',
verbose_name=_('Comment'),
blank=True,
null=True)

I solved this issue.
In DB a type of field "employee_type" was defined as:
ENUM('Undefined','Sewer','Manager')
But the model has EmployeeType choices with uppercase.
Solution: I changed lowercase to uppercase of the values in the field type in DB:
ENUM('UNDEFINED','SEWER','MANAGER')
Now everything works fine.

Related

Retrieve items from Many-to-Many relationship in Django query

Models.py
class SalesOrderItems(models.Model):
item = models.ForeignKey(MasterItems, on_delete=models.CASCADE)
item_quantity = models.IntegerField(default=0)
class SalesOrder(models.Model):
delivery_method_choice = (('Full-Truck Load', 'Full-Truck Load'), ('Part-Truck Load', 'Part-Truck Load'))
status_choices = (('On Hold', 'On Hold'),('Ready to Dispatch', 'Ready to Dispatch'),('Dispatched', 'Dispatched'))
owner = models.ForeignKey(Teacher, on_delete=models.CASCADE, related_name='so_owner')
client = models.ForeignKey(MasterClient, on_delete=models.CASCADE, related_name='so_client')
reference_no = models.CharField(max_length=500, blank=True, null=True)
date = models.DateField(default=datetime.date.today)
shipment_date = models.DateField(default=datetime.date.today)
delivery_method = models.CharField(max_length=500, default='Full-Truck Load', choices=delivery_method_choice)
items = models.ManyToManyField(SalesOrderItems, related_name='items_so', blank=True, null=True)
status = models.CharField(max_length=500, default='On Hold', choices=status_choices)
origin = models.CharField(max_length=255)
destination = models.CharField(max_length=255)
I want to retrieve the items of a particular sales order by django query
My attempt to get the items:
items = []
for i in sales_orders:
so = SalesOrder.objects.filter(pk=i)[0]
print("items",so.items)
Output:
items classroom.SalesOrderItems.None
How can I get the list of items in a particular SalesOrder ??
sales_orders = SalesOrder.objects.prefetch_related('items').filter(**sales_filter_here)
for sales_order in sales_orders:
for sales_order_item in sales_order.items.all():
print(sales_order_item)
this query will work for you
SalesOrder.objects.filter(id=1).values_list('items__item__item_name')
below is my simple Masteritems model
class MasterItems(models.Model):
item_name = models.CharField(max_length=50)
def __str__(self):
return self.item_name
by this way you will get every item name in queryset. this is my simple output
<QuerySet [('rice',), ('pepsi',), ('Computer',)]>

How to specify GROUP BY field in Dajngo ORM?

I have the following working SQL statement:
SELECT id FROM ops_kpitarget WHERE (site_id = 1 AND validFrom <= "2019-08-28") GROUP BY kpi_id HAVING validFrom = (MAX(validFrom))
But I cannot get this to work inside Django ORM.
The best I got was the code below, but then the database is complaining that it is missing a GROUP BY clause to make HAVING work.
How can I get the same query with specifying "kpi_id" as the GROUP BY clause using Djangos ORM? Any ideas?
KpiTarget.objects
.filter(validFrom__lte=fromDate)
.values("id", "kpi")
.filter(validFrom=Max("validFrom"))
... which translates to:
SELECT "ops_kpitarget"."id", "ops_kpitarget"."kpi_id" FROM "ops_kpitarget" WHERE "ops_kpitarget"."validFrom" <= 2019-08-14 HAVING "ops_kpitarget"."validFrom" = (MAX("ops_kpitarget"."validFrom"))
I played around with annotate but this is not really giving me what I want...
Update:
Some background: I have 3 tables: Kpi, KpiTarget, and KpiTargetObservation.
Kpi holds all general information regarding the KPI like name, typeetc.
KpiTarget stores target values defined for several different sites. These target values can change over time. Hence, I have included the combination of MAX() and validFrom <= (some date) to determine the latest valid target for any given KPI.
KpiTargetObservation stores the individual observations per defined KPI target. It just holds the link to KpiTarget, the date of the observation, and the observation value.
The final queries I need to build will have to give me something like the following:
give me all known KPIs per given site
tell me the most recent target value for the KPIs you found
get me any known observation that is related to the identified kpi targets
I am struggling with the 2nd query, and specifically how to get this working using Djangos ORM. I could just escape to RAW SQL, but I would prefer to not to, if possible.
The models:
class KpiCategory(models.Model):
name = models.CharField(max_length=255)
def __str__(self):
return self.name
class Kpi(models.Model):
KPI_KIND_CHOICES = [("BOOL", "Boolean"), ("FLOAT", "Float"), ("STRING", "String")]
# firstCreated = models.DateField(auto_now_add=True)
# firstCreatedBy = models.OneToOneField(User, on_delete=models.CASCADE)
# lastEdited = models.DateField(auto_now=True)
# lastEditedBy = models.OneToOneField(User, on_delete=models.CASCADE)
name = models.CharField(max_length=255)
category = models.ForeignKey(KpiCategory, on_delete=models.CASCADE)
kind = models.CharField(max_length=150, choices=KPI_KIND_CHOICES)
def __str__(self):
return self.name
class KpiTarget(models.Model):
# firstCreated = models.DateField(auto_now_add=True)
# firstCreatedBy = models.OneToOneField(User, on_delete=models.CASCADE)
# lastEdited = models.DateField(auto_now=True)
# lastEditedBy = models.OneToOneField(User, on_delete=models.CASCADE)
kpi = models.ForeignKey(Kpi, on_delete=models.CASCADE, related_name="kpiTargetSet")
targetDouble = models.DecimalField(
max_digits=20, decimal_places=15, blank=True, null=True
)
targetBool = models.BooleanField(blank=True, null=True)
targetStr = models.CharField(max_length=255, blank=True)
site = models.ForeignKey(Site, on_delete=models.CASCADE)
validFrom = models.DateField()
def __str__(self):
return str(self.kpi)
class KpiObservation(models.Model):
# firstCreated = models.DateField(auto_now_add=True)
# firstCreatedBy = models.OneToOneField(User, on_delete=models.CASCADE)
# lastEdited = models.DateField(auto_now=True)
# lastEditedBy = models.OneToOneField(User, on_delete=models.CASCADE)
kpiTarget = models.ForeignKey(
KpiTarget, on_delete=models.CASCADE, related_name="kpiObservationSet"
)
observed = models.DateField()
observationDouble = models.DecimalField(
max_digits=20, decimal_places=15, blank=True, null=True
)
observationBool = models.BooleanField(blank=True, null=True)
observationStr = models.CharField(max_length=255, blank=True)
def __str__(self):
return str(self.observed)
KpiTarget.objects.filter(validFrom__lte=fromDate).annotate(validFrom=Max("validFrom")).order_by('kpi__id').values("id", "kpi")

Django connected SQL queries with filters

Example:
class Room(models.Model):
assigned_floor = models.ForeignKey(Floor, null=True, on_delete=models.CASCADE)
room_nr = models.CharField(db_index=True, max_length=4, unique=True, null=True)
locked = models.BooleanField(db_index=True, default=False)
last_cleaning = models.DateTimeField(db_index=True, auto_now_add=True, null=True)
...
class Floor(models.Model):
assigned_building = models.ForeignKey(Building, on_delete=models.CASCADE)
wall_color = models.CharField(db_index=True, max_length=255, blank=True, null=True)
...
class Building(models.Model):
name = models.CharField(db_index=True, max_length=255, unique=True, null=True)
number = models.PositiveIntegerField(db_index=True)
color = models.CharField(db_index=True, max_length=255, null=True)
...
I want to output all rooms in a table sorted by Building.number.
Data which I want to print for each room:
Building.number, Building.color, Building.name, Floor.wall_color, Room.last_cleaning
Furthermore I want to allow optional filters:
Room.locked, Room.last_cleaning, Floor.wall_color, Building.number, Building.color
With one table it's no Problem for me, but I don't know how I archive this with three tables.
kwargs = {'number': 123}
kwargs['color'] = 'blue'
all_buildings = Building.objects.filter(**kwargs).order_by('-number')
Can you please help me? Do I need write raw SQL queries or can I archive this with the Django model query APIs?
I'm using the latest Django version with PostgreSQL.
No raw sql needed:
room_queryset = Room.objects.filter(assigned_floor__wall_color='blue')
^^
# A double unterscore declares the following attribute to be a field of the object referenced in the foregoing foreign key field.
for room in room_queryset:
print(room.assigned_floor.assigned_building.number)
print(room.assigned_floor.assigned_building.color)
print(room.assigned_floor.assigned_building.name)
print(room.assigned_floor.wall_color)
print(room.last_cleaning)

Querying from child of model given django inheritance and m2m link to parent

Among my models, I have Exercise which has a m2m link to Workout. I also have WorkoutPlan and LogBook which are types of Workouts. WorkoutPlan is where ideal workouts are stored. LogBook is where a user stores the workout they actually completed. They can also link a LogBook to a WorkoutPlan to indicate that the actual performance was connected to an original ideal plan.
class Exercise(NameDescModel):
muscles = models.ManyToManyField(Muscle, blank=True)
groups = models.ManyToManyField(Group, blank=True)
priority_score = models.DecimalField(max_digits=5, decimal_places=3, editable=False, default = 0)
frequency = models.IntegerField()
time_period = models.CharField(max_length=2, choices=TIME_PERIOD_CHOICES,default=WEEK)
last_p_calc_date = models.DateField("Date of Last Priority Recalculation", blank=True, null=True, default=datetime.now)
class Workout(NameDescModel):
exericises = models.ManyToManyField(Exercise, through='Measurement')
class WorkoutPlan(Workout):
priority_score = models.DecimalField(max_digits=5, decimal_places=3, editable=False, default = 0)
frequency = models.IntegerField()
time_period = models.CharField(max_length=2, choices=TIME_PERIOD_CHOICES,default=WEEK)
time_estimate = models.IntegerField()
last_p_calc_date = models.DateField("Date of Last Priority Recalculation", blank=True, null=True, default=datetime.now)
class LogBook(Workout):
workout_date = models.DateField(default=datetime.now)
notes = models.TextField(blank=True)
workout_plan = models.ForeignKey(WorkoutPlan, blank=True, null=True)
For a given exercise, I want to pull all of the WorkoutPlans that the exercise is in.
exercise_list = Exercise.objects.order_by('-last_p_calc_date')
for exercise in exercise_list:
print exercise
workout_list = []
for workout in exercise.workout_set.all():
workout_list.append(workout)
print list(set(workout_list))
print ""
I'm realizing that the list of workouts include both WorkoutPlans and LogBooks because exercise is attached to Workout, not to WorkoutPlans or LogBooks specifically.
How might I pull Workouts that are affiliated only to WorkoutPlans?
I think you've over-used inheritance here.
I guess you wanted to put the exercises field into a base model because WorkoutPlan and LogBook both have that field. But it seems like in reality WorkoutPlan and LogBook are different types of thing, rather than sub-types of Workout.
Possibly don't you need the exercises field on the LogBook model at all, since it has a foreign key to WorkoutPlan which seems a sensible place to record the exercises... unless you want to record the difference between the plan and exercises actually performed?
I would model it like this:
class Exercise(NameDescModel):
muscles = models.ManyToManyField(Muscle, blank=True)
groups = models.ManyToManyField(Group, blank=True)
priority_score = models.DecimalField(max_digits=5, decimal_places=3, editable=False, default = 0)
frequency = models.IntegerField()
time_period = models.CharField(max_length=2, choices=TIME_PERIOD_CHOICES,default=WEEK)
last_p_calc_date = models.DateField("Date of Last Priority Recalculation", blank=True, null=True, default=datetime.now)
class WorkoutPlan(Workout):
exercises = models.ManyToManyField(Exercise, through='Measurement')
priority_score = models.DecimalField(max_digits=5, decimal_places=3, editable=False, default = 0)
frequency = models.IntegerField()
time_period = models.CharField(max_length=2, choices=TIME_PERIOD_CHOICES,default=WEEK)
time_estimate = models.IntegerField()
last_p_calc_date = models.DateField("Date of Last Priority Recalculation", blank=True, null=True, default=datetime.now)
class LogBook(Workout):
exercises = models.ManyToManyField(Exercise, through='Measurement')
workout_date = models.DateField(default=datetime.now)
notes = models.TextField(blank=True)
workout_plan = models.ForeignKey(WorkoutPlan, blank=True, null=True)
You can then query either WorkoutPlans or LogBooks from an Exercise instance:
exercise_list = Exercise.objects.order_by('-last_p_calc_date')
for exercise in exercise_list:
print exercise
workout_list = exercise.workoutplan_set.all()
print ""

Django: Are multiple Generic Relations in one Model bad design?

I have a model with multiple Generic Relations that has become very complicated to use in my templates. The model is a 'Gig' or musical event that takes place at a 'Venue' and/or a 'Festival' and has a 'Musician' and/or an 'Ensemble'.
Where it gets complicated is that each 'Gig' has a presenter, promoter and an agent. These are setup as generic relations to other models such as 'PresenterCompany'. A Presenter company could be a promoter, presenter, or agent, or all of them for the same gig. Here are the models (simplified for ref):
class Gig(models.Model):
description = models.CharField(max_length=100, blank=True)
date = models.DateTimeField()
venue = models.ForeignKey(Venue)
festival = models.ForeignKey(Festival, blank = True, null=True)
musician = models.ManyToManyField(Musician, blank=True)
ensembles = models.ManyToManyField(Ensemble, blank = True)
presenter_content_type = models.ForeignKey(ContentType,
limit_choices_to={"model__in": ("Individual", "ArtsOrganization",'Presenter', "BookingAgent","Festival", "OtherOrganization","PresenterCompany", "Venue")}, related_name = "Presenter Type", verbose_name = "Presenter",blank=True, null=True)
presenter_id = models.IntegerField(db_index=True, blank=True, null=True, verbose_name='Presenter ID')
presenter = generic.GenericForeignKey('presenter_content_type','presenter_id')
promoter_content_type = models.ForeignKey(ContentType,
limit_choices_to={"model__in": ("Individual", "ArtsOrganization","BookingAgent","Presenter", "Festival", "OtherOrganization","PresenterCompany", "Venue")}, related_name = "promotor", verbose_name='Promoter Type', blank=True, null=True)
promoter_id = models.IntegerField(db_index=True, blank=True, null=True, verbose_name='Promoter ID')
promoter = generic.GenericForeignKey('promoter_content_type','promoter_id')
agent_content_type = models.ForeignKey(ContentType,
limit_choices_to={"model__in": ("Individual", "BookingAgent")}, related_name="agent", verbose_name='Agent Type', blank=True, null=True)
agent_id = models.IntegerField(db_index=True, blank=True, null=True, verbose_name='Agent ID')
agent = generic.GenericForeignKey('agent_content_type','agent_id')
class PresenterCompany(models.Model):
name = models.CharField(max_length=70)
address =GenericRelation(Address)
presented_gig = GenericRelation('Gig',
content_type_field='presenter_content_type',
object_id_field='presenter_id',
related_name='presenter_presented_gig'
)
promoted_gig = GenericRelation('Gig',
content_type_field='promoter_content_type',
object_id_field='promoter_id',
related_name='presenter_promoted_gig'
)
booked_gig = GenericRelation('Gig',
content_type_field='promoter_content_type',
object_id_field='promoter_id',
related_name='presenter_booked_gig'
)
The main issue is that when I try to get all of the gigs for a presenter company, I have to write three different for loops for each role i.e. {% for gig in presentercompany.presented_gig.all %}, and so on... This seems like redundant code.
Is there a better way to structure this such as using intermediary models for presenter, promoter, and agent? Thanks for your advice!
Generic relationships can definitely be hard to deal with. I would only use them when there is no other option.
In your case, I see a couple other options. You could have a ManyToMany relationship between PresenterCompany and Gig using a through table to specify the type of relationship (https://docs.djangoproject.com/en/2.0/topics/db/models/#extra-fields-on-many-to-many-relationships):
class Gig(models.Model):
description = models.CharField(max_length=100, blank=True)
date = models.DateTimeField()
venue = models.ForeignKey(Venue)
festival = models.ForeignKey(Festival, blank=True, null=True)
musician = models.ManyToManyField(Musician, blank=True)
ensembles = models.ManyToManyField(Ensemble, blank=True)
class PresenterCompanyGigRelationship(models.Model):
gig = models.ForeignKey(Gig, on_delete=models.CASCADE)
presenter_company = models.ForeignKey(
'PresenterCompany', on_delete=models.CASCADE)
relationship = models.CharField(
max_length=10,
choices=(
('presenter', 'Presenter'),
('promoter', 'Promoter'),
('agent', 'Agent'),
))
class PresenterCompany(models.Model):
name = models.CharField(max_length=70)
git = models.ManyToManyField(Gig, through=PresenterCompanyGigRelationship)