Update multiple fields of member of an instance simultaneously - django

Suppose I have a User model and this model
class modelEmployer(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, null=True, blank=True)
employer_image = models.ImageField(upload_to='images/', default='')
Now suppose i have an instance of modelEmployer and I would like to update the content of the user object in it. I know I can do this
instance.user.email = new value
instance.first_name = new value
instance.save()
I read we can run an update on a queryset (even if it returns one object). Now suppose I have a dictionary like this
dict = {"first_name : "John","last_name" : "deer",....}
How can i do something like this
modelEmployer.object.filter(instance.user.email=dict["email"]).update(only update the user objects as I would like to update the user object of this field using directly the dictionary. Any suggestions ?

You can use explicitly mention the relation and do it,
dict = {"user__first_name" : "John","user__last_name" : "deer",....}
And in the ORM, do as
modelEmployer.object.filter(instance.user.email=dict["email"]).update(**dict)
Hope this will solve your issue

Related

Django - Create custom PrimaryKey with selected ForeignKey object

Problem:
I want to create a custom-PrimaryKey in ItemCode Model contain with selected-ForeignKey object. So, It's gonna change the custom-PrimaryKey every time submit a new ForeignKey field.
Here's my Model:
class ItemCategory(models.Model):
idItemCat = models.CharField(primary_key=True max_length=5)
nameCategory = models.CharField(max_length=150)
class ItemCode(models.Model):
idItemCode = models.CharField(primary_key=True, editable=False, max_length=20)
idItemCat = models.ForeignKey(ItemCategory, on_delete=models.DO_NOTHING)
To illustrate, here's the example of custom-PrimaryKey I wanna create: MN.202203.001
MN means Monitor from selected-ForeignKey object
Then, it change every time I submit new ForeignKey field, like this: CM.202203.002
CM means Camera from new selected-ForeignKey object
What I've tried:
I've tried to using request method but I don't know how to implemented it in my Model.
def CustomPK(request):
if request.method == 'POST':
category = ItemCategory.objects.get(pk=request.POST.get('idItemCat'))
return category
Question:
Is there anyway to get or fetch the object from selected-ForeignKey field to make a custom-PrimaryKey with request method? or is there any better way to do it?
If my question isn't clear enough, please let me know...

Django: How to create a queryset from a model relationship?

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()

ValueError: Cannot use Queryset for "": Use a Queryset for ""

I'm working on a little project using these models here and I'm trying to figure out a way to get a set of all the posts associated with users the currently authenticated user is following.
But I keep getting:
Cannot use QuerySet for "Profile": Use a QuerySet for "User".
class Profile(models.Model):
user = models.OneToOneField(User)
isInstructor = models.BooleanField(default=False)
isTutor = models.BooleanField(default=False)
isStudent = models.BooleanField(default=False)
isAdmin = models.BooleanField(default=False)
following = models.ManyToManyField('self', related_name = "followers", blank=True, symmetrical=False)
profile_image = ImageField(upload_to=get_image_path, blank=True, null=True)
class Post(models.Model):
title = models.CharField(max_length=100)
topic = models.CharField(max_length=50)
description = models.CharField(max_length=1200)
poster = models.ForeignKey(User, related_name="posts")
likes = models.IntegerField(default=0)
created = models.DateTimeField(auto_now_add=True)
tags = models.ManyToManyField(Tag, blank=True, related_name="posts")
def __str__(self):
return self.title
This is what keeps giving me the error.
current_user = Profile.objects.get(user = self.request.user)
Post.objects.filter(poster__in = current_user.following.all())
I searched around an found out that I had to use the __in operator whenever you want to filter by a list of things. But I keep getting the same error. Any help with explaining what the error means and what I can do to get around it would be much appreciated.
Maybe try something like this,
Post.objects.filter(poster__id__in=current_user.following.all().values_list('user_id'))
profile class is different to the user class. Therefore, the Profile instance is different to User's instance.
Instead of use current_user you need to use current_user.user.
You can check the documentation.
This is old, but I do not see a clear explanation of the error yet.
Consider this:
Post.poster is a foreign key to the User model.
current_user is a Profile object, not, as the name would suggest, a User object.
Profile.following is a m2m relation back to Profile, so it represents a Profile queryset.
Thus, when you filter on poster__in=current_user.following.all(), you're actually trying to compare a User with a Profile queryset.
This cannot be done, and Django is telling you exactly that:
Cannot use QuerySet for "Profile": Use a QuerySet for "User".
To fix this, you should provide a User queryset in the filter, e.g. something similar to zaidfazil's answer:
current_user_profile = Profile.objects.get(user=self.request.user)
Post.objects.filter(
poster__in=current_user_profile.following.values('user_id')
)
Or do something like this: https://stackoverflow.com/a/67247647
This does not answer the original post, but may help people who end up here based on the title:
A similar error message can also arise when your lookup refers to a reverse relation using '<fieldname>_set'.
For example, if a Bar model has a foreign key to a Foo model, then Foo will get a default related manager called Foo.bar_set. However, a lookup attempt like foo__bar_set__in=... would yield the following error:
ValueError: Cannot use QuerySet for "Bar": Use a QuerySet for "Foo".
This can be fixed by removing the _set from the lookup, so foo__bar_set__in=... should actually be foo__bar__in=....

Creating and saving non-empty Django model instance as part of subclass instance

I am experiencing a very strange behavior inconsistent with the Django documentation while creating and saving (inserting into DB) model instance. I've already run out of ideas for possible reason and will be very grateful for any suggestions why Django fails to save all fields in these cases.
This class I am using:
class Person(models.Model):
user = models.ForeignKey(User)
phone_number = models.CharField(max_length=20, blank=True)
address = models.CharField(max_length=200, blank=True)
And here's code that does't work, few cases:
# First Case
new_person = Person()
new_person.user = request.user
new_person.phone_number = '111111'
new_person.save(force_insert=True)
# Second One
new_person = Person(user=request.user, phone_number='111111')
new_person.save(force_insert=True)
# Third One
new_person = Person.objects.create(user=request.user, phone_number='111111')
Basing on official Django docs in any case django should create an object and insert it into DB.
In fact the object is successfully created (and all relevant fields are set), but row inserted into DB has only id and user_id fields filled correctly while phone_number field that was also set, remains blank.
There is, however, no problem to access and update all fields of existing (saved earlier) objects.
Removing blank=True from Person class declaration (with proper table alteration) does't change anything.
EDIT:
Problem turned out to be more sophisticated. Full description and solution in my own answer beneath
Ok, I found an explanation....
It has something to do with inheritance, namely further in the code I wanted to create instance of Person's subclass. So there was another class:
class Person(models.Model):
user = models.ForeignKey(User)
phone_number = models.CharField(max_length=20, blank=True)
address = models.CharField(max_length=200, blank=True)
class ConnectedPerson(Person):
connection = models.ForeignKey(AnotherClass)
# etc..
And after creating instance of Person, intending to extend it to ConnectedPerson I made such code:
#creating instance of Person:
person = Person(user=request.user, phone_number='111111')
person.save(force_insert=True)
c_person = ConnectedPerson(id=person.id, connection=instance_of_another_c)
and using ConnectedPerson(id=person.id) was in fact killing previously created Person instance by overwritting it in the DB.
So for anyone not too much experienced in managing inheriting instances: if you need to use earlier created super class instance as part of subclass instance do it this way:
#creating person but not saving it
person = Person(user=request.user, phone_number='111111')
######
#later
######
#creating subclass instance and saving
c_person = ConnectedPerson(user=request.user, connection=instance_of_another_c)
c_person.save()
#saving super class instance as part of subclass instance
person.pk = super(ConnectedPerson, c_person).pk
person.save()

How do you set the initial value for a ManyToMany field in django?

I am using a ModelForm to create a form, and I have gotten the initial values set for every field in the form except for the one that is a ManyToMany field.
I understand that I need to give it a list, but I can't get it to work. My code in my view right now is:
userProfile = request.user.get_profile()
employer = userProfile.employer
bar_memberships = userProfile.barmembership.all()
profileForm = ProfileForm(
initial = {'employer': employer, 'barmembership' : bar_memberships})
But that doesn't work. Am I missing something here?
Per request in the comments, here's the relevant parts of my model:
# a class where bar memberships are held and handled.
class BarMembership(models.Model):
barMembershipUUID = models.AutoField("a unique ID for each bar membership",
primary_key=True)
barMembership = USStateField("the two letter state abbreviation of a bar membership")
def __unicode__(self):
return self.get_barMembership_display()
class Meta:
verbose_name = "bar membership"
db_table = "BarMembership"
ordering = ["barMembership"]
And the user profile that's being extended:
# a class to extend the User class with the fields we need.
class UserProfile(models.Model):
userProfileUUID = models.AutoField("a unique ID for each user profile",
primary_key=True)
user = models.ForeignKey(User,
verbose_name="the user this model extends",
unique=True)
employer = models.CharField("the user's employer",
max_length=100,
blank=True)
barmembership = models.ManyToManyField(BarMembership,
verbose_name="the bar memberships held by the user",
blank=True,
null=True)
Hope this helps.
OK, I finally figured this out. Good lord, sometimes the solutions are way too easy.
I need to be doing:
profileForm = ProfileForm(instance = userProfile)
I made that change, and now everything works.
Although the answer by mlissner might work in some cases, I do not think it is what you want. The keyword "instance" is meant for updating an existing record.
Referring to your attempt to use the keyword "initial", just change the line to:
bar_memberships = userProfile.barmembership.all().values_list('pk', flat=True)
I have not tested this with your code, but I use something similar in my code and it works.