I'm confused with my django models,
My models:
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
bio = models.TextField(max_length=500, blank=True)
location = models.CharField(max_length=30, blank=True)
birth_date = models.DateField(null=True, blank=True)
picture = models.ImageField(upload_to="photos/", default="photos/none/default.png")
film = models.ManyToManyField(Film)
class Film(models.Model):
title = models.CharField(max_length=60)
year = models.IntegerField(choices=YEARS)
image = models.ImageField(upload_to="images/", default="images/none/blank_poster.jpg")
def __str__(self):
return self.title
and now I trying to make a ratings for my film, when user adding a film to his list.
I tried M2M with through, but it wasn't exactly what I wanted, because user could add the same film several times and another problem with it was remove single film from list.
Now i thinking about additional models like this:
class FilmRating(models.Model):
user = models.ForeignKey(User)
film = models.ForeignKey(Film)
rate = models.IntegerField(choices=CHOICES)
Im glad If you can point me to the correct way to solve this problem, In future I want probably to store all rating from users for set average rate.
Related
error image
I'm using the model and I keep running into problems with many to many. At first, I made it without giving an id value, but it seems that the id value is not entered, so when I put the id value directly, the same problem as above occurs. But in the Post model below, the same form of likes is used. Why?
from django.db import models
# from django.contrib.auth.models import User
from django.conf import settings
# from server.apps.user.models import Profile
# Create your models here.
class Clothes(models.Model):
CATEGORYS =[
(0, '상의'), #상의
(1, '하의'), #하의
(2, '아우터'), #아우터
(3, '신발'), #신발
(4, '악세사리'), #악세사리
]
category = models.IntegerField(default=0,choices=CATEGORYS)
id = models.IntegerField(primary_key=True)
img = models.ImageField(upload_to='main/images/clothes/%Y/%m/%d')
save = models.ManyToManyField(settings.AUTH_USER_MODEL, related_name='Pickitems', blank=True)
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
buying = models.TextField(null=True, blank=True)
def __str__(self):
return f'{self.id}: {self.category}'
#pk가 존재하지 않는것 같음.
# class SavePeople(models.Model):
class Post(models.Model):
main_img = models.ImageField(upload_to='main/images/post/%Y/%m/%d')
title = models.CharField(max_length=100)
content = models.TextField()
private = models.BooleanField(default=False)
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
clothes = models.ManyToManyField(Clothes,related_name='Clothes')
likes = models.ManyToManyField(settings.AUTH_USER_MODEL, related_name='Likes', blank=True)
def __str__(self):
return f'{self.pk}: {self.title}'
def get_absolute_url(self):
return f'/community/'
#이거 나중에 detail page로 바꿔주세요
class Comment(models.Model):
post = models.ForeignKey(Post, on_delete=models.CASCADE)
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
content = models.TextField()
create_date = models.DateTimeField(auto_now_add=True)
update_date = models.DateTimeField(auto_now_add=True)
def __str__(self):
return f'({self.author}) {self.post.title} : {self.content}'
class Commu(models.Model):
COMMU_CHOICES = [
('buying', 'buying'), #공동구매
('openrun', 'openrun'), #오픈런
('question', 'question'), #고민방
]
category = models.CharField(max_length=20, choices=COMMU_CHOICES)
img = models.ImageField(upload_to='main/images/commu/%Y/%m/%d', null=True, blank=True)
title = models.CharField(max_length=100)
content = models.TextField()
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
def __str__(self):
return f'{self.pk}: {self.title}'
def get_absolute_url(self):
return f'/community/commu'
I added the code saves= models.ManyToManyField(settings.AUTH_USER_MODEL, related_name='Save', blank=True) to the Clothes model to make a save of Clothes in the same way as the likes of the Post model, but an error like the attached picture is displayed. occurred. When I searched, it seemed that the pk value did not exist.
The issue is the id field that you explicitly provided, Django itself creates an id field as a primary key for each model if you don't specify one. So, it is not necessary to add it to the model. Kindly remove it through the Clothes model and run migration commands.
And it doesn't give in case of likes since there is no extra field id in Post model unlike that of Clothes.
Note: Models in Django doesn't require s to be added as suffix, as it is automatically done, so you may change Clothes to Cloth.
I have been using Django for 4 5 months now and i have been implimenting users by importing the user class like this
example 1:
from django.db import models
from django.contrib.auth.models import User
class Posts(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
post_name = models.CharField(max_length=150)
desription = models.CharField(max_length=200)
image = models.ImageField(upload_to="images/uploads")
def __str__(self):
return self.desription
and i have seen some people use the user model like this :
example 2:
class Recipe(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
name = models.CharField(max_length=220)
description = models.TextField(blank=True, null=True)
directions = models.TextField(blank=True, null=True)
timestamp = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
active = models.BooleanField(default=True)
and also like this :
example 3:
author = models.ForeignKey(get_user_model())
now I have used both example 1 and example 2 for my projects and to mess around in my free time
and both seem to work fine , I am wondering what would be the use cases for these different methods and also is there any pros or cons to these methods of using the User Model?
I'm currently working on a website where advertisements will be posted to display vehicles for sale and rent. I would like to retrieve a queryset that highlights only one car brand (i.e. Audi) which has the highest number of posts for the respective model. Example:
Displaying the Audi brand because it has the highest number of related posts.
My question is, what's the most efficient way of doing this? I've done some work here but I'm pretty sure this is not the most efficient way. What I have is the following:
# Algorithm that is currently retrieving the name of the brand and the number of related posts it has.
def top_brand_ads():
queryset = Advertisement.objects.filter(status__iexact="Published", owner__payment_made="True").order_by('-publish', 'name')
result = {}
for ad in queryset:
# Try to update an existing key-value pair
try:
count = result[ad.brand.name.title()]
result[ad.brand.name.title()] = count + 1
except KeyError:
# If the key doesn't exist then create it
result[ad.brand.name.title()] = 1
# Getting the brand with the highest number of posts from the result dictionary
top_brand = max(result, key=lambda x: result[x]) # Returns for i.e. (Mercedes Benz)
context = {
top_brand: result[top_brand] # Retrieving the value for the top_brand from the result dict.
}
print(context) # {'Mercedes Benz': 7} -> Mercedes Benz has seven (7) related posts.
return context
Is there a way I could return a queryset instead without doing what I did here or could this be way more efficient?
If the related models are needed, please see below:
models.py
# Brand
class Brand(models.Model):
name = models.CharField(max_length=255, unique=True)
image = models.ImageField(upload_to='brand_logos/', null=True, blank=True)
slug = models.SlugField(max_length=250, unique=True)
...
# Methods
# Owner
class Owner(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
telephone = models.CharField(max_length=30, blank=True, null=True)
alternate_telephone = models.CharField(max_length=30, blank=True, null=True)
user_type = models.CharField(max_length=50, blank=True, null=True)
payment_made = models.BooleanField(default=False)
expiring = models.DateTimeField(default=timezone.now)
...
# Methods
# Advertisement (Post)
class Advertisement(models.Model):
STATUS_CHOICES = (
('Draft', 'Draft'),
('Published', 'Published'),
)
owner = models.ForeignKey(Owner, on_delete=models.CASCADE, blank=True, null=True)
name = models.CharField(max_length=150, blank=True, null=True)
brand = models.ForeignKey(Brand, on_delete=models.CASCADE, blank=True, null=True)
publish = models.DateTimeField(default=timezone.now)
status = models.CharField(max_length=10, choices=STATUS_CHOICES, default='Draft')
...
# Other fields & methods
Any help would be greatly appreciated.
Since you need brands, let's query on Brand model:
Brand.objects.filter(advertisement__status__iexact="Published").\
filter(advertisement__owner__payment_made=True).\
annotate(published_ads=Count('advertisement__id')).\
order_by('-published_ads')
However, even in your proposed solution, you can improve a little bit:
Remove the order_by method from your queryset. It doesn't affect the final result but adds some overhead, especially if your Advertisement model is not indexed on those fields.
Every time you call ad.brand you are hitting the database. This is called the N+1 problem. You are in a loop of n, you make n extra db access. You can use select_related to avoid such problems. In your case: Advertisement.objects.select_related('brand')...
Did you try the count method?
from django.db.models import Count
Car.objects.annotate(num_views=Count('car_posts_related_name')).order_by('num_views')
I am struggling with Many-to-Many model and form. What is the best way to show extra level field when creating a new Person with skill. I am going also to edit it later.
I am trying to achieve an effect in forms like that:
[input text] name
[select] skill name (there are choices in the model)
[input text] level of the skill
I tried things which people were suggesting but I couldn't make it to work. For example inlineformset + through.
Later on, I would like also to give the user a chance to add multiple sets of skill+level, maybe it is worth to think about it in advance?
My models and form:
class PersonSkill(models.Model):
person = models.ForeignKey('Person', on_delete=models.CASCADE)
skill = models.ForeignKey('Skill', on_delete=models.CASCADE)
level = models.CharField(max_length=50, choices=[(1, 'working'),
(2, 'advanced'),
(3, 'champion')], null=True, blank=True)
class Skill(models.Model):
name = models.CharField(max_length=50, null=True, blank=True)
def __str__(self):
return self.name
class Person(models.Model):
name = models.CharField(max_length=30, null=True, blank=True)
skill = models.ManyToManyField('Skill', through='PersonSkill', blank=True)
def __str__(self):
return self.name
class PersonForm(forms.ModelForm):
class Meta:
model = Person
fields = ('name',)
I want to make an API End Point so the user can get a list of the users in his city ordered by their post reviews
I have defined a method in the post model to calculate the total review (up vote and down vote), I'm imagining that the solution can be realized in the following path but I'm not entirely sure groupBy post_owner in the post and orderBy sum(count_reactions()), but I don't know how to do it in django
Post Model
class Post(models.Model):
title = models.TextField(max_length=255, default='Title')
post_owner = models.ForeignKey(MyUser, on_delete=models.CASCADE)
description = models.TextField(max_length=255)
city = models.ForeignKey(City, related_name='location', on_delete=models.CASCADE)
longitude = models.CharField(max_length=255)
image = models.CharField(max_length=255,
default='https://www.eltis.org/sites/default/files/styles/web_quality/public/default_images/photo_default_2.png')
latitude = models.CharField(max_length=255)
created_at = models.DateTimeField(auto_now_add=True)
def count_reactions(self):
likes_count = Reaction.objects.filter(post=self.id, is_like=True).count()
dislikes_count = Reaction.objects.filter(post=self.id, is_like=False).count()
return likes_count - dislikes_count
def owner(self):
return self.post_owner
MyUser Model
class MyUser(AbstractUser):
phone_number = models.BigIntegerField(blank=False, unique=True)
city = models.ForeignKey(City, related_name='city', on_delete=models.CASCADE)
address = models.CharField(max_length=255)
def owner(self):
return self
Reaction Model
class Reaction(models.Model):
reaction_owner = models.ForeignKey(MyUser, on_delete=models.CASCADE)
post = models.ForeignKey(Post, related_name='reactions', on_delete=models.CASCADE)
is_like = models.BooleanField(null=False)
def owner(self):
return self.reaction_owner
The expected result is to get the ordered list of the users by their posts reviews but only the users in the same city (city field in MyUser model)
You can put it all into one query.
Depending on where your Reaction naming the query should look something like this:
# Filter for the city you want
users = MyUser.objects.filter(city=your_city_obj)
# Then doing the calculations
users = users.annotate(rank_point=(Count('post__reactions', filter=Q(post__reactions__is_like=True)) - (Count('post__reactions', filter=Q(post__reactions__is_like=False)))))
# And finaly, order the results
users = users.order_by('-rank_point')
The answer is Navid's answer but completing it with excluding the users with rank equal to zero and include also the limit
# Filter for the city you want
users = MyUser.objects.filter(city=your_city_obj)
# Then doing the calculations
users = users.annotate(rank_point=(Count('post__reactions', filter=Q(post__reactions__is_like=True)) - (Count('post__reactions', filter=Q(post__reactions__is_like=False))))).filter(rank_point__gt=0)
# And finaly, order the results
users = users.order_by('-rank_point')[:LIMIT]