Django query get objects that are not in other object - python

I have two Django models: Match and MatchRegister. I want to get list of all Matches that are not in MatchRegister object but I'm unable to do so. Could you please help me achieve it?
Below my two classes
class Match(models.Model):
"""Model representing Match object"""
match_number = models.CharField(
max_length=10
)
home_team = models.ForeignKey(
Team,
on_delete=models.SET_NULL,
null=True,
related_name='home_team'
)
away_team = models.ForeignKey(
Team,
on_delete=models.SET_NULL,
null=True,
related_name='away_team'
)
match_category = models.ForeignKey(
MatchCategory,
on_delete=models.SET_NULL,
null=True
)
date_time = models.DateTimeField(
default=timezone.now
)
notes = models.TextField(
max_length=1000,
blank=True
)
last_update = models.DateTimeField(
auto_now=timezone.now
)
class MatchRegister(models.Model):
match = models.ForeignKey(
Match,
on_delete=models.SET_NULL,
null=True
)

You can use the __isnull filter with the correct related_query_name (which defaults to the lower case model name):
Match.objects.filter(matchregister__isnull=True)

You could take list of all the matches connected with a match register and then exclude it from the matches altogether, like this:
all_match_registers = MatchRegister.objects.all()
ids_to_exclude = []
for match_register in all_match_registers:
ids_to_exclude.append(match_register.match.id)
Match.objects.exclude(id__in = ids_to_exclude)

Related

How to select multiple items with multiple quantities in django rest framework?

Models.py
class BaseModel(models.Model):
branch = models.ForeignKey(Branch, on_delete=models.PROTECT, blank=True, null=True)
company = models.ForeignKey(
Company, on_delete=models.PROTECT, blank=True, null=True
)
class Meta:
abstract = True
class MealMenu(BaseModel):
employee = models.ForeignKey(
Employee, on_delete=models.PROTECT, null=True, blank=True
)
item_name = models.CharField(max_length=50, null=True, blank=True)
quantity = models.PositiveIntegerField()
price = models.FloatField()
def __str__(self):
return f"{self.item_name} {self.price}"
class MealOrder(BaseModel):
RECEIVED = "Received"
PENDING = "Pending"
REJECTED = "Rejected"
MEAL_CHOICES = (
("Breakfast", "Breakfast"),
("Lunch", "Lunch"),
("Dinner", "Dinner"),
)
STATUS_CHOICES = (
(RECEIVED, "Received"),
(PENDING, "Pending"),
(REJECTED, "Rejected"),
)
id = models.UUIDField(primary_key=True, default=uuid.uuid4, null=False)
total_items = models.IntegerField(null=True, default=0)
total_amounts = models.FloatField(default=0.0)
menu = models.ForeignKey(MealMenu, on_delete=models.PROTECT)
quantity = models.PositiveIntegerField(default=1, blank=False)
meal_time = models.CharField(max_length=25, choices=MEAL_CHOICES)
employee = models.ForeignKey(Employee, on_delete=models.PROTECT)
date = models.DateField(auto_now=True)
status = models.CharField(max_length=25, choices=STATUS_CHOICES, default=PENDING)
I have two models. In First Model i have created a menu item_name,price and quantity.
In MealOrder i have foreign key MealMenu Model and created quantity field separately.
I want to select multiple items with their multiple quantities. But i can't understand the scenario.
So you could have a separate model to handle the quantity for different items in an order.
Like this:
class MealOrderItem(BaseModel):
order = models.ForeignKey(
MealOrder, on_delete=models.PROTECT, null=True, blank=True
)
quantity = models.PositiveIntegerField()
meal = ForeignKey(
MealMenu, on_delete=models.PROTECT, null=True, blank=True
)
This will help you create multiple meal menu selections for an order with each having its own quantity.

Django: Filtering via SQL, not Python

