class Box(models.Model):
owner = models.ForeignKey(User, related_name='user', verbose_name='Owner')
name = models.CharField("Name", max_length=30)
items = models.ManyToManyField('Item', through='BoxItem', blank=True, null=True)
class BoxItem(models.Model):
item = models.ForeignKey('Item')
box = models.ForeignKey('Box')
quantity = models.IntegerField()
class Item(models.Model):
name = models.CharField("Name Item", max_length=30)
In [1]: from project.app.models import *
In [2]: b = Box.objects.get(owner=1)
In [3]: b.items_all()
Out[4]: [<Item: PC>, <Item: Notebook>]
How to convert this Output to list?
How to add to this list quantity next to the name of Item? (Example: PC - 3, Notebook- 5)
What about something like:
b = Box.objects.get(owner=1)
[('%s - %s' % (box_item.item.name, box_item.quantity)) for box_item in b.items_all()]
In line 4 it appears that the result of b.items_all() is actually a QuerySet; you can use any of the QuerySet's methods; for most purposes (including list access) I usually use the QuerySet directly.
In order to have quantity shown next to the name of Item at Python shell level you can use the __unicode__ method at Model level; this should be easy to achieve if you have a one-to-one relationship between Item and BoxItem; recall that this would result in an additional join each time the __unicode__ function is called.
Related
I am working on a messaging app.
The models are as follows.
class ChatRoom(SafeDeleteModel):
_safedelete_policy = SOFT_DELETE_CASCADE
room_name = models.CharField(max_length=100, null=True, blank=True)
participants = models.ManyToManyField(User)
class Meta:
db_table = TABLE_PREFIX + "chat_room"
class Message(SafeDeleteModel):
_safedelete_policy = SOFT_DELETE_CASCADE
chat_room = models.ForeignKey(ChatRoom, on_delete=models.CASCADE)
message = models.TextField()
sent_by = models.ForeignKey(User, on_delete=models.CASCADE)
created_on = models.DateTimeField(default=django.utils.timezone.now)
class Meta:
db_table = TABLE_PREFIX + "chat_message"
I have to filter ChatRoom object which contains a list of users.
Eg: On sending data like this to the api
{
"participants": [2,3]
}
It should return a ChatRoom object which contains both user '2' and user '3' as participants.
I had tried filtering it with
room = ChatRoom.objects.filter(participants__in=serializer.validated_data['participants'])
but it returns a list of room objects with user '1' and user '2'.
I had also tried using get() but it returns an error.
What am I doing wrong and how can i do it right?
Thanks for looking into my problem. Hope you have a solution.
You said you are using Query..
ChatRoom.objects.filter(participants__in=serializer.validated_data['participants'])
filter function returns a list of objects of the model matching the conditions.
get function only return a single object of model and if none or more than one item matches the condition then an exception is thrown. That is why get is only used for candidate keys or unique resultant conditions.
In your case, I suppose both participants can be part of many rooms, also there might be a possibility that there is no such room. if you want only one queryset to be returned you can use this.
room_list= ChatRoom.objects.filter(participants__in=serializer.validated_data['participants']
if len(room_list) >0:
room = room_list[0]
else:
room = None
This will return the first room in which all the given participants are present, you can replace 0 with any valid value or add something more in the query if you want it to return a specific room.
class Docs(models.Model):
doc_id = models.BigIntegerField(primary_key=True)
journal = models.CharField(max_length=50, blank=True, null=True)
year = models.IntegerField(blank=True, null=True)
class Meta:
managed = False
db_table = 'docs'
class Assays(models.Model):
assay_id = models.BigIntegerField(primary_key=True)
doc = models.ForeignKey('Docs', models.DO_NOTHING)
description = models.CharField(max_length=4000, blank=True, null=True)
class Meta:
managed = False
db_table = 'assays'
class Activities(models.Model):
activity_id = models.BigIntegerField(primary_key=True)
assay = models.ForeignKey(Assays, models.DO_NOTHING)
doc = models.ForeignKey(Docs, models.DO_NOTHING, blank=True, null=True)
record = models.ForeignKey('CompoundRecords', models.DO_NOTHING)
class Meta:
managed = False
db_table = 'activities'
I apologize in advance if this answer is easily found elsewhere. I have searched all over and do not see a simple way to query my data as intuitively as I feel like should be possibe.
These are classes for 3 tables. The actual dataset is closer to 100 tables. Each doc_id can have one or many associated activity_ids. Each activity_id is associated with one assay_id.
My goal is to obtain all of the related data for each of the activities in a single doc. For instance:
query_activities_values = Docs.objects.get(doc_id=5535).activities_set.values()
for y in query_activities_values:
print(y)
break
>>> {'activity_id': 753688, 'assay_id': 158542, 'doc_id': 5535, .....
This returns 32 dictionaries (only part of the first is shown) for columns in the Activities table that have doc_id=5535. I would like to go one step further and also automatically pull in all of the data from the Assays table that is associated with the corresponding assay_id for each dictionary.
I can access that Assay data through a similar query, but only by stating each field explicitly:
query_activities_values = Docs.objects.get(doc_id=5535).activities_set.values('assay', 'assay__assay_type', 'assay__description')
for y in query_activities_values:
print(y)
break
I would like a single query that finds not only the assay and associated assay data for one activity_id, but finds all data and associated data for the 90+ other tables associated in the model
Thank you
Update 1
I did find this code that works surprisingly well for my needs, however, I was curious if this is the best method:
from django.forms.models import model_to_dict
def serial_model(modelobj):
opts = modelobj._meta.fields
modeldict = model_to_dict(modelobj)
for m in opts:
if m.is_relation:
foreignkey = getattr(modelobj, m.name)
if foreignkey:
try:
modeldict[m.name] = serial_model(foreignkey)
except:
pass
return modeldict
That's not too much code, but I thought there may be a more built-in way to do this.
What you need is prefetch_related:
Django 2.2 Prefetch Related Docs
query_activities_values = Docs.objects.get(doc_id=5535).activities_set.values()
Would become:
query_activities_values = Docs.objects.prefetch_related(models.Prefetch("activities_set", to_attr="activities"), models.Prefetch("assays_set", to_attr="assays")).get(doc_id=5535)
A new attributes will be created called "activities" and "assays" which you can use to retrieve data.
One more thing. This isn't actually 1 query. It's 3. However, if you're getting more than just one object from Docs, it's still going to be 3.
Also, is there a reason why you're using BigIntegerField?
I am trying to write a query that returns Vehicle objects. The query should filter by a particular Garage object (i.e., garage__name = ) and by a particular Category object (i.e., category__name = ), and where the Vehicle object's available field is True (available = True). These are the models:
class Garage(models.Model):
name = models.CharField (max_length = 30, blank=False)
zip = models.IntegerField (blank=False)
area = models.CharField (max_length = 30, blank=False)
pic = models.ImageField (upload_to ='static/images/garages')
class Vehicle(models.Model):
car_no = models.CharField (max_length = 20, blank=False)
photo = models.ImageField (upload_to ='static/images/vehicles')
car_model = models.ForeignKey (Car_model, on_delete=models.CASCADE)
garage = models.ForeignKey (Garage, on_delete=models.CASCADE)
category = models.ForeignKey (Category, on_delete=models.CASCADE)
available = models.BooleanField(default=True)
class Category(models.Model):
name = models.CharField (max_length = 15, blank=False)
What I've tried in the corresponding view function is this:
def carSelectView(request, type, grg):
cars=Vehicle.objects.filter(category__name=type, garage__name=grg, available=True)
return render(request, 'carphotoselectpage.html', {'ca':cars})
But it's returning an empty page. Before this approach, i tried to get the cars of a particular category only and it worked:
def carSelectView(request, type):
cars = Vehicle.objects.filter(category__name = type).filter(available=True)
I can't understand where the problem lies. I want to show vehicles by 1. selecting a particular Garage, and then 2. selecting the vehicles from that Garage that matches the Category name. 3. Whose available field is True.
Is the Vehicle model not fetching the Garage model in the query?
Your code looks fine, so this is likely a problem with what's being passed in the type and grg variables rather than a problem with your query.
To debug, try the following:
Use print() commands to output the values stored within the type and grg variables to your terminal. Check to ensure that they are as expected.
User $ python manage.py shell to boot up your terminal, then manually run your query to ensure that it returns the expected output. from .models import Vehicle, then Vehicle.objects.filter(category__name='REAL CATEGORY', garage__name='REAL GARAGE', available=True). Ensure that you get results back. if you don't, try removing criteria one by one until you can isolate the source of the problem.
Ensure that your template properly displays Car instances when provided with them. Try passing it an instance of a Car that you know exists (e.g., Car.objects.all()) and make sure that it is displaying proper output.
Reward models.py
class Reward(CommonInfo):
approved = models.BooleanField(default=False)
manager = models.ForeignKey(OrganisationUser, related_name='rewards_given') #todo add contraint so that manager should be manager of this role
approver = models.ForeignKey(OrganisationUser, null=True, related_name='approved_rewards', blank=True)# todo same as above but approver
number_of_gems = models.PositiveIntegerField(null=True, db_column='number_of_gems', blank=True)
tag = models.ForeignKey(Tag,related_name='rewards')
role_history = models.ForeignKey(RoleHistory, related_name='rewards')
certificate = models.OneToOneField(Certificate,related_name='reward')
and certificate models.py :
class Certificate(models.Model):
comments = models.TextField(blank=True, default='')
generic_certificate = models.ForeignKey(GenericCertificate, related_name='certificates_awarded')
tag = models.ForeignKey('Tag', related_name='certificates_awarded', null=True, blank=True)
created_at = models.DateTimeField(auto_now_add=True)
history_timestamp = models.DateTimeField(auto_now=True)
#template = models.FileField(upload_to='certificate/rewarded_templates', null=True, blank=True)#this will be path of certificate generated for this particular employee
rewardee = models.ForeignKey(OrganisationUser, related_name='certificates_rewarded')
#there will be location in server for certificates and it will be auto generated.
I have query to take out rewardee names from rewards models :
a= Reward.objects.filter(approved=True)
print a
Its printing : [<Reward: reciever-nirmal_4, tag-123>, <Reward: reciever-nirmal_1, tag-SDF34>]
I want to fetch nirmal_4 and nirmal_1 using this query . These are rewardee names.
How to do this?
Its printing [<Reward: reciever-nirmal_4, tag-123>, <Reward: reciever-nirmal_1, tag-SDF34>] because those are Reward objects. And in fact, it is fetching exactly those two objects which you want.
Now, if you want to print rewardee names, then you can loop over the objects and print rewardee names as:
a= Reward.objects.filter(approved=True)
for each in a:
print each.approver
Here, approver is still an object of OrganisationUser. So, if this object has a name then you can do print each.approver.name
Another option is, in your models.py, define a unicode function to the model as:
def __unicode__(self):
return self.approver.name
This function is used to set the name of object for recognizing it. So, you can set the name of reward object with its approver name.
i just want a dropdown field - kind like below:
Sex: | Male |v|
| Female |
you know, a very very standard drop down.
I've created this to that end:
class Relationship(models.Model):
SEX = [
("M","Male"),
("F","Female")
]
title = models.CharField(max_length=100)
sex = models.ChoiceField(label='', choices=SEX)
i will handle the label in the template on my own, hence the label=""
The problem is this: when i run syncdb, django freaks out, because below all this is:
class RelationshipForm(forms.ModelForm):
class Meta:
model = Relationship
ordering = ['create_date']
fields = ('title','sex')
Sadly, this causes me to get this exception:
django.core.exceptions.FieldError: Unknown field(s) (sex) specified for Relationship
What the heck am i meant to do? To be clear:
i want the relationship database table created to have a "sex" field that holds, well, either Male or Female
i want the wee dropdown to show up when you make a new relationship.
I'm sure this is super simple, any ideas?
There is no ChoiceField in models. You want CharField with choices as below.
sex = models.CharField(max_length=1, label='', choices=SEX)
Alternatively:
class Profile(models.Modell):
"""
User profile model
"""
PROF = 1
DR = 2
MR = 3
MRS = 4
MS = 5
PROFESSION_TITLE = ((PROF, 'Prof.'),
(DR, 'Dr.'),
(MR, 'Mr'),
(MRS, 'Mrs'),
(MS, 'Ms'),)
# personal details
user = models.ForeignKey(User, unique=True)
title = models.IntegerField('Title', choices=PROFESSION_TITLE,
max_length=25, blank=True, null=True)
See this link: http://www.b-list.org/weblog/2007/nov/02/handle-choices-right-way/
Argh. I see what i was doing wrong - elementary mistake. I'll keep this up here for now, unless everyone here thinks that this is the sort of elementary thing that is unnecessary # SO
In the Model:
class Relationship(models.Model):
title = models.CharField(max_length=100)
sex = models.CharFieldField(max_length=100)
in the Form:
class RelationshipForm(forms.ModelForm):
class Meta:
model = Relationship
ordering = ['create_date']
fields = ('title','sexField')
SEX = [
("M","guy"),
("F","girl")
]
sexField = ChoiceField(label='', choices=SEX)
def clean(self):
cleaned_data = super(RelationshipForm, self).clean()
self.instance.sex = (self.cleaned_data.get('sexField',None) )