Django ORM get all many-to-many fields of an instance - python

I have a model Project, which has m2m relationship with Category, Specialty, Competitor.
I have an instance of this model Project. I can get all the fields of the model using
Fields of model
object._meta.fields
This gives me the all the fields in the model; I just iterate over these can check if something is updated by the user or not.
I also want to know what ManyToMany relations this object has rather than Statically calling all project.category_set.all()
I want to know, if there is any way that i can get a list of all these relation and iterate over them and get they values of these?
AIM
Check if the data in ManyToMany relations have updated by the user or not specific to this instance.
Code
def save(self, request, instance):
project = super(RequestForm, self).save(commit=False)
project.competitor.all() # Gives the list which is in data base (not new list form the form values.
project.save()
project.instance.save_m2m()
project.competitor.all() # Gives the list which is in data base (With the changing have been made.
How to check if the Competitor data has been updated.

Related

Django: Automatically selecting related model UserProfile when retrieving User model

When showing {{ user }} in a Django template, the default behavior is to show the username, i.e. user.username.
I'm changing this to show the user's initials instead, which are stored in a separate (OneToOneField) UserProfile model.
So in customsignup/models.py I've overridden the __unicode__ function successfully, with the desired result:
# __unicode__-function overridden.
def show_userprofile_initials(self):
return self.userprofile.initials
User.__unicode__ = show_userprofile_initials
But of course, the database is hit again because it needs to independently select the UserProfile model every time a user object is asked to show itself as a string. So even though this works, it escalates the number of database hits quite a bit.
So what I'd like to do, is to automatically use select_related('userprofile') whenever a User model is called from the database, seeing that I will essentially always want the profile when dealing with the user in the first place.
In more technical terms, I'm attempting to override the model manager of an existing model. So I'm in no control over the User model definition itself, since that's in an imported library.
So I've tried overriding the objects member of the User model in the same way that I overrode the __unicode__ function, like so:
# A model manager for automatically selecting the related userprofile-table
# when selecting from user-table.
class UserManager(models.Manager):
def get_queryset(self):
# Testing indicates that code here will NOT run.
return super(UserManager, self).get_queryset().select_related('userprofile')
User.objects = UserManager()
Is this supposed to work? If so, what am I getting wrong?
(I will mark an answer as correct if it can show that this is not supposed to work in the first place.)
A similar question I've found is here, but it's approached from the other end:
Automatically select related for OneToOne field
No, User.objects = MyManger() is not supposed to work. According to the docs, there are just two supported methods for extending the provided auth User model, either a profile model, as you are doing, or a proxy model, which probably doesn't fit your case. From the docs (emphasis added):
There are two ways to extend the default User model without substituting your own model. If the changes you need are purely behavioral, and don’t require any change to what is stored in the database, you can create a proxy model based on User. This allows for any of the features offered by proxy models including default ordering, custom managers, or custom model methods.
If you wish to store information related to User, you can use a OneToOneField to a model containing the fields for additional information. This one-to-one model is often called a profile model, as it might store non-auth related information about a site user.
As an alternative to extending the provided auth User model, you can provide your own custom User model. Then you will have complete control over its managers.
Instead, consider simply replacing {{ user }} with {{ user.profile.initials }}. Creating the OneToOne field on your profile model also creates a reverse accessor for instances of the related model. You can specify the reverse accessor name by the related_name keyword argument on the profile model field. For example...
from django.db import models
from django.contrib.auth.models import User
class UserProfile(models.Model)
user = models.OneToOneField('auth.User', related_name='profile')
initials = models.CharField(max_length=6)
some_user = User.objects.first()
# assuming there is already a profile related to this user
some_user.profile.initials = 'S.P.Y.'
You could also make a __str__ method for your profile model like
def __str__(self):
return self.initials
Then when you do {{ user.profile }} in a template, the initials will be shown.

Pass model objects to choices field in django

I have a model called Student that has a manytomany relationship with a model called Courses. I have another model called Attend in which I want to get all the courses the student is taking and pass it in as a select menu containing the courses the student is taking. I tried to get the id using the foreign key "student" and then get courses belonging to that student and put it in a list and pass it to choices but it didn't work obviously. I would like to know how I can get the courses belonging to the student to appear in the select menu.
Here is my model.
class Attend(models.Model):
student = models.ForeignKey(Student, on_delete=models.CASCADE, default="")
time_signed_in = models.DateTimeField(auto_now_add=True)
isSignedIn = models.BooleanField(default=False)
# Below does not work, I get an error 'ForeignKey' object has no attribute 'id'
#courses = User.objects.get(id=student.id).courses
course = models.ForeignKey(Course, on_delete=models.CASCADE)
To render the courses the student is taking you should try using django forms.
If I understand correctly, you want a form that uses ModelMultipleChoiceField:
Allows the selection of one or more model objects, suitable for
representing a many-to-many relation.
class AttendForm(forms.Form):
courses = forms.ModelMultipleChoiceField(queryset=Courses.objects.filter(student__id=id))
That exapmple would only work to show the data to the user and then retrieving its choice. There is a slightly different approach to this case and that is using a ModelForm.
Every ModelForm also has a save() method. This method creates and saves a database object from the data bound to the form.
ModelForm is a "database driven" form in which you can perform many task involving calls to the database easily.
Note: The queryset I used in the example is just an example, you dont have to use it that way.

