I want to insert a ManyToMany fields in my db using django.I select some customers using checkboxes.
This is my models.py :
class Campaign(models.Model):
title = models.CharField(max_length=255)
channel = models.CharField(max_length=255)
start_date = models.DateField()
end_date = models.DateField()
target_prospect = models.ManyToManyField(ProspectClient,related_name='campaigns_prospect')
target_partner = models.ManyToManyField(PartnerClient,related_name='campaigns_partners')
I try the code below in my views.py but didn't work :
def campaigns_page(request):
if request.user.is_authenticated:
if request.user.profile == 'D' or request.user.profile == 'E' or request.user.is_superuser:
campaigns = Campaign.objects.all()
prospects = ProspectClient.objects.all()
partners = PartnerClient.objects.exclude(id__in=PartnerClient.objects.values('id')).all()
context = {
'campaigns':campaigns,
'prospects':prospects,
'partners':partners
}
if request.method == 'POST':
title = request.POST['title']
channel = request.POST['channel']
start_date = request.POST['start_date']
end_date = request.POST['end_date']
descriptions = request.POST['goals'].split(",")
targets = request.POST['targets']
campaign = Campaign.objects.create(title=title,channel=channel,start_date=start_date,end_date=end_date)
for description in descriptions:
goal = Goal.objects.create(description=description)
goal.campaign.add(campaign)
for target in targets:
prospects.campaign.add(campaign)
partners.campaign.add(campaign)
return render(request,'CampaignManagement/campaigns_page.html',context)
return render(request, 'Login/logout.html')
If I delete the part of tergets it works.
But with this part it gives me This error : 'QuerySet' object has no attribute 'campaign'
How I can solve this ?
I see a couple of errors. Perhaps one or more are leading to the problem.
One
Try printing this:
partners = PartnerClient.objects.exclude(id__in=PartnerClient.objects.values('id')).all()
print(partners)
I suspect it will print None since you are excluding all id's in PartnerClient.objects.values('id'). On another note you don't need the all() since exclude() will return all the results you are looking for.
Two
In the line for target in targets: what exactly are you iterating through? targets = request.POST['targets'] is just giving you a string, so it would iterate through each letter. Perhaps you meant:
targets = request.POST['targets'].split(", ")
like you did for descriptions? Or perhaps you are getting a list of items from your form, in which case you can use:
targets = request.POST.getlist('targets')
In my django app I am creating Barcodes with a combination of str and id of model and id of product.
The barcode is generated but the problem that I am encountering is when I scan the barcode I want to show the information of the product scanned.
I'll be able to understand the problem with code in a better way
Models.py
class GrnItems(models.Model):
item = models.ForeignKey(Product, on_delete=models.CASCADE)
item_quantity = models.IntegerField(default=0)
item_price = models.IntegerField(default=0)
label_name = models.CharField(max_length=25, blank=True, null=True)
class Grn(models.Model):
owner = models.ForeignKey(User, on_delete=models.CASCADE)
reference_no = models.CharField(max_length=500, default=0)
items = models.ManyToManyField(GrnItems)
Views.py
def PrintGRNsv1(request, pk):
grn = Grn.objects.filter(pk=pk)[0]
grn_prod = grn.items.all()
print("grn prod", grn_prod)
items = []
for i in grn_prod:
for j in range(i.item_quantity):
items.append({'bar': "YNT9299" + str(pk) +
str(i.item.pk) + str(j + 1)} )
Now let's suppose I generated a Barcode YNT92991231, Now I have no idea how to get the i.item.pk from this code
How can I do this ?
P.s.
Okay the cherry on top is that I have created the Barcodes for a large number of products and they are already placed on them, so can't really change the barcode format at this point
For now when we can't change anything. Generate all the barcodes for you GRN. Save them in files or in DB. Whenever there is a query that matches those just find them from there. If there is any conflict (when 2 or more product has the same barcode) Django USER can be one way to resolve the conflict.
For new barcodes change the generator function. Use delimiter or fixed-width characters (for pk).
ex: YNT9299GGGGGPPPPPCCCCC where G => GRN pk, P => Product pk, C => Count. Or with delimiters YNT9299G1P23C2.
Yep, the solution is not a foolproof solution is just a workaround for the mess created.
class Edge(BaseInfo):
source = models.ForeignKey('Node', on_delete=models.CASCADE,related_name="is_source")
target = models.ForeignKey('Node', on_delete=models.CASCADE,related_name="is_target")
def __str__(self):
return '%s' % (self.label)
class Meta:
unique_together = ('source','target','label','notes')
class Node(BaseInfo):
item_type_list = [('profile','Profile'),
('page','Page'),
('group','Group'),
('post','Post'),
('phone','Phone'),
('website','Website'),
('email','Email'),
('varia','Varia')
]
item_type = models.CharField(max_length=200,choices=item_type_list,blank = True,null=True)
firstname = models.CharField(max_length=200,blank = True, null=True)
lastname = models.CharField(max_length=200,blank = True,null=True)
identified = models.BooleanField(blank=True,null=True,default=False)
username = models.CharField(max_length=200, blank=True, null=True)
uid = models.CharField(max_length=200,blank=True,null=True)
url = models.CharField(max_length=2000,blank=True,null=True)
edges = models.ManyToManyField('self', through='Edge',blank = True)
I have a Model Node (in this case a soc media profile - item_type) that has relations with other nodes (in this case a post). A profile can be the author of a post. An other profile can like or comment that post.
Question : what is the most efficient way to get all the distinct profiles that liked or commented on anothes profile's post + the count of these likes /comments.
print(Edge.objects.filter(Q(label="Liked")|Q(label="Commented"),q).values("source").annotate(c=Count('source')))
Gets me somewhere but i have the values then (id) and i want to pass the objects to my template rather then .get() all the profiles again...
Result :
Thanks in advance
I ended up with iterating over the queryset and adding the objects that i wanted in a dictionary , if the object was already in dictionary , i would count +1 and add the relation in a nested list.
This doesnt feel right but works for now.
posts = Edge.objects.filter(source = self,target__item_type='post',label='Author')
if posts:
q = Q()
for post in posts:
q = q | Q(target=post.target)
contributors = Edge.objects.filter(Q(label="Liked")|Q(label="Commented"),q)
if contributors:
for i in contributors:
if i.source.uid in results:
if i.label in results[i.source.uid]['relation']:
pass
else:
results[i.source.uid]["relation"].append(i.label)
if 'post' in results[i.source.uid]:
results[i.source.uid]['post'].append(i.target)
else:
results[i.source.uid]['post']=[i.target]
else:
results[i.source.uid] = {'profile' : i.source , 'relation':[i.label],'post':[i.target]}
I have a users table which has 3 types of users Student, Faculty and Club and I have a university table.
What I want is how many users are there in the specific university.
I am getting my desired output but the output is very slow.I have 90k users and the output it is generating it takes minutes to produce results.
My user model:-
from __future__ import unicode_literals
from django.db import models
from django.contrib.auth.models import User
from cms.models.masterUserTypes import MasterUserTypes
from cms.models.universities import Universities
from cms.models.departments import MasterDepartments
# WE ARE AT MODELS/APPUSERS
requestChoice = (
('male', 'male'),
('female', 'female'),
)
class Users(models.Model):
id = models.IntegerField(db_column="id", max_length=11, help_text="")
userTypeId = models.ForeignKey(MasterUserTypes, db_column="userTypeId")
universityId = models.ForeignKey(Universities, db_column="universityId")
departmentId = models.ForeignKey(MasterDepartments , db_column="departmentId",help_text="")
name = models.CharField(db_column="name",max_length=255,help_text="")
username = models.CharField(db_column="username",unique=True, max_length=255,help_text="")
email = models.CharField(db_column="email",unique=True, max_length=255,help_text="")
password = models.CharField(db_column="password",max_length=255,help_text="")
bio = models.TextField(db_column="bio",max_length=500,help_text="")
gender = models.CharField(db_column="gender",max_length=6, choices=requestChoice,help_text="")
mobileNo = models.CharField(db_column='mobileNo', max_length=16,help_text="")
dob = models.DateField(db_column="dob",help_text="")
major = models.CharField(db_column="major",max_length=255,help_text="")
graduationYear = models.IntegerField(db_column='graduationYear',max_length=11,help_text="")
canAddNews = models.BooleanField(db_column='canAddNews',default=False,help_text="")
receivePrivateMsgNotification = models.BooleanField(db_column='receivePrivateMsgNotification',default=True ,help_text="")
receivePrivateMsg = models.BooleanField(db_column='receivePrivateMsg',default=True ,help_text="")
receiveCommentNotification = models.BooleanField(db_column='receiveCommentNotification',default=True ,help_text="")
receiveLikeNotification = models.BooleanField(db_column='receiveLikeNotification',default=True ,help_text="")
receiveFavoriteFollowNotification = models.BooleanField(db_column='receiveFavoriteFollowNotification',default=True ,help_text="")
receiveNewPostNotification = models.BooleanField(db_column='receiveNewPostNotification',default=True ,help_text="")
allowInPopularList = models.BooleanField(db_column='allowInPopularList',default=True ,help_text="")
xmppResponse = models.TextField(db_column='xmppResponse',help_text="")
xmppDatetime = models.DateTimeField(db_column='xmppDatetime', help_text="")
status = models.BooleanField(db_column="status", default=False, help_text="")
deactivatedByAdmin = models.BooleanField(db_column="deactivatedByAdmin", default=False, help_text="")
createdAt = models.DateTimeField(db_column='createdAt', auto_now=True, help_text="")
modifiedAt = models.DateTimeField(db_column='modifiedAt', auto_now=True, help_text="")
updatedBy = models.ForeignKey(User,db_column="updatedBy",help_text="Logged in user updated by ......")
lastPasswordReset = models.DateTimeField(db_column='lastPasswordReset',help_text="")
authorities = models.CharField(db_column="departmentId",max_length=255,help_text="")
class Meta:
managed = False
db_table = 'users'
the query i am using which is producing the desired output but too sloq is:-
universities = Universities.objects.using('cms').all()
for item in universities:
studentcount = Users.objects.using('cms').filter(universityId=item.id,userTypeId=2).count()
facultyCount = Users.objects.using('cms').filter(universityId=item.id,userTypeId=1).count()
clubCount = Users.objects.using('cms').filter(universityId=item.id,userTypeId=3).count()
totalcount = Users.objects.using('cms').filter(universityId=item.id).count()
print studentcount,facultyCount,clubCount,totalcount
print item.name
You should use annotate to get the counts for each university and conditional expressions to get the counts based on conditions (docs)
Universities.objects.using('cms').annotate(
studentcount=Sum(Case(When(users_set__userTypeId=2, then=1), output_field=IntegerField())),
facultyCount =Sum(Case(When(users_set__userTypeId=1, then=1), output_field=IntegerField())),
clubCount=Sum(Case(When(users_set__userTypeId=3, then=1), output_field=IntegerField())),
totalcount=Count('users_set'),
)
First, an obvious optimization. In the loop, you're doing essentially the same query four times: thrice filtering for different userTypeId, and once without one. You can do this in a single COUNT(*) ... GROUP BY userTypeId query.
...
# Here, we're building a dict {userTypeId: count}
# by counting PKs over each userTypeId
qs = Users.objects.using('cms').filter(universityId=item.id)
counts = {
x["userTypeId"]: x["cnt"]
for x in qs.values('userTypeId').annotate(cnt=Count('pk'))
}
student_count = counts.get(2, 0)
faculty_count = counts.get(1, 0)
club_count = count.get(3, 0)
total_count = sum(count.values()) # Assuming there may be other userTypeIds
...
However, you're still doing 1+n queries, where n is number of universities you have in the database. This is fine if the number is low, but if it's high you need further aggregation, joining Universities and Users. A first draft I came with is something like this:
# Assuming University.name is unique, otherwise you'll need to use IDs
# to distinguish between different projects, instead of names.
qs = Users.objects.using('cms').values('userTypeId', 'university__name')\
.annotate(cnt=Count('pk').order_by('university__name')
for name, group in itertools.groupby(qs, lambda x: x["university__name"]):
print("University: %s" % name)
cnts = {g["userTypeId"]: g["cnt"] for g in group}
faculty, student, club = cnts.get(1, 0), cnts.get(2, 0), cnts.get(3, 0)
# NOTE: I'm assuming there are only few (if any) userTypeId values
# other than {1,2,3}.
total = sum(cnts.values())
print(" Student: %d, faculty: %d, club: %d, total: %d" % (
student, faculty, club, total))
I might've made a typo there, but hope it's correct. In terms of SQL, it should emit a query like
SELECT uni.name, usr.userTypeId, COUNT(usr.id)
FROM some_app_universities AS uni
LEFT JOUN some_app_users AS usr ON us.universityId = uni.id
GROUP BY uni.name, usr.userTypeId
ORDER BY uni.name
Consider reading documentation on aggregations and annotations. And be sure to check out raw SQL that Django ORM emits (e.g. use Django Debug Toolbar) and analyze how well it works on your database. For example, use EXPLAIN SELECT if you're using PostgreSQL. Depending on your dataset, you may benefit from some indexes there (e.g. on userTypeId column).
Oh, and on a side note... it's off-topic, but in Python it's a custom to have variables and attributes use lowercase_with_underscores. In Django, model class names are usually singular, e.g. User and University.
I am trying to find the most injured player from my query but I am having trouble getting the proper results.
I was thinking of putting the player ID's in a list but how do you go about counting duplicate entries and then producing a "top 5" most injured list?
Here is my models.py
class PlayerInjury(models.Model):
player = models.ForeignKey(Player)
injury_type = models.ForeignKey(Injury)
injury_date = models.DateField(verbose_name='Injured On', null=True, blank=True)
description = models.CharField(verbose_name='Description', max_length=180, null=True, blank=True)
status = models.ForeignKey(Status)
projected_return = models.DateField(verbose_name='Projected Return Date', null=True, blank=True)
hide = models.BooleanField(default=False)
returned = models.BooleanField(default=False)
timestamp = models.DateTimeField(auto_now_add=True)
and what I have so far for my views.py
EDIT
def home(request):
context={}
player_list = []
most_recent = PlayerInjury.objects.all().order_by('-timestamp')[:5]
news = News.objects.all()
most_injured = PlayerInjury.objects.annotate(injury_count=Count('id')).order_by('-injury_count')[:5]
context['most_injured'] = most_injured
context['most_recent'] = most_recent
context['news'] = news
return render_to_response('dash/home.html', RequestContext(request, context))
Why not just use annotations?
from django.db.models import Count
Player.objects.annotate(injury_count=Count('playerinjury')).order_by('-injury_count')[:5]
If you're using 2.7, a pure-python solution would be
from collections import Counter
inj_counts = Counter()
for ip in all_intered_players:
inj_counts[ip.player_id] += 1
inj_counts.most_common(5) # gives you a list of top five [(player_id, num_injuries), ...]
Although using django's annotation feature is probably more advisable; the heavy lifting will then happen in your database.
Use a dictionary where the key is the player's name and the value is a counter of how many times the player got hurt. Iterate over your data and increment each dictionary entry's value on any instance of injury.
They main concept in using a dictionary in this scenario:
Keys are unique within a dictionary while values may not be. The
values of a dictionary can be of any type, but the keys must be of an
immutable data type such as strings, numbers, or tuples.
To get your top 5 you could then produce a list that is a sort of the dictionary by value.