Trying to craft a relationship like so:
The combination of user/address can only have one rating, where an address is part of a building which is also a foreign key on the rating.
At the moment I have this:
class Rating(models.Model):
buildingaddress = select2.fields.ForeignKey(BuildingAddress, overlay='Select the Building Address')
building = select2.fields.ForeignKey(Building, db_column='bin', null=True, overlay='Select your Building')
author = select2.fields.ForeignKey(User, overlay='Select the Author')
suggestion = models.TextField()
rating = models.IntegerField(null=True, blank=True)
This doesn't work correctly at the moment, because it allows multiple ratings per user per address.
you can add a unique_together constraint to make it so every address and user combination has to be unique
https://docs.djangoproject.com/en/dev/ref/models/options/#unique-together
unique_together = ('buildingaddress', 'author')
Related
I have two models
class Customer(models.Model):
name = models.CharField(max_length=255, unique=True)
default_contact = models.ForeignKey("CustomerContact", verbose_name="...", related_name="default_contacts", null=True, on_delete=models.SET_NULL)
etc.
And
class CustomerContact(models.Model):
customer = models.ForeignKey(Customer, related_name='contacts')
user = models.OneToOneField(User, related_name='user_contacts', on_delete=models.SET_NULL)
address = models.ForeignKey(CustomerAddress, ....)
In this example Customer points to CustomerContact.
At the same time CustomerContact points to Customer.
My coworker says that pointing Customer points to CustomerContact violates the OneToMany nature of ForeignKey.
What am I doing wrong?
As I can see you want to have many CustomerContact related to one Customer, but Customer can also pick his favourite (or one can be set by manager). It's valid approach.
It can go both ways, as long as you will secure related_names properly.
default_contact = models.ForeignKey("CustomerContact", ... related_name="default_contacts") <= should be changed
default_contacts should be changed (i.e. to default_for_customers) because this name is for reversed relation, so actually for CustomerContact. It means, that you can use it in the following situation:
cc = CustomerContact.objects.get(id=1)
cc.default_for_customers.all() <= this will return QuerySet of Customer objects that is default for
It's simplier and less confusing.
I have been struggling with grasping relations for some time and would be very grateful if someone can help me out on this issue.
I have a relation that connects the User model to a ProcessInfo model via one to many and then I have a relation that connects the ProcessInfo to the ProcessAssumptions as One to one
Is there a way to use the User id to get all ProcessAssumptions related to all processes from that user.
I would like to retrieve a queryset of all ProcessAssumptions related to a user id
Here is the model relation :
class ProcessInfo(models.Model):
process_name = models.CharField(max_length=120, null=True)
user_rel = models.ForeignKey(User, null=True, on_delete=models.SET_NULL)
class ProcessAssumptions(models.Model):
completion_time = models.FloatField(default='0')
process_rel_process = models.OneToOneField(ProcessInfo, primary_key = True, on_delete=models.CASCADE)
Using field referencing for foreign keys.
process_assumption_objects = ProcessAssumptions.objects.filter(process_rel_process__user_rel=<user_id>)
Replace <user_id> with the id you wish to query for.
When you define a relationship to model X in another model Y, all related Ys can be accessed from an instance of X by X_instance.Y_set.all(). You can even perform the regular filter or get operations on that. X_instance.Y_set is the default object manager for Y (same as Y.objects), but it's filtered to only contain the objects that are related to X_instance.
So in this specific case, you can get all ProcessInfo objects for a certain user like this:
user = User.objects.get(the_user_id)
required_assumptions = [proc_info.process_assumptions for proc_info in user.process_info_set.all()]
This might be a bit hard to read with _set suffix, so you can define a related_name argument while defining the relation on the model.
like:
# in class ProcessInfo
user_rel = models.ForeignKey(User, null=True, on_delete=models.SET_NULL, related_name='processes')
# and now you can do
some_user.processes.all()
I apologize if that question was raised before. But I have been struggling with this for weeks and couldn't find anything useful.
I have the following problem (it is simplified a lot but essentially my problem is presented)
I have a Model that has a lot of fields. It's called
class DocAide(models.Model):
id = models.AutoField(primary_key=True)
pulse = models.DecimalField('Pulse', max_digits=3, decimal_places=0)
weight = models.DecimalField('Weight (kg)', max_digits=3, decimal_places=0)
bp_sys = models.DecimalField('BP Sys', max_digits=3, decimal_places=0)
bp_dia = models.DecimalField('BP Dia', max_digits=3, decimal_places=0)
temperature = models.DecimalField('Temp. deg C', max_digits=2, decimal_places=1)
drugs = models.ManyToManyField(Drug, blank=True)
date = models.DateField(editable=False, default=timezone.now)
doctors_notes = models.TextField('Patient is complaining about:', default='')
note = models.TextField(max_length=100, default='')
The ForeignKey Drugs has Names of drugs with quantity I would like to have the possibility to select multiple drugs but with edit fields that show what dosage needs to be taken and when, it should be like a prescription. The Model looks like this:
class Drug(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=100, default='')
QUANTITY_STR = ['Bottle', 'Tablet' 'Injection', 'Capsules', 'other']
QUANTITY = ((str, str) for str in QUANTITY_STR)
quantity = models.CharField(max_length=2, choices=QUANTITY, default='Bottle')
category = models.CharField(max_length=150, default='')
strength = models.CharField(max_length=150, default='')
in_supply_stock = models.PositiveIntegerField(default=0)
in_main_stock = models.PositiveIntegerField(default=0)
date = models.DateField(editable=False, default=timezone.now)
charge = models.PositiveIntegerField(default=0)
morning = models.CharField(validators=[int_list_validator], max_length=3, default=0)
midday = models.CharField(validators=[int_list_validator], max_length=3, default=0)
evening = models.CharField(validators=[int_list_validator], max_length=3, default=0)
night = models.CharField(validators=[int_list_validator], max_length=3, default=0)
days = models.CharField(validators=[int_list_validator], max_length=3, default=0)
tablets = models.CharField(validators=[int_list_validator], max_length=3, default=0)
How can I accomplish that in a form or template. I tried with Inlineformset it doesn't work. Also later I would like to have them preselected as well.
But for now I would like to have a button that produces a line with a dropdown list of the drugs and the edit fields of the model.
Thank you in advance.
As others have said, a Drug object should not have a quantity associated with it, but a prescription "entry" should.
I think this is the Model structure you need:
QUANTITY_STR = ['Bottle', 'Tablet' 'Injection', 'Capsules', 'other']
class DocAide(models.Model):
# same properties but remove `drugs` from this model
class Drug(models.Model):
# same properties but remove `quantity` property
class Prescription(model.Model):
drug = model.ForeignKey(to=Drug, related_name='prescriptions')
doc_aide = model.ForeignKey(to=DocAide, related_name='prescriptions')
quantity = models.IntegerField()
qty_container = models.CharField(max_length=10, choices=QUANTITY_STR, default=QUANTITY_STR[0])
I changed a few things for you assuming I understood your business logic correctly. Such as how the quantity field works.
I created two fields to describe the quantity. quantity holds the numerical value, and qty_container holds the container's name if you will, like "Bottle", "Injection" and so on.
qty_container has a max_length equal to the number of characters in the word "Injection" since it is the largest word that might fit in this field. You had the default of that field be greater than the max_length which would cause an error.
Now I'm not sure why you wanted to save a tuple of two strings in the quantity field so I ignored that, but if you can comment on your intended logic here I might be able to edit the answer.
Anyway, the Prescription model.
This model will act as an intermediary between Drug and DocAide, and it is the one that will hold the quantity information. I've linked it with Drug and DocAide using foreign keys and set the related_name to suitable names. These "related_names" you'll find show up in the referenced model. So for example if you can do
doc_aide = DocAide.objects.get(pk=1)
for presc in doc_aide.prescriptions:
print(presc.drug.name)
print(presc.quantity)
This means that one DocAide object will be linked with one or many Prescription objects, each of those holds quantity info and is linked with a Drug object:
DocAide (id, etc) >> Prescription (doc_aide_id, drug_id, qty_info) >> Drug (id, etc)
As a side note, after you're sure everything works and you're good to go, you might need to look into query optimization in Django, because as it is written now, it's pretty unoptimized. But don't worry about optimization until you've finished and your code works correctly.
You likely want to move some fields of your Drug model to an intermediary one that defines a foreign key to both your Drug and DocAide models.
This model should then be used as the through option of your DocAide.drugs field.
If you are using the admin you'll be able to rely on inlines to display an input form that allows selecting the desired Drug and annotating extra fields otherwise you'll likely have to build your own mechanism that relies on ModelFormSet.
I have 4 models -
class Group(models.model):
group_id = models.CharField(max_length=10)
name = models.CharField(max_length=20)
class User(models.model):
user_id = models.CharField(max_length=10)
grp = models.ForeignKey(Group, null=True, blank=True)
user_name = models.CharField(max_length=50)
contact_no = models.CharField(max_length=20)
class DesigType(models.model):
desig_name = models.CharField(max_length=10)
class Designation(models.model):
user = models.ForeignKey(User, null=True, blank=True, related_name='desigs')
desig_type = models.ForeignKey(DesigType, null=True, blank=True, related_name='desigs')
Group model holds groups of users. User holds records for each individual user. DesigType has information about "type of designation", like maybe manager, team lead etc. Designation stores the exact designation - for example, for manager DesigType, Designation might have project manager or account manager; similarly, for team lead DesigType, Designation might have front-end lead or back-end lead.
The UI currently shows a list of users under a group. I want to implement a search functionality according to desig_name. The UI sends me the group_id and the text entered by the end-user in the search box, and I have to return only those Users which have the corresponding desig_name.
I have already done the above, by using a property to return a list of desig_names that a User has and checking whether the user input exists in the list.
This is a property under User -
#cached_property
def desig_types(self):
desig_types = []
for value in self.desigs.select_related('desig_type').values('desig_type__desig_name'):
desig_types.append(value['desig_type__desig_name'])
return desig_types
In my view I have a generic search function which takes any user filter to return the appropriate list of users.
group = Groups.objects.get(pk=grp_id)
_queryset = group.user_set.filter(**user_filter)
The above code works for filtering according to contact_no and user_name. For contact_no, **user_filter is group.user_set.filter(contact_no=user_input), and for user_name, it's group.user_set.filter(user_name=user_input). I want it to also work for filtering according to desig_name, but I couldn't figure out how to navigate through the relationships so I wrote the code below, that retrieves a list of user_ids which have the user inputted desig_name.
required_users = []
for user in group.user_set.all():
user_desig_names = user.desig_types
if user_input in user_desig_names:
required_users.append(user.user_id)
return required_users
I then pass in the filter as group.user_set.filter(user_id__in=required_users). But as you see, I have to have an additional code to get the user_ids, instead of directly using **user_filter, like with user_name or contact_no.
Does anyone know how I can do that?
I know that filtering by property is not possible with Django, as filtering is done at database level and properties live in Python code. However, I have the following scenario:
In one hand, I have the model RegisteredUser on the other hand Subscription. A user can have multiple subscriptions, a subscription is from one user and a user has one or none active subscriptions.
To implement this, I have a foreign key from Subscription to RegisteredUser and a property subscription at RegisteredUser that points to the active one (latest created subscription for that user) or none if he hasn't any subscriptions.
Which would be the most efficent way to filter users that have subscription "platinum", "gold", "silver"...? I could do a "fetch all subscriptions" and then iterate over them to check each one for a match. But it would be really expensive and if I have to do the same process for each kind of subscription type, then cost would be s * u (where s is the number of different subscriptions and u is the number of users).
Any help will be appreciated. Thanks in advance!
UPDATE:
When I first explained the problem, I didn't include all the models related to
simplify a litte. But as you are asking me for the models and some of you haven't understood me
(perhaps I wasn't clear enough) here you have the code.
I've simplified the models and stripped out code that is not important now.
What do I have here? A RegisteredUser can have many subscriptions (because he may change it
as many times as he wants), and a subscription is from just one user. The user has only
one current subscription, which is the latest one and is returned by the property
subscription. Subscription is attached with Membership and this is the model whose
slug can be: platinum, gold, silver, etc.
What do I need? I need to lookup Content whose author has a specific kind of membership.
If the property approach worked, I'd have done it like this:
Content.objects.filter(author__id__in=RegisteredUser.objects.filter(
subscription__membership__slug="gold"))
But I can't do this because properties can't be used when filtering!
I thought that I could solve the problem converting the "virtual" relation created by
the property into a real ForeignKey, but this may cause side effects, as I should update it manually each time a user changes its subscription and now it's automatic! Any better ideas?
Thanks so much!
class RegisteredUser(AbstractUser):
birthdate = models.DateField(_("Birthdate"), blank=True, null=True)
phone_number = models.CharField(_("Phone number"), max_length=9, blank=True, default="")
#property
def subscription(self):
try:
return self.subscriptions_set.filter(active=True).order_by("-date_joined",
"-created")[0]
except IndexError:
return None
class Subscription(models.Model):
date_joined = models.DateField(_("Date joined"), default=timezone.now)
date_canceled = models.DateField(_("Date canceled"), blank=True, null=True)
subscriber = models.ForeignKey(AUTH_USER_MODEL, verbose_name=_("Subscriber"),
related_name="subscriptions_set")
membership = models.ForeignKey(Membership, verbose_name=_("Membership"),
related_name="subscriptions_set")
created = models.DateTimeField(_("Created"), auto_now_add=True)
last_updated = models.DateTimeField(_("Last updated"), auto_now=True)
active = models.BooleanField(_("Active"), default=True)
class Membership(models.Model):
name = models.CharField(_("Name"), max_length=15)
slug = models.SlugField(_("Slug"), max_length=15, unique=True)
price = models.DecimalField(_("Price"), max_digits=6, decimal_places=2)
recurring = models.BooleanField(_("Recurring"))
duration = models.PositiveSmallIntegerField(_("Duration months"))
class Content(models.Model):
author = models.ForeignKey(AUTH_USER_MODEL, verbose_name=_("Author"),
related_name="contents_set")
title = models.CharField(_("Title"), max_length=50)
slug = models.SlugField(_("Slug"), max_length=70, unique=True)
content = RichTextField(_("Content"))
date = models.DateField(_("Date"), default=timezone.now)
published = models.BooleanField(_("Published"))
Finally, to solve the problem I replaced the subscription property by a real foreign key and added a signal to attach the RegisteredUser with the created subscription.
Foreign key:
subscription = models.ForeignKey(Subscription, verbose_name=_("Subscription"),
related_name='subscriber_set', blank=True, null=True)
Signal:
#receiver(post_save, sender=Subscription)
def signal_subscription_post_save(sender, instance, created, **kwargs):
if created:
instance.subscriber.subscription = instance
instance.subscriber.save()
I think you model are something like:
KIND = (("p", "platinum"), ("g","gold"), ("s","silver"),)
class RegisteredUser(models.Model):
# Fields....
class Subscription(models.Model):
kind = models.CharField(choices=KIND, max_len=2)
user = models.ForeignKey(RegisteredUser, related_name="subscriptions")
Now, you can do something like that:
gold_users = RegisteredUser.objects.filter(subscriptions_kind="g")
silver_users = RegisteredUser.objects.filter(subscriptions_kind="s")
platinum_users = RegisteredUser.objects.filter(subscriptions_kind="p")
Adapt it to your models
Hope helps
EDIT
Now, With your models, I think you want something like:
content_of_golden_users = Content.objects.filter(author__subscriptions_set__membership__slug="golden")
content_of_silver_users = Content.objects.filter(author__subscriptions_set__membership__slug="silver")
content_of_platinum_users = Content.objects.filter(author__subscriptions_set__membership__slug="platinum")