I have to models connected by a ForeignKey
class User(AbstractUser):
...
and
class PrivateMessage(models.Model):
user_from = models.ForeignKey(
User,
verbose_name=u'From',
related_name='sent_messages',
)
user_to = models.ForeignKey(
User,
verbose_name=u'To',
related_name='received_messages',
)
Is there any way to get all the addresses for a particular user. For example, if
u = User.objects.get(id=1)
messages = PrivateMessage.objects.filter(user_from=u)
for m in messages:
users.add(m.user_to)
How to obtain a list of users that appear in user_to for these messages using only Django ORM methods?
I think a better idea would be to define ManyToManyField on the User model:
class User(AbstractUser):
#...
receivers = models.ManyToManyField('self', through='Message',
symmetrical=False, related_name="senders")
class Message(models.Model):
user_from = models.ForeignKey(MyUser, related_name='messages_from')
user_to = models.ForeignKey(MyUser, related_name='messages_to')
message = models.CharField(max_length=100, default="")
#...
Then to retrieve users list on the other end you simply do:
User.objects.get(id=1).receivers.all() # who I sent the message to
User.objects.get(id=1).senders.all() # who sent me a message
This way you have a nice clear API.
Finally, I ended up writing three queries:
users_from = set(PrivateMessage.objects.filter(
user_to=self.request.user,
).values_list(
'user_from__pk',
flat=True,
))
users_to = set(PrivateMessage.objects.filter(
user_from=self.request.user,
).values_list(
'user_to__pk',
flat=True,
))
interlocutors = User.objects.filter(pk__in=users_from.union(users_to))
I saw this docs
Maybe you can try:
u = User.objects.get(id=1)
users = User.objects.filter(received_messages__user_from=u).distinct()
related_name field makes our queries especially the ones using foreign key (on to many relation) easier, shorter and cleaner.
Let say we have 2 models classes Library and Book.
class Library(Models.model):
name = models.CharField(max_length = 100)
`class Book(Models.model):
title = models.CharField(max_length = 100)
library = models.ForeignKey(Library,
on_delete = models.CASCADE,
related_name = 'books')`
Here we have a one to many relation from Library to Book using foriegn key.
And in my django shell. I can create a new Library and a book related to that library in the following manner.
`from <app_name>.models import *`
`library = Library.objects.create(name = 'Big Library')`
`Book.objects.create(title = 'Awesome book', library = library`
Now I can query the book of the library using related name of model Book class:
`library.books.all()`
rather than using the starting the query from Book model as:
Book.objects.filter(library = library)
Related
I really don't understand all the ways to build the right query.
I have the following models in the code i'm working on. I can't change models.
models/FollowUp:
class FollowUp(BaseModel):
name = models.CharField(max_length=256)
questions = models.ManyToManyField(Question, blank=True, )
models/Survey:
class Survey(BaseModel):
name = models.CharField(max_length=256)
followup = models.ManyToManyField(
FollowUp, blank=True, help_text='questionnaires')
user = models.ManyToManyField(User, blank=True, through='SurveyStatus')
models/SurveyStatus:
class SurveyStatus(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
survey = models.ForeignKey(Survey, on_delete=models.CASCADE)
survey_status = models.CharField(max_length=10,
blank=True,
null=True,
choices=STATUS_SURVEY_CHOICES,
)
models/UserSurvey:
class UserSurvey(BaseModel):
user = models.ForeignKey(User, null=True, blank=True,
on_delete=models.DO_NOTHING)
followups = models.ManyToManyField(FollowUp, blank=True)
surveys = models.ManyToManyField(Survey, blank=True)
questions = models.ManyToManyField(Question, blank=True)
#classmethod
def create(cls, user_id):
user = User.objects.filter(pk=user_id).first()
cu_quest = cls(user=user)
cu_quest.save()
cu_quest._get_all_active_surveys
cu_quest._get_all_followups()
cu_quest._get_all_questions()
return cu_quest
def _get_all_questions(self):
[[self.questions.add(ques) for ques in qstnr.questions.all()]
for qstnr in self.followups.all()]
return
def _get_all_followups(self):
queryset = FollowUp.objects.filter(survey__user=self.user).filter(survey__user__surveystatus_survey_status='active')
# queryset = self._get_all_active_surveys()
[self.followups.add(quest) for quest in queryset]
return
#property
def _get_all_active_surveys(self):
queryset = Survey.objects.filter(user=self.user,
surveystatus__survey_status='active')
[self.surveys.add(quest) for quest in queryset]
return
Now my questions:
my view sends to the create of the UserSurvey model in order to create a questionary.
I need to get all the questions of the followup of the surveys with a survey_status = 'active' for the user (the one who clicks on a button)...
I tried several things:
I wrote the _get_all_active_surveys() function and there I get all the surveys that are with a survey_status = 'active' and then the _get_all_followups() function needs to call it to use the result to build its own one. I have an issue telling me that
a list is not a callable object.
I tried to write directly the right query in _get_all_followups() with
queryset = FollowUp.objects.filter(survey__user=self.user).filter(survey__user__surveystatus_survey_status='active')
but I don't succeed to manage all the M2M relationships. I wrote the query above but issue also
Related Field got invalid lookup: surveystatus_survey_status
i read that a related_name can help to build reverse query but i don't understand why?
it's the first time i see return empty and what it needs to return above. Why this notation?
If you have clear explanations (more than the doc) I will very appreciate.
thanks
Quite a few things to answer here, I've put them into a list:
Your _get_all_active_surveys has the #property decorator but neither of the other two methods do? It isn't actually a property so I would remove it.
You are using a list comprehension to add your queryset objects to the m2m field, this is unnecessary as you don't actually want a list object and can be rewritten as e.g. self.surveys.add(*queryset)
You can comma-separate filter expressions as .filter(expression1, expression2) rather than .filter(expression1).filter(expression2).
You are missing an underscore in surveystatus_survey_status it should be surveystatus__survey_status.
Related name is just another way of reverse-accessing relationships, it doesn't actually change how the relationship exists - by default Django will do something like ModelA.modelb_set.all() - you can do reverse_name="my_model_bs" and then ModelA.my_model_bs.all()
I've got a complicated relationship between my Django models and I'm trying to get django-import-export to play nicely.
class Person(models.Model):
name = models.CharField(max_length=64)
class Team(models.Model):
rep = models.ManyToManyField(Person, related_name="rep")
def get_reps(self):
return "/".join(sorted([p.name for p in self.reps.all()]))
class Account(models.Model):
tid = models.IntegerField("Territory ID", primary_key=True)
name = models.CharField("Territory Name", max_length=64)
sales_team = models.ForeignKey(Team, related_name="sales_team")
I'm trying to export (and hopefully later import) the territories with the names of the reps as rendered by the get_reps method.
class TerritoryResource(resources.ModelResource):
tid = fields.Field(attribute='tid', column_name="Territory ID")
name = fields.Field(attribute='name', column_name="Territory Name")
sales_team = fields.Field(
column_name="Sales Team",
widget=widgets.ForeignKeyWidget(Team, "get_reps")
)
The export is giving me a blank field. If I don't use the widget I get the Team ID as I'd expect.
Is it possible to get my custom name in the export?
I didn't include the standard __str__ methods in the sample code, because I didn't think they were important, but I did have in my Team class definition:
def __str__(self):
return self.get_reps()
This means, had I read the documentation with a little more creativity, I would have figured out how to do this. It's deceptively simple:
class TerritoryResource(resources.ModelResource):
...
def dehydrate_sales_team(self, territory):
return str(territory.sales_team)
I could also use return territory.sales_team.get_reps() to get the same results.
I'm been trying to create an app that allows users to follow each other profile since yesterday and today and I haven't been successful so far.
I'm having trouble creating a following function that allows me to retrieve users from a particular user he follows.
Example . If John follows Diana . I want to able to retrieve the user called Diana and use it with my modules.
I'm really sorry if this doesn't make sense . I'm trying my hardest to explain my situation.
class Person(models.Model):
user = models.ForeignKey(User)
name = models.CharField(max_length=100)
image = models.FileField(upload_to="images/",blank=True,null=True)
class Board(models.Model):
user = models.ForeignKey(User)
name = models.CharField(max_length=100)
def __unicode__(self):
return self.name
Most of these solutions gave me no query
This was one of the solutions I tried.
class UserLink(models.Model):
from_user = models.ForeignKey(User , related_name = "following_set")
to_user = models.ForeignKey(User , related_name = "follower_set")
date_added = models.DateTimeField(default = datetime.now)
def __unicode__(self):
return "%s is following %s" % (self.from_user.username,self.to_user.username)
def save(self,**kwargs):
if self.from_user == self.to_user:
raise ValueError("Cannot follow yourself ")
super(UserLink , self).save(**kwargs)
class Meta:
unique_together = (('to_user','from_user'),)
I tried to retrieve the users that a particular user followed and use it against my modules such as Person but it gave me an error No query exist.
def Follow(request,username=""):
if request.method == "POST":
username = request.POST.get('follow',False)
user = User.objects.get(username=username)
UserLink.objects.create(from_user=request.user,to_user=user)
return HttpResponseRedirect(reverse('world:Profile'))
return HttpResponseRedirect(reverse('world:Profile'))
I also tried this following function but it only followed himself and I changed self to User but it didn't allow me to put the person to follow
class UserProfile(models.Model):
user = models.OneToOneField(User)
follows = models.ManyToManyField('self', related_name='followed_by', symmetrical=False)
>>>from pet.models import *
>>>from django.contrib.auth.models import User
>>>user = User.objects.get(username='Peter')
>>>user1 = User.objects.get(username='Sarah')
>>>p = UserProfile.objects.filter(user=user,follows=user1)
>>>Error no field called follows
How can I create a following class that allows retrieve the people that they followed and use it with my modules such as Person?
Can someone help me . Thannk you community!
If I understand correctly, youu are on the right track with the many to many relationship. What you need is to modify your existing Person class to include this information.
Since information about who someone follows or is following is essentially information about that person and so you shouldn't really need to define a new class to implement that functionality.
I would suggest modifying your Person like so.
class Person(models.Model):
user = models.ForeignKey(User)
name = models.CharField(max_length=100)
image = models.FileField(upload_to="images/",blank=True,null=True)
following = models.ManyToManyField('self', related_name='followers', symmetrical=False, blank=True, null=True)
What this line does is makes a many to many relationship between the class Person and its self.
Many to many relationships work a little different to other relationships and I suggest you read the Django documentation https://docs.djangoproject.com/en/dev/topics/db/examples/many_to_many/.
But you should now be able to setup and access the relationship like this.
>>>john = Person.objects.get(name="John")
>>>diana = Person.objects.get(name="Diana")
>>>john.following.add(diana)//setup the many to many relationship
>>>john.save()
>>>john.following.all()
//This should return a queryset of Person objects which john is following.
//eg Diana
>>>diana.followers.all()
//This should return a queryset of Person objects which are following Diana.
//eg. John.
Easy, how awesome is Django!
I have the following models:
class Sked(models.Model):
pass
class Class(models.Model):
class_key = models.CharField(max_length=20, null=True)
name = models.CharField(max_length=150)
class Sked_class(models.Model):
class_room = models.CharField(max_length=100, null=True)
sked = models.ForeignKey(Sked)
class_took = models.ForeignKey(Class)
class User(djmodels.User):
sked = models.ForeignKey(Sked, null=True)
I want to make a query that selects all the classes that a specific user is taking, but i still can't get the idea of how to do it without using SQL, I already read this document https://docs.djangoproject.com/en/dev/topics/db/queries/ , but I still don't get it, How can I span multi-valued relationships through this models?
You're looking for two things - how to span foreign keys, and how to only return a unique set of classes that doesn't include duplicates.
You span foreign keys using __ to separate the relationships, and use distinct() on the query set to filter out duplicates. Remember that foreign key relationships work both ways with Django syntax, as the ORM will recognize reverse relationships. This should work:
user = User.objects.get(id=1)
Class.objects.filter(sked_class__user=user).distinct()
It's unclear to me if you data model makes sense, however. I think this makes more sense:
class Class(models.Model):
key = models.CharField(max_length=20, null=True)
name = models.CharField(max_length=150)
class Schedule(models.Model):
student = models.ForeignKey(User)
classes = models.ManyToManyField(Class)
Then you'd say:
user = User.objects.get(id=1)
Class.objects.filter(schedule__student=user)
I have a simple userprofile class in django such that
class Profile(models.Model):
user = models.OneToOneField(User,unique=True)
gender = models.IntegerField(blank=True, default=0, choices=UserGender.USER_GENDER,db_column='usr_gender')
education = models.IntegerField(blank=True, default=0, choices=UserEducation.USER_EDU,db_column='usr_education')
mail_preference = models.IntegerField(blank=True, default=1, choices=UserMailPreference.USER_MAIL_PREF,db_column='usr_mail_preference')
birthyear = models.IntegerField(blank=True, default=0,db_column='usr_birthyear')
createdate = models.DateTimeField(default=datetime.datetime.now)
updatedate = models.DateTimeField(default=datetime.datetime.now)
deletedate = models.DateTimeField(blank=True,null=True)
updatedBy = models.ForeignKey(User,unique=False,null=True, related_name='%(class)s_user_update')
deleteBy = models.ForeignKey(User,unique=False,null=True, related_name='%(class)s_user_delete')
activation_key = models.CharField(max_length=40)
key_expires = models.DateTimeField()
You can see that deletedBy and updatedBy are foreign key fields to user class. If I don't write related_name='%(class)s_user_update' it gives me error (I don't know why).
Although this works without any error, it doesn't push the user id's of deletedBy and updatedBy fields although I assign proper user to them.
Could give me any idea and explain the related_name='%(class)s_user_update' part ?
Thanks
'%(class)s_user_update' implies that it is a string awaiting formatting. You would normally see it in the context:
'%(foo)s other' % {'foo': 'BARGH'}
Which would become:
'BARGH other'
You can read more about python string formatting in the python docs. String Formatting Operations
I can't see how the code you have would ever work: perhaps you want:
class Profile(models.Model):
# other attributes here
updated_by = models.ForeignKey('auth.User', null=True, related_name='profile_user_update')
deleted_by = models.ForeignKey('auth.User', null=True, related_name='profile_user_deleted')
# other attributes here
If it does work, it is because django is doing some fancy magic behind the scenes, and replacing '%(class)s' by the class name of the current class.
Notes on the above:
The consistent use of *snake_case* for attributes. If you must use camelCase, then be consistent for all variables. Especially don't mix *snake_case*, camelCase and runwordstogethersoyoucanttellwhereonestartsandtheotherends.
Where you have two attributes that reference the same Foreign Key, you must tell the ORM which one is which for the reverse relation. It will default to 'profile_set' in this case for both, which will give you the validation error.
Use 'auth.User' instead of importing User into the models.py file. It is one less import you'll need to worry about, especially if you don't use the User class anywhere in your models.py file.
You can read more about the related_name stuff here:
https://docs.djangoproject.com/en/1.3/topics/db/queries/#following-relationships-backward