I created the following context variables context["genders"] and context["ages"].
Currently, there is a lot of work done by Python under #Filtering, while I think it would be better done in #Query.
However, that's where I currently struggle. Do you have an idea on how to achieve the pre-filtering in the #Query section via SQL?
Please not the int(answer_obj.answer) as answer is a TextField.
# Query
responses = Response.objects.filter(
survey__event=12, survey__template=settings.SURVEY_POST_EVENT
).order_by("-created")
# Filtering
filtered_responses = []
for response in responses:
for answer_obj in response.answers.all():
if (
answer_obj.question.focus == QuestionFocus.RECOMMENDATION_TO_FRIENDS
and int(answer_obj.answer) >= 8
):
filtered_responses.append(response)
# Context
gender_list = []
age_list = []
for response in filtered_responses:
for answer_obj in response.answers.all():
# Here a list of all the genders that gave that answer:
if answer_obj.question.focus == QuestionFocus.GENDER:
gender_list.append(answer_obj.answer)
# Here a list of all the ages that gave that answer:
if answer_obj.question.focus == QuestionFocus.AGE:
age_list.append(answer_obj.answer)
context["genders"] = gender_list
context["ages"] = age_list
models.py
class Answer(TimeStampedModel):
question = models.ForeignKey(
"surveys.Question", on_delete=models.CASCADE, related_name="answers"
)
response = models.ForeignKey(
"Response", on_delete=models.CASCADE, related_name="answers"
)
answer = models.TextField(verbose_name=_("Answer"))
choices = models.ManyToManyField(
"surveys.AnswerOption", related_name="answers", blank=True
)
class Response(TimeStampedModel):
class Language(Choices):
CHOICES = settings.LANGUAGES
survey = models.ForeignKey(
"surveys.Survey", on_delete=models.CASCADE, related_name="responses"
)
order = models.ForeignKey(
"orders.Order",
on_delete=models.SET_NULL,
null=True,
blank=True,
related_name="response",
)
attendee = models.ForeignKey(
"attendees.Attendee",
on_delete=models.SET_NULL,
null=True,
blank=True,
related_name="response",
)
total_time = models.PositiveIntegerField(
null=True, blank=True, verbose_name=_("Total time")
)
ip_address = models.GenericIPAddressField(null=True, verbose_name=_("IP Address"))
language = models.CharField(
max_length=Language.get_max_length(),
choices=Language.CHOICES,
verbose_name=_("Language"),
)
class Question(TimeStampedModel):
survey = models.ForeignKey(
"surveys.Survey", on_delete=models.CASCADE, related_name="questions"
)
question_set = models.ForeignKey(
"QuestionSet", on_delete=models.CASCADE, related_name="questions"
)
title = models.CharField(max_length=100, verbose_name=_("Title"))
help_text = models.TextField(null=True, blank=True, verbose_name=_("Help text"))
type = models.CharField(
max_length=QuestionType.get_max_length(),
choices=QuestionType.CHOICES,
verbose_name=_("Question type"),
)
focus = models.CharField(
max_length=QuestionFocus.get_max_length(),
choices=QuestionFocus.CHOICES,
verbose_name=_("Question focus"),
)
required = models.BooleanField(default=False, verbose_name=_("Is required?"))
position = models.PositiveSmallIntegerField(
null=True, blank=True, verbose_name=_("Position")
)
# Translatable fields
i18n = TranslationField(fields=("title", "help_text"))
class Meta:
ordering = ("position", "pk")
Filtering
It looks to me, that you want all responses, where answer is higher than eight for question focused on friend recommendation. Is it expected that you might have the same response appended to the filtered responses more than once, or will there be only one question of this type? I think you could rewrite it as follows:
filtered_response = responses.filter(
answers__question__focus=QuestionFocus.RECOMMENDATION_TO_FRIENDS
).annotate(
answer_num=Cast("answers__answer", IntegerField()),
).filter(
answer_num__gt=8,
)
And populating the context:
context["genders"] = Answer.objects.filter(
response_id__in=filtered_response.values_list("id", flat=True),
question__focus=QuestionFocus.GENDER,
).values_list("answer", flat=True)
context["ages"] = Answer.objects.filter(
response_id__in=filtered_response.values_list("id", flat=True),
question__focus=QuestionFocus.AGE,
).values_list("answer", flat=True)
This should allow you to avoid firing the queries to iterate over response.answers.all(), and hopefully achieve the same result.

How to create two choices fields by using foreign key from another model?

I want to create a model which will hold the routes between two places, but I don't know how to handle choices fields in this model, also my choices should hold only places (village, city, and town)
my Place model:
class Place(CoreModel):
TOWN = 'town'
CITY = 'city'
REGION = 'region'
DISTRICT = 'district'
VILLAGE = 'village'
ROLE_CHOICES = (
(REGION, 'область'),
(CITY, 'місто'),
(DISTRICT, 'район'),
(TOWN, 'село міського типу'),
(VILLAGE, 'село')
)
name = models.CharField(max_length=128, verbose_name='Place name', )
slug = models.SlugField(max_length=128, blank=True, null=True)
parent = models.ForeignKey('self', on_delete=models.CASCADE, blank=True, null=True)
role = models.CharField(max_length=20, choices=ROLE_CHOICES, null=True, blank=True)
my Route model:
class Routes(CoreModel):
start_point = models.ForeignKey(Place, on_delete=models.CASCADE)
end_point = models.ForeignKey(Place, on_delete=models.CASCADE)
but it doesn't work
When you have a model with two ForeignKeys to the same model, you must give at least one of them a related_name otherwise django doesn't know how to differentiate them in the reverse relationship:
class Routes(CoreModel):
start_point = models.ForeignKey(Place, on_delete=models.CASCADE, related_name="departing_routes")
end_point = models.ForeignKey(Place, on_delete=models.CASCADE, related_name="arriving_routes")

Django: Suggestion for models design

