I have the following classes: Student, LabJournal, JournalResponse, and JournalField. I want to define a "status" function for student to determine how many questions (JournalField) they've answered (JournalResponse). The problem is the function dies without a return on the following line:
total_questions = models.JournalResponse.objects.filter(owner__exact=self.id).filter(field__journal__exact=self.assignment).count()
My guess is that I'm doing the model query wrong from within the class definition, or that you're not allowed to query from within a separate model. However I have not found anything in the docs to confirm or deny this, and without any errors it's difficult to debug. Running Django 1.1.
Code below:
class Student (models.Model):
user = models.ForeignKey(User, unique=True, null=False, related_name='student')
teacher = models.ForeignKey(User, null=False, related_name='students')
assignment = models.ForeignKey(LabJournal, blank=True, null=True, related_name='students')
def get_absolute_url(self):
return "/labjournal/student/%i/" % self.id
def status(self):
if self.assignment == None : return "unassigned"
percent_done = 0
total_questions = models.JournalResponse.objects.filter(owner__exact=self.id).filter(field__journal__exact=self.assignment).count()
answered_questions = models.JournalResponse.objects.filter(owner__exact=self.id).filter(field__journal__exact=self.assignment).filter(text!=None).count()
percent_done = (answered_questions/total_questions)*100
return '%d%% done' % percent_done
class JournalResponse (models.Model):
owner = models.ForeignKey(Student, null=False, related_name='responses')
field = models.ForeignKey(JournalField, null=False, related_name='responses')
text = models.TextField(null=True, blank=True)
file = models.URLField(null=True, blank=True)
class JournalField (models.Model):
TYPE_CHOICES = (
(u'HTML', u'HTML'),
(u'IF', u'ImageField'),
(u'TF', u'TextField'),
)
journal = models.ForeignKey(LabJournal, null=False, related_name='fields', help_text='Parent Journal')
ordinal = models.IntegerField(help_text='Field order')
type = models.CharField(null=False, max_length=64, choices=TYPE_CHOICES, help_text='Field type')
# Contains HTML content for HTML fields, contains the text marked "question" closest
# to and above the current field for picture and text entry fields
content = models.TextField(help_text='Should contain HTML content for HTML (question) fields or associated (previous question) HTML for ImageFields and TextFields.')
UPDATED
Here's the working status method:
def status(self):
if self.assignment == None : return "unassigned"
percent_done = 0
# sets up query, but doesn't actually hit database
response_set = self.responses.filter(owner=self).filter(field__journal=self.assignment)
# force float so divide returns float
# the two count statements are the only two actual hits on the database
total_questions = float(response_set.count())
answered_questions = float(response_set.exclude(text='').count())
percent_done = (answered_questions/total_questions)*100
return '%d%% done' % percent_done
It looks like you're referring to models.JournalResponse which shouldn't exist (AttributeError?) because in the class definition the same models name is referring to django.db.models
You would need to refer to it via the actual model object, so JournalResponse.objects.filter().
In your case, you have a reverse relationship to JournalResponse from Student so you can simply use self.journalresponse_set.filter() to access JournalResponse.objects.filter(student=self)
http://docs.djangoproject.com/en/dev/topics/db/queries/#following-relationships-backward
Try:
self.journalresponse_set.filter(field__journal=self.assignment)
Also, your next filter line would break as well on text!=None. Use exclude(text=None) syntax instead.
Related
I want to make a website for eBooks with a page that has all the books published by one of the authors. The problem is that I have no idea how to do that. I will mention that I am a beginner.
I tried this int the model file
class Author(models.Model):
author = models.TextField()
class Product(models.Model):
…
author=models.ForeignKey(Author,on_delete=models.CASCADE)
The result in the terminal was:
File "/home/user/petnet/petnet-env/lib/python3.10/site-packages/django/db/backends/sqlite3/base.py", line 264, in check_constraints
raise IntegrityError(
django.db.utils.IntegrityError: The row in table 'store_product' with primary key '2' has an invalid foreign key: store_product.author_id contains a value 'anonim' that does not have a corresponding value in store_author.id.
I think this is caused by the act that I made the author field later and there were already authors fields from before, but then, when I tried to revert back to what I had before doing this, I got some errors regarding migrations.
Also the views were:
def author_detail(request, slug):
author = get_object_or_404(Author, slug=slug)
products = author.products.filter(status=Product.ACTIVE)
return render(request, 'store/author_detail.html', {
'author':author,
'products':products
})
But I am also curious if there is a chance I could use only this for models so I could use the form for adding a product in a much easier way.
class Product(models.Model):
DRAFT = 'draft'
WAITING_APPROVAL = 'waitingapproval'
ACTIVE = 'active'
DELETED = 'deleted'
STATUS_CHOICES = (
(DRAFT, 'Ciorna'),
(WAITING_APPROVAL, 'Asteapta aprobare'),
(ACTIVE, 'Activ'),
(DELETED, 'Sters')
)
user = models.ForeignKey(User, related_name='products',on_delete=models.CASCADE)
category=models.ForeignKey(Category, related_name='products',on_delete=models.CASCADE)
title = models.CharField(max_length=50)
image = models.ImageField(upload_to='uploads/product_images/', blank=True, null=True)
editie = models.IntegerField()
editura = models.CharField(max_length=50)
description = models.TextField(blank=True)
author = models.TextField(max_length=50)
created_at = models.DateTimeField(auto_now_add=True)
slug = models.SlugField(max_length=50)
status = models.CharField(max_length=50, choices=STATUS_CHOICES, default=ACTIVE)
i encountered the following problem when i try to migrate list of models one of which contains a ManyToMany field.
class Item(models.Model):
File "C:\Users\helin\Downloads\Django\E-commerce\Farmers\Farmersapp\models.py", line 60, in Item
sluger = farmer.First_Name
AttributeError: 'ManyToManyField' object has no attribute 'First_Name'
Below are the models i created.any help is appreciated.Thank you
class Farmer(models.Model):
id = models.AutoField(default=1,primary_key=True)
First_Name = models.CharField(max_length=15)
Last_Name = models.CharField(max_length=15)
def __str__(self):
return self.First_Name+" "+self.Last_Name
def get_farmer(self):
return self.farmer.First_Name+" " +self.farmer.Last_Name
class Item(models.Model):
id = models.AutoField(default=1,primary_key=True)
category = models.CharField(choices=CATEGORY_CHOICES, max_length=6)
price = models.FloatField()
description = models.TextField(blank=True)
image = models.ImageField()
farmer = models.ManyToManyField(Farmer, through='ItemAmount',related_name='item')
sluger = farmer.First_Name
slug = models.SlugField(default=sluger)
def __str__(self):
return self.category
class ItemAmount(models.Model):
farmer = models.ForeignKey(Farmer, on_delete=models.CASCADE)
item = models.ForeignKey(Item, on_delete=models.CASCADE)
quantity = models.IntegerField(default=1)
First, would suggest to take a look at Python style guide, like lowercase attribute names, etc.
Django auto-creates id primary-key field on every model, unless other field is set as primary-key. So, this part can be safely avoided.
get_farmer method - how is it different from str? Also, these are model instance methods ((self)), so there is no self.farmer field on Farmer object - this will fail.
class Farmer(models.Model):
# id AutoFied is created by default by django, so no need to specify
# id = models.AutoField(default=1,primary_key=True)
first_name = models.CharField(max_length=15)
last_name = models.CharField(max_length=15)
def __str__(self):
return self.first_name + " " + self.last_name
farmer = models.ManyToManyField() - as it is ManyToMany, this means many farmers, so it is better to name field farmers, also same applies to reverse relation - Farmer might have multiple items - related_name=items.
sluger - is it a field? Also, it might have many farmers, so which one to pick?
slug - referencing self fields in default is not good idea, better set default in forms.
You can make slug CharField and set its value in save() method for example.
class Item(models.Model):
# id AutoFied is created by default by django, so no need to specify
# id = models.AutoField(default=1,primary_key=True)
category = models.CharField(choices=CATEGORY_CHOICES, max_length=6)
price = models.FloatField()
description = models.TextField(blank=True)
image = models.ImageField()
farmers = models.ManyToManyField(
Farmer,
through='ItemAmount',related_name='items'
)
slug = models.SlugField()
def __str__(self):
return self.category
You can start with minimum working models and add new fields / methods one by one - it would be easier to debug and you will have base working app.
Order_by not working in FloatField type Django
models.py
class CourseCategory(models.Model):
category = models.CharField(max_length=100, unique=True, null=False)
description = models.TextField(blank=True)
class Meta(object):
app_label = "course_category"
def __unicode__(self):
return self.category
Coursetrack Model
class CourseTrack(models.Model):
category = models.ForeignKey(CourseCategory)
course_id = CourseKeyField(max_length=255, db_index=True)
tracks = models.FloatField(null=True, blank=True, default=None)
active = models.BooleanField(default=True)
class Meta(object):
app_label = "course_category"
def __unicode__(self):
return str(self.course_id)
TopCoursesCategory
class TopCoursesCategory(models.Model):
category = models.ForeignKey(CourseCategory)
class Meta(object):
app_label = "course_category"
def __unicode__(self):
return str(self.category)
I added here order_by(), as you can see but its not working.
view.py
def get_popular_courses_ids():
popular_category_id = CourseCategory.objects.filter(category='Popular')
popular_courses_ids = CourseTrack.objects.values('course_id').filter(category=popular_category_id).order_by('tracks')
course_id_list = []
for course_id in popular_courses_ids:
course_id_list.append(course_id['course_id'])
return course_id_list
I think the query you have posted is wrong.
You have used the following lines.
popular_category_id = CourseCategory.objects.filter(category='Popular')
popular_courses_ids = CourseTrack.objects.values('course_id').filter(category=popular_category_id).order_by('tracks')
In the first line, you have used filter and you have used the resulting variable as category= in your second query which you cannot do. For category= in your second query to work, you would need to give a single element and not a queryset. Replace your filter with get in the first query and it might work fine.
Or
If you think that popular_category_id can have more than one row for the category popular, leave the first query as it is and change your second query to
popular_courses_ids = CourseTrack.objects.values('course_id').filter(category__in=popular_category_id).order_by('tracks')
I have changed category to category__in.
I have the following models in Django:
class campaign(models.Model):
start_date = models.DateField('Start Date')
end_date = models.DateField('End Date')
description = models.CharField(max_length=500)
name = models.CharField(max_length=200)
active_start_time = models.TimeField()
active_end_time = models.TimeField()
last_updated = models.DateTimeField('Date updated',auto_now=True)
active = models.BooleanField(default=True)
client_id = models.ForeignKey('client',on_delete=models.PROTECT)
def __unicode__(self):
return u'%d | %s | %s' % (self.id,self.name, self.description)
class campaign_product(models.Model):
product_id = models.ForeignKey('product',on_delete=models.PROTECT)
last_updated = models.DateTimeField('Date updated',auto_now=True)
campaign_id = models.ForeignKey('campaign',on_delete=models.PROTECT)
class product(models.Model):
name = models.CharField(max_length=200)
description = models.CharField(max_length=500)
sku = models.CharField(max_length=200,blank=True,null=True)
retail_price = models.DecimalField(decimal_places=2,max_digits=11)
discount_price = ((1,'Yes'),(0,'No'))
discounted_price = models.DecimalField(decimal_places=2,max_digits=11,blank=True,null=True)
category_id = models.ForeignKey('category',on_delete=models.PROTECT)
last_updated = models.DateTimeField('Date updated',auto_now=True)
active = models.BooleanField(default=True)
def __unicode__(self):
return u'%d | %s' % (self.id, self.name)
I also have the following serializer:
class campaignProductSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = campaign_product
fields = ('product_id', 'campaign_id')
And the following view set behavior in the urls.py file:
class campaignProductViewSet(viewsets.ModelViewSet):
queryset = campaign_product.objects.filter(campaign_id__start_date__lte=datetime.now(),campaign_id__end_date__gte=datetime.now(),campaign_id__active__exact=True)
serializer_class = campaignProductSerializer
My problem is I need to include the name field from the products model in my query results when for instance a request is made on http://127.0.0.1:8000/campaign_product/1/. Currenly this request returns only the product_id and the campaign_id. I tried making the serializer as follows:
class campaignProductSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = campaign_product
fields = ('product_id', 'campaign_id', 'product.name')
But then the service returns the following error:
Field name `product.name` is not valid for model `campaign_product`.
I event tried using product__name with and without quotes. Without quotes it tells me that there is no such variable, and with quotes it gives the is not valid for model error similar to the above. Heeelp! Getting this extra field is proving to be a pain :-(
What you want will need to look something more like this:
class campaignProductSerializer(serializers.HyperlinkedModelSerializer):
product_name = serializers.CharField(source='product_id.name')
class Meta:
model = campaign_product
fields = ('product_id', 'campaign_id', 'product_name')
P.S. As an unrelated side note, it is generally a convention in Python code to name classes with CamelCase, such as Campaign, CampaignProduct, Product, and CampaignProductSerializer.
Edit: P.P.S. Originally, I had put written the product_name field with source='product.name'. This was actually due to me looking at the code too quickly and making assumptions based on Django conventions. Typically, with a Django ForeignKey, you would name the ForeignKey field after the model you are linking to, rather than explicitly naming it with _id. For example, the CampaignProduct model would typically be written with product = ForeignKey(...) and campaign = ForeignKey(...). In the background, Django will actually use product_id and campaign_id as the database field names. You also have access to those names on your model instances. But the product and campaign variables on your model instances actually return the objects which you are referring to. Hopefully that all makes sense.
I am making a very lightweight crm for a non-profit, in django. The models of interest to this problem are:
class Human(models.Model):
first_name = models.CharField(max_length=200)
last_name = models.CharField(max_length=200)
nickname = models.CharField(max_length=200, blank=True, null=True)
middle_name = models.CharField(max_length=200, blank=True, null=True)
def __unicode__(self):
namestring = self.last_name+','+self.first_name
if self.nickname:
namestring += '('+self.nickname+')'
elif self.middle_name:
namestring += '('+self.middle_name+')'
return namestring
class PhoneNumber(models.Model):
humans = models.ManyToManyField(Human, through='HumanToPhoneNumber')
nation_code = models.IntegerField(blank=True, null=True)
area_code = models.IntegerField()
local_number = models.IntegerField()
def __unicode__(self):
what_to_call_it = "("+str(self.area_code)+")"+str(self.local_number)
if (self.nation_code):
what_to_call_it = str(self.nation_code)+what_to_call_it
return what_to_call_it
class HumanToPhoneNumber(models.Model):
human = models.ForeignKey(Human)
phone_number = models.ForeignKey(PhoneNumber)
begin_date = models.DateTimeField('begin date')
end_date = models.DateTimeField('end date', null=True, blank=True)
active = models.BooleanField(default=True)
preferred = models.BooleanField(default=False)
label = models.CharField(max_length=200, blank=True, null=True)
def __unicode__(self):
what_to_call_it = str(self.human)
if self.label:
what_to_call_it += "("+self.label+")"
return what_to_call_it
When I show the phone numbers for a person, I only want to show the ones that are still "active", and also display a marker by the preferred method of contact (there are similar models for email, humantoemail, address, humantoaddress). More than one person can have the same number, and a person can have multiple numbers, so it's many-to-many.
The view for this is:
def human(request, human_id):
p = get_object_or_404(Human, pk=human_id)
emails = p.emailaddress_set.all()
emails.filter(emailaddress__humantoemailaddress.active=True) #this line does not work
phone_numbers = p.phonenumber_set.all()
addresses = p.physicaladdress_set.all()
return render_to_response('person.html', {'person': p, 'emails': emails, 'phone_numbers': phone_numbers, 'addresses': addresses})
I've tried a few variations on the above, but I'm clearly not groking how I'm meant to access the "active" field on the many-to-many relationship. I can't put the field on the Email, PhoneNumber, or PhysicalAddress model because it could be still active for one person but no longer active for another, and similarly for "preferred".
What is the right way to write this query in a django view? Any help is appreciated. Oh, and I'm using Django 1.3, in case that matters.
Edit: corrected a typo in the above, plus tried a different filter on phone number copied more or less exactly from Django docs on MTM:
def human(request, human_id):
p = get_object_or_404(Human, pk=human_id)
emails = p.emailaddress_set.filter(humantoemailaddress__active=True) <--- does not work
phone_numbers = p.phone_number_set.filter(humantophonenumber__begin_date__gt=date(2011,1,1)) <--- does not work either
addresses = p.physicaladdress_set.all()
return render_to_response('person.html', {'person': p, 'emails': emails, 'phone_numbers': phone_numbers, 'addresses': addresses})
Any help is appreciated, and let me know if there's any other details I should be adding.
Second Edit: D'oh! It helps to edit the right file. I have checked the answer below, which actually works just fine.
You can filter on fields in the joining table using double underscore notation e.g. humantophonenumber__active.
For example:
p = get_object_or_404(Human, pk=human_id)
phone_numbers = p.phone_number_set.filter(humantophonenumber__active=True)
For further Beatles-based examples, check out the Django docs.