Django model form saves m2m after instance

I am having an issue with the way Django class-based forms save a form. I am using a form.ModelForm for one of my models which has some many-to-many relationships.
In the model's save method I check the value of some of these relationships to modify other attributes:
class MyModel(models.Model):
def save(self, *args, **kwargs):
if self.m2m_relationship.exists():
self.some_attribute = False
super(MyModel, self).save(*args, **kwargs)
Even if I populated some data in the m2m relationship in my form, I self.m2m_relationship when saving the model and surprisingly it was an empty QuerySet. I eventually found out the following:
The form.save() method is called to save the form, it belongs to the BaseModelForm class. Then this method returns save_instance, a function in forms\models.py. This function defines a local function save_m2m() which saves many-to-many relationships in a form.
Here's the thing, check out the order save_instance chooses when saving and instance and m2m:
instance.save()
save_m2m()
Obviously the issue is here. The instance's save method is called first, that's why self.m2m_relationship was an empty QuerySet. It just doesn't exist yet.
What can I do about it? I can't just change the order in the save_instance function because it is part of Django and I might break something else.
Daniel's answer gives the reason for this behaviour, you won't be able to fix it.
But there is the m2m_changed signal that is sent whenever something changes about the m2m relationship, and maybe you can use that:
from django.db.models import signals
#signals.receiver(signals.m2m_changed, sender=MyModel.m2m_relationship.through)
def handle_m2m_changed(sender, instance, action, **kwargs):
if action == 'post_add':
# Do your check here
But note the docs say that instance "can be an instance of the sender, or of the class the ManyToManyField is related to".
I don't know how that works exactly, but you can try out which you get and then adapt the code.
But it would be impossible to do it any other way.
A many-to-many relationship is not a field on the instance, it is an entry in a linking table. There is no possible way to save that relationship before the instance itself exists, as it won't have an ID to enter into that linking table.

Difference between model fields(in django) and serializer fields(in django rest framework)

As we can validate the values using the conventional model field then why Django REST Framework contains its own serializer fields. I know that serializer fields are used to handle the converting between primitive values and internal datatypes. Except this, is there anything different between them.
Well there is a ModelSerializer that can automatically provide the serializer fields based on your model fields (given the duality you described). A ModelSerializer allows you to select which models fields are going to appear as fields in the serializer, thus allowing you to show/hide some fields.
A field in a model, is conventionally tied to a data store (say a column in a database).
A DRF Serializer can exist without a Django model too, as it serves to communicate between the API and the client, and its fields can be in many forms that are independent from the model and the backing database, e.g. ReadOnlyField, SerializerMethodField etc
Model fields are what you keep in your database.
(it answers how you want your data organized)
Serializer fields are what you expose to your clients.
(it answers how you want your data represented)
For models.ForeignKey(User) of your model,
you can represent it in your serializer as an Int field, or UserSerializer(which you will define), or as http link that points to the api endpoint for the user.
You can represent the user with username, it's up to how you want to represent it.
With DRF,
You can hide model fields, mark it as read-only/write-only.
You can also add a field that is not mappable to a model field.
Both of them refers to the same thing with a little bit difference.
Model fields are used within the database i.e while creating the schema, visible to the developer only.
while Serializer fields are used to when exposing the api to the client, visible to client also.

Looping through model objects to check whether a field is populated

I am working on a django project and am trying to figure out how to loop through all of my "task" model objects and check whether the ManyToMany "user" field is populated by user model objects of a certain type or not.
Is there a simple way to iterate over all of the model objects to do this?
You don't have to iterate objects. For example, assume that you have a Task model similar to:
class Task(models.Model):
users = models.ManyToManyField(User)
...
then the following query will return all the Task objects which has at least one related user who is a "Student":
Task.objects.filter(users__type='Student')
The double underscore (__) tells Django to traverse the many-to-many relation and fetch the type column from the User table.

Categories