How to implement a list in a Django model?
Lets say I have a UserProfile model, and each user can have a list of mortgages (undefined quantity) defined by MortgageModel.
class MortgageModel(models.Model):
bank_name = models.CharField(max_length=128)
sum = models.BigIntegerField()
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
# list of morgtages?
my only idea is to make a old school list, where every mortgage can point to another one or null, like this:
class MortgageModel(models.Model):
bank_name = models.CharField(max_length=128)
sum = models.BigIntegerField()
next_mortgage = MortgageModel(null=True, default=null)
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
mortgages = MortgageModel(null=True, default=null)
is there any other possibility?
You'll have to assign a ForeignKey to User , so that each Mortgate 'belongs' to a user.
That is how a One-To-Many relationship is done. Then, if you want to get the list of Mortgages a user have, you'd filter them out like MortgageModel.objects.filter(related_user=user)
So, you'd have something like
Model
class MortgageModel(models.Model):
bank_name = models.CharField(max_length=128)
sum = models.BigIntegerField()
related_user = models.ForeignKey(UserProfile)
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
View
list_of_mortages = MortgageModel.objects.filter(related_user=user)
Related
I am currently working on a mobile app delivery system which involves two types of users: "Employee" and "Customer". Each type of user would have different views and permissions within the app. In addition, each type of user would their own "profile", if you will. The employee's profile purpose is mostly just to designate company roles. The customer's profile is mostly used to save an address for delivery.
I am trying to get some opinions on what the best practice to achieve something like this would be. I can't decide if its better to use AbstractBaseUser or AbstractUser.
Below is a visual of the models I want to create along with their relationship:
Below is the the user/models.py file that I mocked up:
class User(AbstractBaseUser):
USER_TYPES = (
('Employee', 'employee'),
('Customer', 'customer')
)
first_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100)
email = models.EmailField()
phone_number = models.CharField(max_length=20)
user_type = models.CharField(max_length=8, choices=USER_TYPES)
def __str__(self):
return f'{self.first_name} {self.last_name}'
# if user.user_type == 'Employee'
class EmployeeProfile(models.Model):
EMPLOYEE_ROLES = (
('Driver', 'driver'),
('Production', 'production'),
('Manager', 'manger')
)
user = models.OneToOneField(User, on_delete=models.CASCADE)
role = models.CharField(max_length=12, choices=EMPLOYEE_ROLES)
def __str__(self):
return self.user
# if user.user_type == 'Customer'
class CustomerProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
company = models.CharField(max_length=100)
address = models.CharField(max_length=100)
address_2 = models.CharField(max_length=100)
city = models.CharField(max_length=50)
state = models.CharField(max_length=2, help_text="State Abbreviation (ex: OH)")
zipcode = models.CharField(max_length=5)
def __str__(self):
return self.user
I know that I would also need to use Django signals or something similar to create a User profile (for either an employee or customer, on user creation).
Your code works
But according to the design pattern standards, it can be said to put a Boolianfield in the user named is_employee and all the information of both types of users should be in AbstractUser, but with null=True and blank=True values.
This way you have a single user with which it can be separated by a is_employee field
I hope it was useful
So I have a social media app, where users can like the posts of other users. Now I want to fetch the top 20 users who have received the most number of likes. I am pretty much confused how to query my Likes Model
My LIKES MODEL
class PostLike(models.Model):
user_who_liked = models.ForeignKey(User, on_delete=models.CASCADE)
post_liked = models.ForeignKey(Post, on_delete=models.CASCADE)
liked_on = models.DateTimeField(default=timezone.now)
SIMPLIFIED POST MODEL
class Post(models.Model):
id = models.AutoField(primary_key=True)
user = models.ForeignKey(User, on_delete=models.CASCADE)
caption = models.TextField()
date = models.DateTimeField(default=timezone.now)
likes = models.ManyToManyField(
User, blank=True, through=PostLike)
image = models.TextField()
class Meta:
ordering = ['-id']
SIMPLIFIED USER MODEL
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(unique=True)
user_name = models.CharField(max_length=100, unique=True)
date = models.DateTimeField(default=timezone.now)
profile_picture = models.TextField(
default="https://www.kindpng.com/picc/m/24-248253_user-profile-default-image-png-clipart-png-download.png")
bio = models.CharField(max_length=200, default="")
objects = CustomManger()
def __str__(self):
return self.user_name
** My View **
#api_view(["GET"])
#permission_classes([IsAuthenticated])
def leaderboard(request):
# I dont know how to query the PostLike model now to get the most liked users
pass
First I changed the user attribute in your Post model, I added related_name because otherwise the related names were clashing. This is the definition I used, otherwise your models are unchanged.
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='author')
I.e. the posts by a user are accessible on User via the author attribute.
The following query gives you the top 20 users by number of likes they received:
User.objects.annotate(num_likes=Count('author__likes')).order_by('-num_likes')[:20]
Explanation:
Query User model and
annotate each user by doing a count:
author leads to the posts by the user
likes follows to PostLike and counts all likes which are associated with a post by the user
then order by number of likes descending,
and limit the number of retrieved objects to 20.
I am getting errors while I am building the following database. Idea is that you create a Team object. Create Student Objects and link them to Teams. And then give the Students points through PointEntry objects. I want to relate the team given to each Student object in each PointEntry Object. But for some reason, Django gives the error:
score_board.Student: (fields.E336) The model is used as an intermediate model by 'score_board.PointEntry.team', but it does not have a foreign key to 'PointEntry' or 'Team'.
Modeladmin Class
class StudentAdmin(admin.ModelAdmin):
list_display = ['name', 'team']
list_filter = ['team']
class PointEntryAdmin(admin.ModelAdmin):
list_display = ['student', 'points']
list_filter = ['student']
Below are the models
class Team(models.Model):
# Team/group model
name = models.CharField(max_length=64)
class Student(models.Model):
# Student model
name = models.CharField(max_length=64)
team = models.ForeignKey(Team, on_delete=models.CASCADE)
def __str__(self):
return f"{self.name}"
class PointEntry(models.Model):
# Point entry's made by users appointed to a student in a group
student = models.OneToOneField(Student, on_delete=models.CASCADE)
points = models.IntegerField()
team = models.ManyToManyField(Team, through='Student')
Your through model needs a ForeignKey to both models. Since the model that defines the ManyToManyField is defined lower, you can not reference to the class. But in Django, you can also use a string literal:
class Student(models.Model):
name = models.CharField(max_length=64)
team = models.ForeignKey(Team, on_delete=models.CASCADE)
pointentry = models.ForeignKey('PointEntry', on_delete=models.CASCADE)
def __str__(self):
return f'{self.name}'
class PointEntry(models.Model):
# Point entry's made by users appointed to a student in a group
student = models.OneToOneField(Student, on_delete=models.CASCADE)
points = models.IntegerField()
team = models.ManyToManyField(Team, through='Student')
Django will then replace the string with a reference to the class.
class Team(models.Model):
# Team/group model
name = models.CharField(max_length=64)
student = models. models.ManyToManyField(Student,through='PointEntry ')
class Student(models.Model):
# Student model
name = models.CharField(max_length=64)
team = models. models.ManyToManyField(Team,through='PointEntry')
def __str__(self):
return f"{self.name}"
class PointEntry(models.Model):
# Point entry's made by users appointed to a student in a group
student = models. ForeignKey(Student,on_delete=models.CASCADE)
team = models. ForeignKey(Team, on_delete=models.CASCADE)
points = models.IntegerField()
I think a model like this might work for what you’re trying to achieve.
I have models of Exercise, Training and Workout.
Training contains some exercises (Exercise)
Workout contains trainings (Training).
Snippet of my models.py:
class Exercise(models.Model):
user = models.ForeignKey(User, related_name='exercises',
on_delete=models.CASCADE)
name = models.CharField(max_length=80)
description = models.TextField(max_length=300)
details = models.ManyToManyField(ExerciseDetail, blank=True)
...
class Training(models.Model):
user = models.ForeignKey(User, related_name='trainings',
on_delete=models.CASCADE)
name = models.CharField(max_length=80)
description = models.CharField(max_length=250)
exercises = models.ManyToManyField(Exercise, related_name='trainings',
blank=True)
...
class Workout(models.Model):
user = models.ForeignKey(User, related_name='workouts',
on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now=True)
name = models.CharField(max_length=200)
description = models.TextField(max_length=400, blank=True)
trainings = models.ManyToManyField(Training, related_name='workouts',
blank=True)
...
I would like to have possibility to use something like Workout.objects.get(name='workout').exercises.objects.all() to get a list/set of all exercises included in trainings of chosen Workout.
I would also like to have possibility to use exercises`` field with Django Rest Framework to list all exercises, possibly with link to particularExercise``` model serializer.
Can someone give a hint how can I do that?
You can query this with:
Exercise.objects.filter(
trainings__workouts__name='workout'
)
With the consecutive underscores (__), you thus can look "through" relations.
This will thus return the Exercises that belong to Trainings that belong to Workouts with as name 'Workout'.
I have 4 models.
class User(models.Model):
id = models.IntegerField(primary_key=True)
name = models.CharField()
class Subscription(models.Model):
user_id = models.ForeignKey(User)
title = models.CharField()
class Address(models.Model):
user_id = models.ForeignKey(User)
street = models.CharField()
class Wallet(models.Model):
user_id = models.ForeignKey(User)
balance = models.DecimalField(max_digits=6, decimal_places=2)
Here I want to get the subscription rows along with the respected user address and wallet balance. Is that possible to retrieve in a single query (ORM)?
I heard about select_related() and prefetch_related(). But not sure how to put all together in a single queryset.
How can I achieve this in pythonic way?
Have you tried to follow this snippet from documentation?
Having a User object instance you can do something like this to access subscriptions:
user.subscription_set.all()
It will require separate calls to different managers to collect all your data though.
First of all remove _id from FK fields. You'll still have subscription.user_id (int) and subscription.user which is User. Right now you have to write subscription.user_id_id for accessing id.
Do you understand that user can have multiple wallets and addresses with you db design?
It is not possible to do it in a single query with ORM. But it is possible to do it in 3 queries (doesn't matter how many records).
UPDATED:
class User(models.Model):
name = models.CharField()
class Subscription(models.Model):
user = models.ForeignKey(User, related_name='subscriptions')
title = models.CharField()
class Address(models.Model):
user = models.ForeignKey(User, related_name='addresses')
street = models.CharField()
class Wallet(models.Model):
user = models.ForeignKey(User, related_name='wallets')
balance = models.DecimalField(max_digits=6, decimal_places=2)
subscriptions = Subscription.objects.select_related('user').prefetch_related(
'user__wallets', 'user__addresses')
for s in subscriptions:
print(s.user.name)
for wallet in s.user.wallets.all():
print(wallet.balance)
for address in s.user.addresses.all():
print(address.street)