I need help with creating models for my simple Django app.
The purpose of the application is to let users (referees) register for matches, then admin will choose 2 users (referees) from the list of registered for given match. Right now my Matches model looks like below:
class Match(models.Model):
match_number = models.CharField(
max_length=10
)
home_team = models.ForeignKey(
Team,
on_delete=models.SET_NULL,
null=True,
related_name='home_team'
)
away_team = models.ForeignKey(
Team,
on_delete=models.SET_NULL,
null=True,
related_name='away_team'
)
match_category = models.ForeignKey(
MatchCategory,
on_delete=models.SET_NULL,
null=True
)
date_time = models.DateTimeField(
default=timezone.now
)
notes = models.TextField(
max_length=1000,
blank=True
)
What I thought to do is to create new Model named MatchRegister where I will be saving match_id and user_id, something like below:
class MatchRegister(models.Model):
match_id = models.ForeignKey(
Match
)
user_id = models.ForeignKey(
Users
)
And than admin will have list of registered user for given match from which he will choose two, so I thought to modify my Match model like this (add two new Fields):
class Match(models.Model):
match_number = models.CharField(
max_length=10
)
home_team = models.ForeignKey(
Team,
on_delete=models.SET_NULL,
null=True,
related_name='home_team'
)
away_team = models.ForeignKey(
Team,
on_delete=models.SET_NULL,
null=True,
related_name='away_team'
)
match_category = models.ForeignKey(
MatchCategory,
on_delete=models.SET_NULL,
null=True
)
date_time = models.DateTimeField(
default=timezone.now
)
notes = models.TextField(
max_length=1000,
blank=True
)
ref_a = models.ForeignKey(
Users,
on_delete=models.SET_NULL,
null=True,
related_name='ref_a'
)
ref_b = models.ForeignKey(
Users,
on_delete=models.SET_NULL,
null=True,
related_name='ref_b'
)
This is my solution but I don't know if it is done in proper way so I want to ask you for help.
If you know for certain that matches will only ever have two refs, then what you propose is just fine. However, if there's an opportunity in the future for the number to change (only one, or perhaps three), an alternative would be to add a flag to the intermediate table:
class MatchRegister(models.Model):
match_id = models.ForeignKey(Match)
user_id = models.ForeignKey(Users)
chosen = models.BooleanField(default=False)
You would need business logic to constrain the number of "chosen" refs to the number you anticipate. This option makes it easy to increase or decrease the number of refs without adding or removing columns (just change the business logic).

Django admin - Foreign key to display its values (not inlines)

earlier this week, I asked this question about having foreign keys in your main model from your subclasses: Django Form With Foreign Key
I used the answer given to make a model and sub-models (code at the end). My question is, I know about admin inlines for foreign keys, but I can't use that since the main model has the foreign key to the subclasses, not the other way around. I want the foreign keys in my main class to be displayed in the admin.
Sorry it that sounds confusing, here's my model:
Subclass 1 PreObservation
class PreObservation( models.Model ):
pre_observation = models.CharField(
max_length=255,
choices=OBS_STANDARD_TYPES,
verbose_name="Pre-Observation Standard"
)
obs__meter_reading = models.FloatField( blank=True, null=True )
obs_if_other = models.FloatField( blank=True, null=True )
Subclass 2 FieldObservation
class FieldObservation( models.Model ):
site_id = models.CharField( max_length=255, choices=STATION_CHOICES )
site_name = models.CharField( max_length=255 )
stage_reading = models.FloatField( )
specific_conductance = models.FloatField( )
water_temp = models.FloatField( )
Main class Record
class Record( models.Model ):
observers = models.CharField( max_length=255, verbose_name="Name of Observer(s)")
pre_observation_standard_1 = models.ForeignKey(
PreObservation,
related_name="pre_observation_1"
)
pre_observation_standard_2 = models.ForeignKey(
PreObservation,
related_name="pre_observation_2",
blank=True, null=True
)
field_observation_1 = models.ForeignKey(
FieldObservation,
related_name="field_observation_1"
)
field_observation_2 = models.ForeignKey(
FieldObservation,
related_name="field_observation_2",
blank=True, null=True
)
cloud_coverage = models.CharField( max_length=255, choices=CLOUD_COVERAGE )
rain_past_three_days = models.BooleanField( verbose_name="Rain in Past 3 Days" )
snow = models.BooleanField( )
snow_melt = models.FloatField( )
temperature = models.CharField( max_length=255, choices=TEMPERATURE )
wind = models.CharField( max_length=255, choices=WIND )
field_notes = models.TextField( )
teachers_comments = models.TextField( )
user = models.ForeignKey( User )
group_name = models.CharField( max_length=255, blank=True )
You can use
class RecordAdmin(admin.ModelAdmin):
list_display = ('pre_observation__pre_observation_standard_1',
'pre_observation__pre_observation_standard_2', )
admin.site.register(Record, RecordAdmin)

Categories

Resources