Problem: I have Two Tables Users and Users Group and in front end on
request of that particular page need to send all data from both the
table together, as there is specific drop down to show them both, and after done with the operation of that page data will get back in POST request (current models structures is given below), i am not getting how do i make connection in all these three tables so that it will get managed, Please let me know.
Model: User.py
class Users(AbstractBaseUser):
vendor_name = models.ForeignKey(Vendor, on_delete=models.CASCADE, default=None, null=True)
username = models.CharField(max_length=100, verbose_name="username", unique=True)
password = models.CharField(max_length=100)
created_by = models.DateField(verbose_name="created_by", auto_now_add=True)
USERNAME_FIELD = "username"
REQUIRED_FIELDS = ['password', 'hardware_id']
is_active = models.BooleanField(default=True)
is_admin = models.BooleanField(default=False)
is_role_vendor = models.BooleanField(default=False)
is_role_customer = models.BooleanField(default=True)
def __str__(self):
return self.username
objects = UserManager()
Model: UserGroup.py
class UserGroup(models.Model):
vendor_id = models.ForeignKey(Vendor, on_delete=models.CASCADE, default=None, null=True)
id = models.IntegerField(primary_key=True)
name = models.CharField(max_length=100)
description = models.CharField(max_length=1000)
users = models.ManyToManyField(Users)
def __str__(self):
return self.name
Model: Rules.py
class Rules(models.Model):
vendor_id = models.ForeignKey(Vendor, on_delete=models.CASCADE, default=None, null=True)
id = models.IntegerField(primary_key=True)
name = models.CharField(max_length=100)
description = models.CharField(max_length=1000)
# Here i need to mention the code for field where i can store the combined value of User and UserGroup [selected from the dropdown].
def __str__(self):
return self.name
Need Solution:
How do i code in View to fetch the data of Two tables to send them for DropDown. {GET Request}
How will i store the values for the same together in Rules Table { As i said DropDown consist both values and can be selected all
together. }
The Structure of the Model {with the required Changes}.
there is no out of the box solution for that. I can advise to seprate this dropdown into two. First with UserGroup, second with User. You can fill user dropdown based on selected UserGroup with ajax or htmx -> htmx value-select
In your model Rules (should be Rule)
add fields:
user = models.ForeignKey(Users, on_delete=models.CASCADE)
group = models.ForeignKey(UserGroup, on_delete=models.CASCADE)
if there can be only one rule per Users(this should also be User)/UserGroup add unique_toigether to model Rules:
unique_together = ['user', 'group']
django docs unique_together
Related
I have four models in my django application with following structure:
class User(models.Model):
first_name = models.CharField()
last_name = models.CharField()
class Customer(models.Model):
kyc_record = models.ForeignKey(CustomerKYCRecord, on_delete=models.CASCADE,null=True,default=None)
user = models.ForeignKey(User, on_delete=models.CASCADE)
class SomeItem(models.Model):
price = models.DecimalField()
customer = models.ForeignKey(Customer, on_delete=models.CASCADE)
class SomeOtherItem(models.Model):
transaction_status = models.CharField(max_length=200, default='INITIATED')
some_item = models.ForeignKey(SomeItem, on_delete=models.CASCADE, unique=True)
I have to create an API and I have been given a list of SomeItem. I have to write a django queryset line to extract first_name and last_name from User model, all details of SomeItem model and all details of SomeOtherItem model(if present).
I also have to create a serializer to parse the data as a Python dict.
Will be great if one can help me in this.
views
company = Company.objects.get(id = company_id) # getting input from django urls (<int:company_id>)
vehicles = CompanyContainVehicles.objects.filter(company_id=company.id) # Give all rows having same id (company.id)
all_vehicles = Vehicle.objects.filter(companies=company) # Gives all row with id provide by company
all_vehicles_parts = VehiclePart.objects.filter(__________) # Not Working
models
class Company(models.Model):
name = models.CharField(max_length=255)
slug = models.SlugField(blank=True, null=True, unique=True)
description = models.TextField()
class Vehicle(models.Model):
vehicle_number = models.IntegerField()
name = models.CharField(max_length=255)
slug = models.SlugField(blank=True, null=True, unique=True)
companies = models.ManyToManyField(
Company,
through='CompanyVehicle',
related_name='companies'
)
class CompanyVehicle(models.Model):
company = models.ForeignKey(Company, on_delete=models.CASCADE)
vehicle = models.ForeignKey(Vehicle, on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add=True)
class VehiclePart(models.Model):
id = models.AutoField(primary_key=True)
vehicle = models.ForeignKey(Vehicle, on_delete=models.CASCADE)
type = models.ForeignKey(PartType, on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add=True, blank=True)
How do I get VehiclePart's with their Vehicle? (I think I will give all the data in a variable and we should divide it and add it with their Vehicle). Also, what can we do to access data if VehiclePart contains a child class named VehiclePartDetail?
I think I will give all the data in a variable and we should divide it and add with their Vehicle.
You don't have to. Django can read ForeignKey relations in reverse. You can query with:
qs = Vehicle.objects.prefetch_related('vehiclepart_set')
then you can enumerate over the queryset, and for each Vehicle object, access this with .vehiclepart_set.all(). For example:
for item in qs:
print(vehicle_name)
for part in item.vehiclepart_set.all():
print(part.id)
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]
I am trying to create a django membership models with 2 model classes: Target and Group.
I want to have targets attributable to certain groups, but also to be able to query which targets are in which group. This is what I have so far and I am able to see that "targets" is a field of Group but it shows up as empty in the query set when I access Group.objects.get(pk=1) through a variable. I also want both groups and targets to be attributable to certain users.
Here are my models, what am I doing wrong? I've tried doing this a few different ways so far:
class Target(models.Model):
first_name = models.CharField(max_length=50, default='Target First name')
last_name = models.CharField(max_length=50, default='Target last name')
email = models.EmailField(max_length=100, default='email#example.com')
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.DO_NOTHING)
date_time = models.DateTimeField(auto_now=True)
group = models.ForeignKey(Group, on_delete=models.DO_NOTHING, null=True, blank=True)
def __str__(self):
return self.email
def __unicode__(self):
return self.email
class Group(models.Model):
group_id = models.IntegerField(primary_key=True)
name = models.CharField(max_length=50, default='Group name')
created_date = models.DateTimeField(auto_now=True)
modified_date = models.DateTimeField(null=True, blank=True)
targets = models.ManyToManyField(Target, related_name='targets', blank=True, null=True)
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.DO_NOTHING)
def __str__(self):
return self.name
def __unicode__(self):
return self.name
You don't need both the ForeignKey and the ManyToManyField. If you just want each target to be in a single group, keep the FK but drop the M2M. Then from your group you can do mygroup.target_set.all() to get the list of targets in that group.
Consider the following database model:
class User:
id = models.BigAutoField(primary_key=True)
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
class Restaurant:
id = models.BigAutoField(primary_key=True)
title = models.CharField(max_length=50)
class Rating:
id = models.BigAutoField(primary_key=True)
by_user = models.ForeignKey(to='User',
on_delete=models.PROTECT,
related_name='written_ratings')
for_restaurant = models.ForeignKey(to='Restaurant',
on_delete=models.PROTECT,
related_name='received_ratings')
score = models.SmallIntegerField()
# make sure only one vote per user per restaurant
class Meta:
unique_together = ('by_user', 'for_restaurant')
For a given User, we can obtain a list of Restaurant that we have not yet rated by performing the following query (that I have learned from my last post)
eligible_restaurants = Restaurant.objects.exclude(rating__by_user_id=my_id)
But what happens when the Ratings don't point directly at the Restaurants - but rather at an intermediate Profile object?
class User:
id = models.BigAutoField(primary_key=True)
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
class Restaurant:
id = models.BigAutoField(primary_key=True)
title = models.CharField(max_length=50)
current_profile = models.OneToOneField(to='Profile',
on_delete=models.PROTECT,
related_name='+')
# the `+` means to not generate a related name
class Profile:
# this is here acting as an intermediate between
# `Restaurant` and `Rating` so that we can keep track
# of all reviews - deleting/remaking would simply be
# creating a new `Profile` and setting the `Restaurant`
# to point to it instead - the old one will act as a
# historical record
id = models.BigAutoField(primary_key=True)
by_restaurant = models.ForeignKey(to='Restaurant',
on_delete=models.PROTECT,
related_name='written_profiles')
picture_url = models.CharField(max_length=500)
picture_desc = models.CharField(max_length=500)
class Rating:
id = models.BigAutoField(primary_key=True)
by_user = models.ForeignKey(to='User',
on_delete=models.PROTECT,
related_name='written_ratings')
for_profile = models.ForeignKey(to='Profile',
on_delete=models.PROTECT,
related_name='received_ratings')
score = models.SmallIntegerField()
# make sure only one vote per user per restaurant
class Meta:
unique_together = ('by_user', 'for_profile')
How would I query for eligible restaurants now?
You could filter them starting with restaurants
restaurant_ids = Rating.objects.filter(by_user=user).values_list('for_profile__by_restaurant', flat=True).distinct()
eligible_restaurants = Restaurant.objects.exclude(id__in=restaurant_ids)
Note: this will generate only one query because django's querysets are lazy.