If you have eg an app that stores articles and each of these articles can be rated by the user. This rating is not visible to the other users and is user specific (no overall rating) ie each rating of the same article-object needs to be stored for each user.
Currently I do this complete crazy stuff:
class Article(models.Model):
text = models.TextField(null=True, blank=True)
def __unicode__(self):
return self.text
class UserArticleStorage(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
null=True,
)
articles_rated_1 = models.ManyToManyField(
Article,
related_name="articles_rated_1",
blank=True
)
articles_rated_2 = models.ManyToManyField(
Article,
related_name="articles_rated_3",
blank=True
)
articles_rated_3 = models.ManyToManyField(
Article,
related_name="articles_rated_3",
blank=True
)
And I get them in the view by e.g. request.user.userarticlestorage.articles_rated_3
What is the normal way to store this user specific rating as an IntegerField?
I think you can do that by defining a simple model:
class Rating(models.Model):
article = models.ForeignKey(Article, ..., related_name='ratings')
user = models.ForeignKey(settings.AUTH_USER_MODEL,, ..., related_name='ratings')
rate = models.IntegerField()
and then access ratings by:
request.user.ratings
Related
In my project , Each candidate can takepart in some assessments,each assessment has some tests, each test has some questions in it and candidates should answer the questions
at last scores of the questions are saved in question_score and test_score table
I need to get some values of field and use them
I write a method for question_result table, to get them
but i dont know if it is needed to use select_related or not
if it is needed how can i use it ?
Assessment:
class Assessment(BaseModel):
company = models.ForeignKey(
'company.Company',
on_delete=models.CASCADE,
related_name='assessments',
)
title = models.CharField(max_length=255)
job_role = models.ForeignKey(
JobRole,
on_delete=models.PROTECT,
related_name='assessments',
blank=True,
null=True,
)
tests = models.ManyToManyField(
'exam.Test',
related_name='assessments',
blank=True,
through='TestOfAssessment',
)
candidates = models.ManyToManyField(
'user.User',
related_name='taken_assessments',
blank=True,
through='candidate.Candidate'
)
def __str__(self):
return self.title
Test:
class Test(BaseModel):
class DifficultyLevel(models.IntegerChoices):
EASY = 1
MEDIUM = 2
HARD = 3
company = models.ForeignKey(
'company.Company',
on_delete=models.PROTECT,
related_name='tests',
null=True,
blank=True,
)
questions = models.ManyToManyField(
'question.Question',
related_name='tests',
blank=True,
help_text='Standard tests could have multiple questions.',
)
level = models.IntegerField(default=1, choices=DifficultyLevel.choices)
title = models.CharField(max_length=255)
summary = models.TextField()
def __str__(self):
return self.title
Question :
class Question(BaseModel):
company = models.ForeignKey(
'company.Company',
on_delete=models.SET_NULL,
null=True,
blank=True,
related_name='company_questions',
)
question_text = models.TextField()
def __str__(self):
return truncatewords(self.question_text, 7)
TestResult:
class TestResult(BaseModel):
candidate = models.ForeignKey(
'Candidate',
on_delete=models.CASCADE,
related_name='test_results',
)
test = models.ForeignKey(
'exam.Test',
on_delete=models.CASCADE,
)
test_score = models.DecimalField(default=0.00, max_digits=5, decimal_places=2)
def __str__(self):
return f'{self.candidate.user.email} - {self.test.title}'
Candidate :
class Candidate(BaseModel):
assessment = models.ForeignKey(
'assessment.Assessment',
on_delete=models.CASCADE,
)
user = models.ForeignKey(
'user.User',
on_delete=models.CASCADE,
)
is_rejected = models.BooleanField(default=False)
def __str__(self):
return f'{self.user.email} - {self.assessment.title}'
Company :
class Company(models.Model):
manager = models.ForeignKey('user.User', on_delete=models.CASCADE, related_name='user_companies')
name = models.CharField(max_length=255)
city = models.ForeignKey('company.City', null=True, on_delete=models.SET_NULL)
address = models.CharField(max_length=255, blank=True, null=True)
def __str__(self):
return self.name
QuestionResult :
class QuestionResult(BaseModel):
test = models.ForeignKey(
'TestResult',
on_delete=models.CASCADE,
related_name='question_results',
)
question = models.ForeignKey(
'question.Question',
on_delete=models.CASCADE,
related_name='results',
)
result = models.TextField(
null=True,
blank=True,
)
answer_score = models.DecimalField(default=0.00, max_digits=5, decimal_places=2)
def __str__(self):
return f'{self.test.candidate.user.email} - {self.question}'
def text_variables(self):
email = self.test.candidate.user.email
company_name = self.test.test.company.name
assessment_name = self.test.candidate.assessment.title
candidate_first_name = self.test.candidate.user.first_name
job_name = self.test.candidate.assessment.job_role
user_fullname = User.full_name
data = dict(
job_name=job_name,
company_name=company_name,
email=email,
assessment_name=assessment_name,
candidate_first_name=candidate_first_name,
job_name=job_name,
user_fullname = user_fullname
)
return data
I wrote the def text_variables(self): method to fill the data dictionary and use it somewhere else
it work properly but i dont know if it needed to use selected_related or not
something like this (it does not work)
def text_variables(self):
question_result_object = QuestionResult.objects.filter(id=self.id).select_related(
"test__candidate","test__test__company","test__candidate__assessment")
email = question_result_object.test.candidate.user.email
company_name = question_result_object.test.test.company.name
assessment_name = question_result_object.test.candidate.assessment.title
candidate_first_name = question_result_object.test.candidate.user.first_name
job_name = question_result_object.test.candidate.assessment.job_role
data = dict(
job_name=job_name,
company_name=company_name,
email=email,
assessment_name=assessment_name,
candidate_first_name=candidate_first_name,
job_name=job_name,
user_fullname = user_fullname
)
return data
the error is :
File "E:\work\puzzlelity\talent-backend\candidate\models.py", line 385, in report_to_candidate_email_text_variables
email = question_result_object.test.candidate.user.email
AttributeError: 'QuerySet' object has no attribute 'test'
[03/Jan/2023 17:59:00] "POST /api/v1/candidatures/183f8432-ea81-4099-b211-3b0e6475ffab/submit-answer/ HTTP/1.1" 500 123319
I dont know how should i use the select_related
It's never required. It optimizes querysets, especially in ListViews.
Consider your Assessment model. It has ForeignKey fields company and job_role. If you simply fetch
assessment = Assessment.objects.get( id=something)
and then refer to assessment.company, that causes a second DB query to fetch the company object. And then a third if you refer to assessment.job_role.
You can reduce these three queries to one by using
assessment = Assessment.objects.select_related(
'company', 'job_role') .get( id=something)
which does a more complex query to retrieve all the data.
Where it matters is in a list view where you iterate over a large number of assessment objects in Python or in a template. For example, if object_list is assessment.objects.all() and there are 300 of them, then
{% for assessment in object_list %}
... stuff ...
{{assessment.company.name }}
...
{% endfor %}
Will hit the DB 300 times, once for each company! If you use select_related, all 300 companies linked to the 300 assessments will be retrieved in a single DB query. which will be very noticeably faster.
I'd strongly recommend installing Django Debug Toolbar in your development project. Then click on the SQL option on any view, and you can see what SQL was required, and in particular how many SQL queries were performed and whether there were batches of repetetive queries which mean there's a trivial optimisation to be made.
I am trying to create an E-Commerce Website and I am at the Final Step i.e. Placing the Order. So, I am trying to add all the Cart Items into my Shipment model. But I am getting this error.
'QuerySet' object has no attribute 'product'
Here are my models
class Product(models.Model):
productId = models.AutoField(primary_key=True)
productName = models.CharField(max_length=200)
productDescription = models.CharField(max_length=500)
productRealPrice = models.IntegerField()
productDiscountedPrice = models.IntegerField()
productImage = models.ImageField()
productInformation = RichTextField()
productTotalQty = models.IntegerField()
alias = models.CharField(max_length=200)
url = models.CharField(max_length=200, blank=True, null=True)
class Customer(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
name = models.CharField(max_length=100, null=True, blank=True)
email = models.EmailField(max_length=100)
profileImage = models.ImageField(blank=True, null=True, default='profile.png')
phoneNumber = models.CharField(max_length=10, blank=True, null=True)
address = models.CharField(max_length=500, blank=True, null=True)
class Order(models.Model):
customer = models.ForeignKey(Customer, on_delete=models.SET_NULL, blank=True, null=True)
dateOrdered = models.DateTimeField(auto_now_add=True)
orderCompleted = models.BooleanField(default=False)
transactionId = models.AutoField(primary_key=True)
class Cart(models.Model):
product = models.ForeignKey(Product, on_delete=models.SET_NULL, blank=True, null=True)
order = models.ForeignKey(Order, on_delete=models.SET_NULL, blank=True, null=True)
quantity = models.IntegerField(default=0, blank=True, null=True)
dateAdded = models.DateTimeField(auto_now_add=True)
class Shipment(models.Model):
customer = models.ForeignKey(Customer, on_delete=models.SET_NULL, blank=True, null=True)
orderId = models.CharField(max_length=100)
products = models.ManyToManyField(Product)
orderDate = models.CharField(max_length=100)
address = models.CharField(max_length=200)
phoneNumber = models.CharField(max_length=13)
I just removed additional functions i.e. __str__ and others.
Here is the views.py
def orderSuccessful(request):
number = Customer.objects.filter(user=request.user).values('phoneNumber')
fullAddress = Customer.objects.filter(user=request.user).values('address')
timeIn = time.time() * 1000 # convert current time in milliSecond
if request.method == 'POST':
order = Shipment.objects.create(customer=request.user.customer, orderId=timeIn,
orderDate=datetime.datetime.now(), address=fullAddress,
phoneNumber=number)
user = Customer.objects.get(user=request.user)
preOrder = Order.objects.filter(customer=user)
orders = Order.objects.get(customer=request.user.customer, orderCompleted=False)
items = orders.cart_set.all() # Here is all the items of cart
for product in items:
product = Product.objects.filter(productId=items.product.productId) # error is on this line
order.products.add(product)
Cart.objects.filter(order=preOrder).delete()
preOrder.delete()
order.save()
else:
return HttpResponse("Problem in Placing the Order")
context = {
'shipment': Shipment.objects.get(customer=request.user.customer)
}
return render(request, "Amazon/order_success.html", context)
How to resolve this error and all the cart items to field products in Shipment model?
Your model is not really consistent at all. Your Cart object is an m:n (or m2m - ManyToMany) relationship between Product and Order. Usually, you would have a 1:n between Cart and Product (a cart contains one or more products). One Cart might be one Order (unless you would allow more than one carts per order). And a shipment is usually a 1:1 for an order. I do not see any of this relationships in your model.
Draw your model down and illustrate the relations between them first - asking yourself, if it should be a 1:1, 1:n or m:n? The latter can be realized with a "through" model which is necessary if you need attributes like quantities.
In this excample, we have one or more customers placing an order filling a cart with several products in different quantities. The order will also need a shipment fee.
By the way: bear in mind that "filter()" returns a list. If you are filtering on user, which is a one to one to a unique User instance, you would better use "get()" as it returns a single instance.
Putting in into a try - except or using get_object_or_404() makes it more stable.
product = Product.objects.filter(productId=items.product.productId)
should be something like:
product = product.product
not to say, it becomes obsolete.
It looks like you make a cart for a product by multiple instances of Cart, the problem is you try to access the wrong variable, also you don't need to filter again when you already have the instance, make the following changes:
carts = orders.cart_set.all() # Renamed items to carts for clarity
for cart in carts:
product = cart.product
order.products.add(product) # The name order is very misleading makes one think it is an instance of Order, actually it is an instance of Shipment
As mentioned above in my comment your variable names are somewhat misleading, please give names that make sense to any variable.
I am trying to get the information from one table filtered by information from another table (I believe this is called joining tables).
I have these two models:
class Listing(models.Model):
title = models.CharField(max_length=64)
description = models.CharField(max_length=500)
price = models.DecimalField(max_digits=11, decimal_places=2, validators=[MinValueValidator(Decimal('0.01'))])
category = models.ForeignKey(Category, on_delete=models.CASCADE, default="")
imageURL = models.URLField(blank=True, max_length=500)
creator = models.ForeignKey(User, on_delete=models.CASCADE, related_name="creator", default="")
isOpen = models.BooleanField(default=True)
def __str__(self):
return f"{self.id} | {self.creator} | {self.title} | {self.price}"
class Watchlist(models.Model):
listing = models.ForeignKey(Listing, on_delete=models.CASCADE, related_name="listingWatched", default="")
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="userWatching", default="")
What I need to do is to get all the listings from a specific user Watchlist, the idea is to generate a page with all of the information of each of the listings that are in the user's watchlist. What should I do?
Thanks in advance!
Since is a foreign key, in Django you can access the information by calling the attribute
For example:
my_user = Watchlist.objects.get(pk=1)
print(my_user.listing.title)
You can also access to that attrbute in a query in case you need to filter upwards some value
values = Watchlist.objects.all().filter(listing__title='MyTitle')
my_titles = [x.title for x in values]
print(my_titles)
Or in your case, if you want to list all the title for a specific user
values = Watchlist.objects.all().filter(user='foo_user')
my_titles = [x.listing.title for x in values]
print(my_titles)
More documentation here
Good day,
I am trying to create a django model that contains a choice whether the user has read or not read a book. For that I have made a choice list. But i am unable to display it on the admin panel. All other fields are getting displayed other than the choice field.
Can you please tell me where I am going wrong. I am new to django and have referred from the documnetation.
Following is the code:
class Book(models.Model):
YES = 'y'
NO = 'n'
DID_READ_CHOICES = [
(YES,'Yes'),
(NO,'No'),
]
title = models.CharField(max_length=100)
author = models.ForeignKey(
Author,
on_delete=models.SET_NULL,
null=True,
related_name='author_books'
)
genre = models.ManyToManyField(Genre, help_text='Select a genre for this book')
summary = models.TextField(max_length=1000, help_text='Enter a brief description of the book',blank=True,null=True)
read = models.CharField(
max_length=1,
choices=DID_READ_CHOICES,
default=NO,
),
objects = BookManager()
class Meta:
ordering = ['title']
def __str__(self):
return self.title
Thank you
There is a trailing question at the end of read, thus django did not detect the field.
I am studying Django and SQL and I have proposed to create a social network in which I can add all the reactions of a publication and add it to a new field where they are all added.
from django.db import models
# Create your models here.
class Post(models.Model):
# User
user = models.OneToOneField(User, on_delete=models.CASCADE)
post = models.TextField(max_length=500000)
# Data
comments = models.IntegerField()
reactions = models.IntegerField()
## Reaction Data
like = models.IntegerField()
love = models.IntegerField()
wow = models.IntegerField()
sad = models.IntegerField()
angry = models.IntegerField()
That is the model of publications, there is a field called reactions, and that will be the sum of all the reactions that publication has acquired. How can I create that sum?
Such architecture will be a little wrong.
from project_name import settings
class Post(models.Model):
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
title = models.CharField(max_length=50)
text = models.TextField()
likes = models.ManyToManyField(settings.AUTH_USER_MODEL, blank=True, related_name='post_likes')
love = models.ManyToManyField(settings.AUTH_USER_MODEL, blank=True, related_name='post_loves')
# ... another reactions
created_date = models.DateTimeField(default=timezone.now)
settings.AUTH_USER_MODEL is your User
After that you will then be able to not only know the number of reactions, but also to identify users
To count users:
post = Post.objects.create(author=..., ...) # create post
queryset = post.likes # will return users id, who liked post
queryset.count() # will return number of users