Django link multiple table - django

I have four models as follows:
class deals_view(models.Model):
deal = models.ForeignKey(dealsModel, on_delete=models.CASCADE, related_name='deal_view')
client = models.ForeignKey(client_profileModel, on_delete=models.CASCADE)
client_ip = models.GenericIPAddressField(protocol='both')
date_added = models.DateField(auto_now_add=True)
class client_profile(models.Model):
GENDER_NAME = (
('M', 'Male'),
('F', 'Female'),
('O', 'Others')
)
user = models.ForeignKey(User, unique=True, on_delete=models.CASCADE)
gender = models.CharField(max_length=1, choices=GENDER_NAME, null=True)
address = models.CharField(max_length=100, null=True)
dob = models.DateField(null=True)
class deals(models.Model):
GENDER_NAME = (
('M', 'Male'),
('F', 'Female'),
('O', 'Others'),
('A', 'All'),
)
AGE_RANGE = (
('A1', '18-25'),
('A2', '25-40'),
('A3', '40-55'),
('A4', '55-100'),
('A5', '18-100'),
('AL', '13-100'),
('T1', '13-18')
)
store = models.ForeignKey(storesModel, on_delete=models.CASCADE, related_name='deals_store')
title = models.CharField(max_length=30)
description = models.CharField(max_length=160)
price = models.DecimalField(max_digits=6, decimal_places=2)
category = models.ForeignKey(categoriesModel, on_delete=models.PROTECT)
targeted_gender = models.CharField(max_length=1, choices=GENDER_NAME)
targeted_age = models.CharField(max_length=2, choices=AGE_RANGE)
is_active = models.BooleanField(default=False)
created_date = models.DateField(auto_now_add=True)
expiry_date = models.DateField(default=(dt.now() + td(days=30)))
class stores(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
name = models.CharField(max_length=50, unique=True)
about = models.CharField(max_length=300)
company_name = models.CharField(max_length=100)
I want to list all deals for the current month and its corresponding number of views per gender.
so far I've tried the following; i can get all the info but it seems i have multiple hits of the database:
self.storeObj = storesModel.objects.prefetch_related('deals_store').get(id=storeid)
self.deals_store = self.storeObj.deals_store
segmentedInfo = self.deals_store.all().prefetch_related('deal_view').filter(deal_view__date_added__range=((datetime.today() - timedelta(days=30)), datetime.now())).distinct()
for seg in segmentedInfo:
for x in seg.deal_view.select_related('client').distinct():
print(x.client.gender)
Is there any way i can optimise my queries to get the number of views per gender for a deal of a specific store?

Yes, we can do some filtering in the related client_profile model, and then use a .annotate(..) to count the number of distinct ids.
from django.db.models import Count
client_profile.objects.filter(
deals_view__deal__store_id=storeid,
deals_view__date_added__range=(datetime.today()-timedelta(days=30), datetime.now())
).values('gender').annotate(
n=Count('id', distinct=True)
).order_by('gender')
This will result in a QuerySet that contains dictionaries with the gender, and the number of client_profiles, like:
<QuerySet [
{'gender': 'M', 'n': 1425},
{'gender': 'M', 'n': 1302},
{'gender': 'O', 'n': 173}
]>
If there are no client_profiles with a given gender that have seen the deal, then it is not part of the QuerySet.

Related

Getting Count Result With Multiple Conditions

I have models named Class, StudentList, Child, TakingQuiz and TakingQuizAnswer. Students can take exams. In this case, when they start the exam, data is added to the 'TakingQuiz' table. With each new answer, the answers are also recorded in the TakingQuizAnswer table.
The result I want to reach -> The question with the most mistakes in the exams solved by the students in a class.
I tried to use Count for this. I'm filtering answer_is_correct to False but that is insufficient. I also need to filter this data for the question column. So I need to get rows where both question and answer_is_correct = False columns are the same and return the first few most repetitive data as results.
I always get a general result in my experiments. I can't include rows where the question column is the same. How can I access the questions with the most mistakes in exams solved by students studying in a class?
Serializer
class ClassSerializerReport(ModelSerializer):
instructor = InstructorSerializerReport(source="instructor.user")
students = StudenListSerializerReport(many=True,
source="student_list_class")
max_incorrect_question = serializers.SerializerMethodField()
class Meta:
model = Class
exclude = [
"created_at",
"updated_at",
"school",
]
def get_max_incorrect_question(self, obj):
data = Class.objects.filter(id = obj.id).values('student_list_class__child__child_taking_quiz__taking_quizes').annotate(res = Count('student_list_class__child__child_taking_quiz__taking_quizes__question', filter = Q(student_list_class__child__child_taking_quiz__taking_quizes__answer_is_correct = False)))
print(data)
return {"question_id" : "I couldn't access that result yet."}
Related Models
class Class(AbstractSchoolBaseModel):
school = models.ForeignKey(
"school.School",
on_delete=models.CASCADE,
related_name="classes_school",
)
instructor = models.ForeignKey(
"account.InstructorProfile",
on_delete=models.CASCADE,
related_name="instructors_school",
)
name = models.CharField(
max_length=50,
)
grade = models.IntegerField(
)
class StudentList(AbstractSchoolBaseModel):
school_class = models.ForeignKey(
"school.Class",
on_delete=models.CASCADE,
related_name="student_list_class",
)
child = models.ForeignKey(
"account.ChildProfile",
on_delete=models.CASCADE,
related_name="student_list_children",
)
class ChildProfile(models.Model):
user = models.OneToOneField(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
primary_key=True,
related_name="user_child")
city = models.ForeignKey(
"country.City",
on_delete=models.SET_NULL,
null=True,
blank=True,
related_name="city_child_profiles")
hobbies = models.CharField(
max_length=500,
null=True,
blank=True,
)
class TakingQuiz(AbstractQuizBaseModel):
quiz = models.ForeignKey("quiz.Quiz", on_delete=models.DO_NOTHING, related_name="quiz_taking_quiz")
child = models.ForeignKey("account.ChildProfile", on_delete=models.CASCADE, related_name = "child_taking_quiz")
title = models.CharField(max_length=150, editable=False, default="-")
total_point = models.PositiveIntegerField(default=0)
class TakingQuizAnswer(AbstractQuizBaseModel):
taking_quiz = models.ForeignKey("quiz.TakingQuiz", on_delete=models.CASCADE, related_name="taking_quizes")
question = models.ForeignKey("quiz.Question", on_delete=models.DO_NOTHING, related_name="question_taking_quiz"e)
answer = models.ForeignKey("quiz.Answer", on_delete= models.DO_NOTHING, related_name="answer_taking_quiz")
taking_quiz_title = models.TextField(editable=False, null=True, blank=True)
question_text = models.TextField(editable=False, null=True, blank=True)
question_topic_content = models.TextField(editable=False, null=True, blank=True)
answer_text = models.TextField(editable=False, null=True, blank=True)
answer_is_correct = models.BooleanField(editable=False, null=True, blank=True)
class Quiz(AbstractQuizBaseModel):
ENABLED_CHOICES = (
(True, _("Active")),
(False, _("Not Active")),
)
book = models.ForeignKey("book.Book", on_delete= models.CASCADE, related_name="book_quiz")
title = models.CharField(max_length=150)
enabled = models.BooleanField(choices=ENABLED_CHOICES, default=False)
class Question(AbstractQuizBaseModel):
quiz = models.ForeignKey("quiz.Quiz", on_delete=models.DO_NOTHING, related_name="question_quiz")
question = models.CharField(max_length=500)
topic = models.CharField(max_length=500)
class Answer(AbstractQuizBaseModel):
IS_CORRECT_CHOICES = (
(True, _("Correct Answer")),
(False, _("Wrong Answer"))
)
question = models.ForeignKey("quiz.Question", on_delete=models.CASCADE, related_name = "question_answer")
answer = models.CharField(max_length=500)
is_correct = models.BooleanField(choices=IS_CORRECT_CHOICES, default=False)

How to create an object of model A out of 2 random objects of model B in Django?

I'm trying to create an app that meets two random users in Django.
my question is how to create an object Meeting out of 2 random users from my User model,
I want something like a for loop so that every 2 users in my database have a meeting!
ps: I have only one day left to submit my work I will be so thankful if u help me
this is my code so far:
def createMeeting():
user_p = get_user_model()
users = user_p.objects.all()
all_users = users.exclude(username="Admin")
n = all_users.count()
for k in range(math.floor(n/2)):
for user in all_users:
freedate = FreeDate.objects.filter(user=user)
starreds = user.userprofile.desired_user.all()
matched_user = User
if freedate:
if starreds:
for u in starreds:
u_freedate = FreeDate.objects.filter(user=u.user)
for dates in freedate:
for matchdates in u_freedate:
if dates.FreeTime == matchdates.FreeTime and dates.FreeDay == matchdates.FreeDay:
matched_user = u.user
else:
for u in users:
u_freedate = FreeDate.objects.filter(user = u)
for dates in freedate:
for matchdates in u_freedate:
if dates.FreeTime == matchdates.FreeTime and dates.FreeDay == matchdates.FreeDay:
matched_user = u
if matched_user and matched_user != user and not(Meeting.objects.filter(user1=user, user2=matched_user) | Meeting.objects.filter(user1=matched_user, user2=user)):
Meeting.objects.create(user1=user, user2=matched_user)`
it creates only one Meeting object and i'm getting this error:
TypeError: Field 'id' expected a number but got <class 'django.contrib.auth.models.User'>.
This is my models.py :
class UserProfile(models.Model):
GENDER=(
('Female','Female'),
('Male','Male'),
('Others', 'Others'),
)
user = models.OneToOneField(User, null=True, on_delete=models.CASCADE)
birthdate = models.DateTimeField(default=timezone.now, null=True)
phone = models.CharField(max_length=200, null=True)
age = models.IntegerField(null=True, default=18)
years_of_experience = models.IntegerField(null=True, default=5)
job_title = models.CharField(max_length=200, null=True)
gender = models.CharField(max_length=200, null=True, choices=GENDER)
profile_image = models.ImageField(null=True, blank=True)
about = models.TextField(null=True)
desired_user = models.ManyToManyField("self")
skill = models.ManyToManyField("Skill")
`class Meeting(models.Model):
STATE_CHOICES = [
('Accepte', 'Accepte'),
('Deny', 'Deny'),
]
RATE_MEETING = [
(1, '1'),
(2, '2'),
(3, '3'),
(4, '4'),
(5, '5'),
]
user1 = models.ForeignKey(User, on_delete=models.CASCADE, related_name='user1', null=True)
user2 = models.ForeignKey(User, on_delete=models.CASCADE, related_name='user2', null=True)
state1 = models.CharField(max_length=200, null=True, choices=STATE_CHOICES)
state2 = models.CharField(max_length=200, null=True, choices=STATE_CHOICES)
text1 = models.TextField(max_length=3000, null=True, blank=True)
text2 = models.TextField(max_length=3000, null=True, blank=True)
rate1 = models.PositiveSmallIntegerField(choices=RATE_MEETING, null=True, blank=True)
rate2 = models.PositiveSmallIntegerField(choices=RATE_MEETING, null=True, blank=True)
meeeting_place = models.ForeignKey(MeetingPlace, on_delete=models.CASCADE, null=True)`
I can't decipher what you're doing there, but:
for k in range(math.floor(n/2)):
for user in all_users:
freedate = FreeDate.objects.filter(user=user)
starreds = user.userprofile.desired_user.all()
matched_user = User # this is the line that's causing the error. Need an User instance, not the User class.
if freedate:

Django ManyToManyField inline list values

I have two Django models related by a ManyToManyField relationship. Everything works fine except for the inline add dropdown which lists ugly automatically created object names instead of allowing me to format it. How can I specify that?
Models:
class Job(models.Model):
type = models.CharField(max_length=32, choices=JobChoices)
guid = models.CharField(max_length=32)
title = models.CharField(max_length=256)
started_time = models.DateTimeField()
ended_time = models.DateTimeField(blank=True, null=True)
enabled = models.BooleanField(default=False)
running = models.BooleanField(default=False)
working_job_status = models.CharField(max_length=32, choices=StatusCoices)
working_job_length = models.IntegerField(blank=True, null=True)
working_job_progress = models.IntegerField(blank=True, null=True)
working_job_eta_sec = models.IntegerField(blank=True, null=True)
RepeatUnit = (
('s', 'Second'),
('m', 'Minute'),
('h', 'Hour'),
('d', 'Day'),
('W', 'Week'),
('M', 'Month'),
('Y', 'Year'),
)
class Schedule(models.Model):
title = models.CharField(max_length=128)
job = models.ManyToManyField(Job, blank=True, null=True)
start_time = models.DateTimeField(null=False)
end_time = models.DateTimeField(blank=True, null=True)
repeat_unit = models.CharField(blank=True, null=True, max_length=1, choices=RepeatUnit)
repeat_every = models.IntegerField(blank=True, null=True)
repeat_max_count = models.IntegerField(blank=True, null=True)
def __unicode__(self):
return f'{self.title}'
Admin:
class ScheduleAdmin(admin.ModelAdmin):
list_display = ['id', 'title', 'start_time', 'end_time', 'repeat_unit', 'repeat_every', 'repeat_max_count']
class ScheduleInline(admin.TabularInline):
model = Schedule.job.through
min_num = 0
extra = 0
# fields = ('title', )
verbose_name = "Schedule"
verbose_name_plural = "Schedules"
class JobAdmin(admin.ModelAdmin):
list_display = ['id', 'type', 'guid', 'title', 'started_time', 'ended_time', 'enabled', 'running', 'progress']
inlines = [ScheduleInline,]
admin.site.register(Schedule, ScheduleAdmin)
admin.site.register(Job, JobAdmin)
And, when I click on the inlines drop-down menu I get:
changing from __unicode__(self) to __str__(self) did the trick

I need to display summary report in Django admin site. How do I count number of users where gender status is 0 or 1

I am overriding change_list.html and here is what I have in my admin.py file.
class MyHelperGenderAdmin(admin.ModelAdmin):
change_list_template = 'admin/helper_chart_change_list.html'
date_hierarchy = 'created_at'
list_filter = ('gender', 'created_at')
def changelist_view(self, request, extra_context=None):
response = super().changelist_view(request, extra_context=extra_context, )
try:
qs = response.context_data['cl'].queryset
except (AttributeError, KeyError):
return response
metrics = {
'male': Count('gender', gender=1),
'female': Count('gender', gender=0),
'total_helpers': Count('id')
}
response.context_data['helper'] = list(
qs.values('gender').annotate(**metrics).order_by('-male')
)
return response
def has_add_permission(self, request):
return False
admin.site.register(MyHelperChart, MyHelperGenderAdmin)
In my metrics dictionary, i need a way to count where gender is either 0 or 1. Currently, The count method count everything regards of the gender status.
Here is my model:
class Helper(auth.models.User):
MALE = 1
FEMALE = 0
GENDER_CHOICES = (
(MALE, 'Male'),
(FEMALE, 'Female')
)
phone_regex = RegexValidator(regex=r'^\+?1?\d{9,15}$',
message=
"Phone number must be entered in the format: '+999999999'. Up to 15 digits allowed."
)
phone_number = models.CharField(validators=[phone_regex], max_length=15, blank=True, unique=True, null=True)
gender = models.IntegerField(choices=GENDER_CHOICES, default=MALE, null=True)
birthdate = models.DateField(blank=True, null=True)
facebook_id = models.CharField(max_length=200, blank=True, null=True)
google_id = models.CharField(max_length=200, blank=True, null=True)
lng = models.FloatField(blank=True, null=True)
lat = models.FloatField(blank=True, null=True)
country = models.ForeignKey(Country, blank=True, null=True)
image = models.ImageField(
upload_to=upload_location,
null=True, blank=True,
width_field="width_field",
height_field="height_field")
height_field = models.IntegerField(default=0)
width_field = models.IntegerField(default=0)
updated_at = models.DateTimeField(auto_now=True)
created_at = models.DateTimeField(auto_now=False, auto_now_add=True)
class Meta:
verbose_name_plural = "Helpers"
def __str__(self):
return self.first_name
class MyHelperChart(Helper):
class Meta:
proxy = True
verbose_name = 'Helper Gender Summmary'
verbose_name_plural = 'Helpers Gender Summaries'
I have created a proxy model which I will be using in my Django admin in order to display summary of data and a chart.
All you need to do is add a case to both the male and female metrics. Here's an example, and then you can do the same for female = 0:
from django.db.models import Case, When, IntegerField
class MyHelperGenderAdmin(admin.ModelAdmin):
...
metrics = {
...
'male': Count(Case(
When(gender = 1, then = 1),
output_field = IntegerField())),
...
}

Custom Django Form

I'm trying to make a custom backend for my system and I've hit a bit of a snag....I want to give users the ability to add new makes/models/series that are not already in the system via a form. I'm wondering how I'll go about this...my models look as below:
class Manufacturer(models.Model):
MANUFACTURER_POPULARITY_CHOICES = (
('1', 'Primary'),
('2', 'Secondary'),
('3', 'Tertiary'),
)
manufacturer = models.CharField(max_length=15, blank=False)
date_added = models.DateField()
manufacturer_popularity = models.CharField(max_length=1,
choices=MANUFACTURER_POPULARITY_CHOICES)
def __unicode__(self):
return self.manufacturer
class Model(models.Model):
model = models.CharField(max_length=20, blank=False)
manufacturer = models.ForeignKey(Manufacturer)
date_added = models.DateField()
def __unicode__(self):
name = ''+str(self.manufacturer)+" "+str(self.model)
return name
class Series(models.Model):
series = models.CharField(max_length=20, blank=True, null=True)
model = models.ForeignKey(Model)
date_added = models.DateField()
def __unicode__(self):
name = str(self.model)+" "+str(self.series)
return name
class Engine(models.Model):
ENGINE_TYPE_CHOICES = (
('H', 'H'),
('I', 'I'),
('R', 'R'),
('V', 'V'),
('W', 'W'),
)
FUEL_TYPE_CHOICES = (
('G', 'Gas'),
('D', 'Diesel'),
)
size = models.DecimalField(max_digits=2, decimal_places=1)
type = models.CharField(max_length=1, choices=ENGINE_TYPE_CHOICES)
cylinders = models.PositiveSmallIntegerField()
spec = models.CharField(max_length=20, blank=True, null=True)
fuel_type = models.CharField(max_length=1, choices=FUEL_TYPE_CHOICES)
class CommonVehicle(models.Model):
year = models.ForeignKey(Year)
series = models.ForeignKey(Series)
engine = models.ForeignKey(Engine)
body_style = models.ForeignKey(BodyStyle)
transmission = models.ForeignKey(Transmission)
speeds = models.PositiveSmallIntegerField()
drive_train = models.ForeignKey(DriveTrain)
horse_power = models.PositiveSmallIntegerField()
litre_100km_city = models.DecimalField(max_digits=3, decimal_places=1)
litre_100km_hwy = models.DecimalField(max_digits=3, decimal_places=1)
def __unicode__(self):
name = ''+str(self.year)+" "+str(self.series)
return name
This seems to be a fairly standard job for a django model form. I would recommend following the documentation at http://docs.djangoproject.com/en/dev/topics/forms/modelforms/. There are detailed instructions there on how to create a form from a model and then save the returned submission to the database.