I want to show all answers for question__focus=QuestionFocus.REASON_FOR_ATTENDING where question__focus=QuestionFocus.RECOMMENDATION_TO_FRIENDS is >= 9.
The answer field is not an integer field, but a TextField as all questions share the same Answer model. I tried a lot, but nothing worked for me so far.
I first tried to go from the Answer model, but that also didn't work as I filter for different answers than what I want to show at the end.
event = Event.objects.get(pk=12)
survey = event.surveys.get(
template=settings.SURVEY_POST_EVENT
).questions.[HOW TO CONTINUE?]
models.py
class Survey(TimeStampedModel):
class SurveyTemplate(Choices):
CHOICES = ((survey, survey) for survey in settings.SURVEY_TEMPLATES.keys())
id = models.UUIDField(primary_key=True, editable=False, default=uuid.uuid4)
event = models.ForeignKey(
"events.Event", on_delete=models.CASCADE, related_name="surveys"
)
is_active = models.BooleanField(default=False, verbose_name=_("Is active?"))
template = models.CharField(
max_length=SurveyTemplate.get_max_length(),
choices=SurveyTemplate.CHOICES,
verbose_name=_("Survey template"),
)
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 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 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")
)
Related
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.
I am new in web development with Django and MySQL database, I got to develop a web application with Django framework, after deployment of my project in the server.
after 2 months, I noticed that data from my order table was deleted as well as the data of one user is displayed in the profile of another,
I want to know what I must do as a test to know the PR eventual error and to stop the deletion of data in my database.
data often deleted in the order and customer table.
the ORDER model bind with a foreign key to other Model:
class Order(models.Model):
user = models.ForeignKey(User, null=True, blank=True, on_delete=models.CASCADE)
created = models.DateTimeField( auto_now_add=True, verbose_name=_('Creation Date'))
payed = models.DateTimeField( verbose_name=_('Payment Date'), default=datetime.now, null=True, blank=True)
reference = models.IntegerField( verbose_name=_('Order Reference'), default=0, null=True, blank=True )
customer = models.ForeignKey( Customers, verbose_name=_('Customer'), null=True, blank=True, on_delete=models.CASCADE )
company = models.ForeignKey( Compagnie, verbose_name=_('Company'), null=True, blank=True, on_delete=models.CASCADE )
class Customers(models.Model):
company = models.ForeignKey(
Compagnie,
verbose_name=_('Company'),
null=True,
blank=True,
on_delete=models.CASCADE
)
forename = models.CharField(
verbose_name=_('First Name'),
max_length=255,
null=True,
blank=True)
GENDER = [('M', _('Male')),
('F', _('Female'))]
gender = models.CharField(
verbose_name=_('Gender'),
max_length=1,
choices=GENDER,
null=True,
blank=True)
city = models.ForeignKey(
City,
verbose_name=_('City'),
null=True,
blank=True,
on_delete=models.CASCADE
)
additionalNum = models.CharField(
verbose_name=_('Additional Number:'),
max_length=60,
null=True,
blank=True,
)
adressCustomer = models.TextField(
verbose_name=_('Address Customer:'),
max_length=500,
null=True,
blank=True,
)
telCustomer = models.CharField(
verbose_name=_('Phone Customer:'),
max_length=30,
null=True,
blank=True,
)
emailCustomer = models.EmailField(
verbose_name=_('Email Customer:'),
null=True,
blank=True,
)
otherBuyerId = models.CharField(
verbose_name=_('Other Buyer ID:'),
max_length=50,
null=True,
blank=True
)
vatNumber = models.CharField(
max_length=120,
null=True,
verbose_name=_('Vat Number:'),
blank=True
)
needs_attention = models.BooleanField(
verbose_name=_('Needs attention'),
default=False)
biography = models.TextField(
verbose_name=_('Biography'),
null=True,
blank=True)
_is_updating_cache_fields = False
def get_name(self):
first = self.forename or ''
name = "%s" % (first)
return name.strip()
class Meta:
verbose_name = _('Customer')
verbose_name_plural = _('Customers')
def __unicode__(self):
return u'%s %s: %s' % (
type(self).__name__,
self.pk,
self.forename)
def __str__(self):
if self.forename:
return self.forename
else:
return "Unnamed"
Can someone give me an explanation for this problem?
I'm trying to export a csv with information from the model order which has a relation 1 to 1 with delivery channel and restaurant and a 1 to many relationship with orderlines. It is taking way too much time for download it (around 20 seconds for 10k lines).
This is my code:
orderlines = OrderLine.objects.select_related("product").only(
"product__display_name", "quantity", "paid_amount", "discount_amount"
)
return (
Order.objects.prefetch_related(Prefetch("orderlines", queryset=orderlines, to_attr="orderlines_list"))
.select_related("delivery_channel")
.select_related("restaurant")
)
These are my models:
class Order(TimeStampedModel, TenantModel):
id = models.AutoField
objects = OrderManager()
restaurant = models.ForeignKey(
Restaurant,
blank=False,
null=False,
on_delete=models.PROTECT,
help_text=_("References the restaurant the order is for"),
)
delivery_channel = models.ForeignKey(
DeliveryChannel,
blank=False,
null=False,
on_delete=models.PROTECT,
)
class Restaurant(TenantModel):
id = models.AutoField
name = models.CharField(max_length=255, blank=False, null=False, default="", unique=False)
class DeliveryChannel(models.Model):
id = models.AutoField
name = models.CharField(
max_length=255, blank=False, null=False, unique=True, default="",
)
class OrderLine(TimeStampedModel, TenantModel):
id = models.AutoField
order = models.ForeignKey(
Order,
blank=False,
null=False,
on_delete=models.CASCADE,
related_name="orderlines",
)
product = models.ForeignKey(
Product, blank=False, null=False, on_delete=models.CASCADE,
)
unit_price = models.DecimalField(
blank=False,
null=False,
max_digits=8,
decimal_places=2,
)
quantity = models.IntegerField(blank=False, null=False, unique=False)
paid_amount = models.DecimalField(
blank=False,
null=False,
max_digits=8,
decimal_places=2,
)
discount_amount = models.DecimalField(
blank=False,
null=False,
max_digits=8,
decimal_places=2,
help_text=_("Amount of the discount applied to the product"),
)
class Product(TenantModel):
id = models.AutoField
objects = ProductManager()
display_name = models.CharField(max_length=255, blank=False, null=False, unique=False)
I thought about using only in the end but I can't use it on orderlines as it is a 1 to many relationship. I'm stuck on how to improve the performance. Many thanks.
You can use .only(…) [Django-doc], but you need to add the foreign key to the model itself, otherwise this will result in another N+1 problem: where it will each time have to make a query to determine to what Order it belongs, so:
orderlines = OrderLine.objects.select_related('product').only(
'product__display_name',
# add ForeignKey to the Order object ↓
'quantity', 'paid_amount', 'discount_amount', 'order'
)
return Order.objects.prefetch_related(
Prefetch('orderlines', queryset=orderlines, to_attr='orderlines_list')
).select_related(
'delivery_channel'
'restaurant'
)
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.
I have these models:
class Article(TimestampedModel):
title = models.CharField(max_length=255)
slug = models.SlugField(db_index=True, max_length=255, unique=True, null=True, blank=True)
introduction = models.TextField(null=True, blank=True)
content = HTMLField('Content')
image = models.ImageField(null=True, blank=True, upload_to='articles')
parent = models.ForeignKey(
'core.Article', on_delete=models.CASCADE, related_name='sectionparent', null=True, blank=True
)
authors = models.ManyToManyField(People, blank=True)
active = models.BooleanField(default=True)
SECTIONS = (
('about', 'About'),
('newsevents', 'News and Events'),
)
section = models.CharField(max_length=20, choices=SECTIONS, default='about')
site = models.ForeignKey(Site, on_delete=models.CASCADE)
objects = models.Manager()
on_site = CurrentSiteManager()
class Event(models.Model):
article = models.OneToOneField(
Article,
on_delete=models.CASCADE,
related_name='event',
),
EVENT_TYPE = (
('match', 'Match'),
('other', 'Other'),
)
start = models.DateTimeField(null=True, blank=True);
end = models.DateTimeField(null=True, blank=True);
type = models.CharField(max_length=20, choices=EVENT_TYPE)
location = models.CharField(max_length=255, null=True, blank=True)
url = models.CharField(max_length=255, null=True, blank=True)
However, when I look at the generated events table in my database, there is no foreign key (I would have expected on). Furthermore, I have a record in Article:
article = Article.objects.find(1)
And then when I try to access the event:
event = article.event
I will get this error:
'Article' object has no attribute 'event'