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.
Related
I have the Account model were I store information about preferred units.
However I also want to allow user to change the units for particular exercise which by default should be Account.units.
Here are my models:
class Account(models.Model):
"""Model to store user's data and preferences."""
UNIT_CHOICES = [
('metric', 'Metric'),
('imperial', 'Imperial')
]
uuid = models.UUIDField(default=uuid.uuid4, unique=True, primary_key=True, editable=False)
created = models.DateTimeField(auto_now_add=True)
owner = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, null=True, blank=False)
units = models.CharField(max_length=255, choices=UNIT_CHOICES, default=UNIT_CHOICES[0], null=False, blank=False)
weight_metric = models.FloatField(null=True, blank=True)
height_metric = models.FloatField(null=True, blank=True)
weight_imperial = models.FloatField(null=True, blank=True)
height_imperial = models.FloatField(null=True, blank=True)
def __str__(self):
return self.owner.email
class CustomExercise(models.Model):
UNIT_CHOICES = [
('metric', 'Metric'),
('imperial', 'Imperial')
]
uuid = models.UUIDField(default=uuid.uuid4, unique=True, primary_key=True, editable=False)
created = models.DateTimeField(auto_now_add=True)
owner = models.ForeignKey(Account, on_delete=models.CASCADE, null=False, blank=False)
preferred_units = models.CharField(max_length=255, choices=UNIT_CHOICES, default=owner.units, null=False, blank=False) # <- throws an error that "ForeignKey doesn't have units attribute."
name = models.CharField(max_length=255, null=False, blank=False)
measure_time = models.BooleanField(default=False)
measure_distance = models.BooleanField(default=False)
measure_weight = models.BooleanField(default=False)
measure_reps = models.BooleanField(default=False)
def __str__(self):
return f'{self.owner}:{self.name}'
As posted in code sample I tried to get that default value from ForeignKey, which not unexpectedly did not work out.
So my question is: what is the correct solution to implement this kind of feature?
I would not recommend storing duplicate values accross multiple models. You can easily access that value through a property method:
class CustomExercise(models.Model):
... # remove preferred_units field from model
#property
def preferred_units(self):
return self.owner.unit
Although you can not use it in queryset directly, still you can annotate the 'owner__unit' field in queryset or filter by it:
q = CustomExcercise.objects.annotate(preferred_units=F('owner__unit')).filter(preferred_units = 'kg')
q.values()
Displaying the value in Adminsite:
class CustomExerciseAdmin(admin.ModelAdmin):
fields = (..., 'preferred_units')
readonly_fields = ['preferred_units']
Two ways come to mind: overriding the model's save method or by using a pre_save signal. I would try the first one and if it doesn't work then the second one. The reason is that signals are notoriously difficult to debug so if you have alternatives you should always leave them as a last resort.
Ok so, I think this should work:
def save(self, *args, **kwargs):
self.preferred_units = self.owner.units
super(CustomExercise, self).save(*args, **kwargs
Otherwise:
#receiver(pre_save, sender=CustomExercise)
def assign_unit(sender, instance, **kwargs):
instance.preferred_units = instance.owner.units
The convention is to store your signals in signals.py in your app. Make sure to "activate" them from apps.py or they won't work. Here the docs.
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
I am having 4 models linked with a foreign key,
class CustomUser(AbstractUser):
username = None
email = models.EmailField(('email address'), unique=True)
phone_no = models.CharField(max_length=255, unique=True)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
objects = CustomUserManager()
def __str__(self):
return self.email
class personal_profile(models.Model):
custom_user = models.ForeignKey(CustomUser, on_delete=models.CASCADE)
picture = models.ImageField(default='profile_image/pro.png', upload_to='profile_image', blank=True)
role = models.CharField(max_length=255, blank=True, null=True)
gender = models.CharField(max_length=255, blank=True, null=True)
date_of_birth = models.DateField(blank=True, null=True)
def __str__(self):
return str(self.pk)
class academia_profile(models.Model):
custom_user = models.ForeignKey(CustomUser, on_delete=models.CASCADE)
education_or_certificate = models.CharField(max_length=255, blank=True, null=True)
university = models.CharField(max_length=255, blank=True, null=True)
def __str__(self):
return str(self.pk)
class contact_profile(models.Model):
custom_user = models.ForeignKey(CustomUser, on_delete=models.CASCADE)
country = models.CharField(max_length=255, blank=True, null=True)
state = models.CharField(max_length=255, blank=True, null=True)
city = models.CharField(max_length=255, blank=True, null=True)
def __str__(self):
return str(self.pk)
For extracting the data of those four models, I need to extract it by querying 4 times differently and then by passsing for different variables to HTML templates it something a hectic plus would be reducing the performance speed (I am sure!)
My current queries be like
user_base = CustomUser.objects.get(id=user_id)
user_personal = personal_profile.objects.get(custom_user=user_id)
academia = academia_profile.objects.get(custom_user=user_id)
contact = contact_profile.objects.get(custom_user=user_id)
Is it possible to get all of the four queries values in a single variable by hitting a single join query in ORM ?
also, I want to extract just the country from contact_profile and picture from personal_profile in the join query.
Select_related() can able to work here but how? that's what I am not getting.
You are looking for prefetch_related:
Returns a QuerySet that will automatically retrieve, in a single batch, related objects for each of the specified lookups.
user_base = (
CustomUser
.objects
.prefetch_related( #<-- THIS!
"personal_profile_set",
"academia_profile_set",
"contact_profile_set")
.get(id=user_id))
personal_profile = user_base.personal_profile_set.all()[0]
academia_profile = user_base.academia_profile_set.all()[0]
contact_profile = user_base.contact_profile_set.all()[0]
Btw, if you have only one personal_profile, academia_profile, contact_profile per CustomUser, consider changing ForeignKey by OneToOneField and use select_related.
I'm struggling getting the right query for my project. Here is an example of my model :
from django.db import models
class Product_Category(models.Model):
name = models.CharField(max_length=30, unique=True)
handle = models.SlugField(max_length=30, unique=True, null=True, blank=True)
collection = models.CharField(max_length=30, null=True)
def __unicode__(self):
return self.name
class Product(models.Model):
product_id = models.SlugField(unique=True)
name = models.CharField(max_length=100)
collections = models.ManyToManyField('Collection')
category = models.ForeignKey(Product_Category, on_delete=models.SET_NULL, blank=True, null=True)
def __unicode__(self):
return self.product_id
I am trying to get all the product_id based on the value of the Product_Category.collection.
Eg: books is a Product_category.collection, I want to get all the products for books collection.
I tried __ method also. Somehow it is not working.
The double underscore is the way to go.
books = Product.objects.filter(category__collection='books')
What I'd like to be able to do is similar to this pseudo-code - I'm just completely unaware of how to do this in python:
user_groups = request.user.participant_groups.all()
if group in user_groups not in self.object.settings.groups.all():
Basically, I'd like to check if any of the objects in user_groups are in self.object.settings.groups.all(). Is there a simple way to do this?
Models:
class Group(models.Model):
participants = models.ManyToManyField('auth.User', null=True, blank=True, related_name='participant_groups')
title = models.CharField(max_length=180)
date = models.DateTimeField(null=True, blank=True, editable=False)
modified = models.DateTimeField(null=True, blank=True, editable=False)
class Settings(models.Model):
user = models.ForeignKey('auth.User', related_name='settings_objects')
groups = models.ManyToManyField('groups.Group', null=True, blank=True)
participants = models.ManyToManyField('auth.User', null=True, blank=True, related_name='accessible_objects')
private = models.BooleanField(default=True)
What I'm trying to do is check if any of a user's participant_groups (reverse relation to user on group model) are in a settings objects groups manytomany relation.
Try this -
common_groups = user.participant_groups.annotate(
num_settings=Count('settings_objects')
).filter(num_settings__gt=0)
# You can get a count like this
count_of_above = common_groups.count()
I'm assuming self.object.settings is an instance of Settings for the current user. You should make it clear.