Hello Awesome People!
How to check whether a similar record is already in database with ManyToManyField():
class Room():
created_by = models.ForeignKey(User)
allowed_users = models.ManyToMany(User,related_name='rooms_as_guest')
is_active = models.BooleanField(default=True)
In my view before creating a new room, I want to make sure there wasn't an active room with exactly the same participants.
The following example won't work, it's just to show you what I expect
allowed_users = User.objects.filter(id__in=request.POST.get("ids",[]))
if allowed_users:
Room.objects.get_or_create(
created_by = request.user,
allowed_users = allowed_users, # won't work
is_active = True,
)
How could I proceed to do what I want?
This is because allowed_users is a ManyToMany Field and so, Room needs to created before adding Users to it.
See official documentation here:
https://docs.djangoproject.com/en/2.1/topics/db/examples/many_to_many/#many-to-many-relationships
Now the other problem is we need to get an existing room with the same set of users, which is already answered in a similar question here:
Django filter where ManyToMany field contains ALL of list
Try below:
from django.db.models import Count
allowed_users = User.objects.filter(id__in=request.POST.get("ids",[]))
if allowed_users:
room = Room.objects.filter(allowed_users__in=allowed_users).annotate(num_users=Count('allowed_users')).filter(num_users=len(allowed_users)).first()
if not room:
room = Room.objects.create(created_by=request.user, is_active=True)
room.allowed_users.add(*allowed_users)
You can't create an object like that with a ManyToMany field because the object must exist before you can create an intermediary object that represents your m2m relationship. You would have to do something like:
allowed_users = User.objects.filter(id__in=request.POST.get("ids", [])).order_by('id')
room = None
for r in up.rooms.filter(is_active=True):
if list(allowed_users) == list(r.allowed_users.all().order_by('id')):
room = r # get the existing room
break
if not room:
room = Room.objects.create(
created_by = request.user,
is_active = True
)
room.allowed_users.add(*allowed_users)
You'd have to ensure allowed_users are in the same order as room.allowed_users however.
Check the docs for more info
Related
I would like to know how, using Django, to ensure the uniqueness of a field value, even if objects are deleted.
For example, I create a CustomerUser with username = "carlos" , delete this user, then if I create another CustomerUser with username= "carlos" I will get an error.
models.py
class CustomUser(models.Model):
username = models.CharField(max_length=100 , unique=True)
shell
user_one = CustomUser.objects.create(username="carlos")
user_one.delete()
user_two = CustomUser.objects.create(username="carlos") ---> This should not be possible.
Should I save in another model all the usernames created or there is a Django function that assures the uniqueness of the username will be always True even after object deletion?
You can try this:
class CustomUser(models.Model):
username = models.CharField(max_length=100 , unique=True)
is_deleted = models.BooleanField(default=False)
Then just update the is_delete to True and filter user according that.
user_one = CustomUser.objects.create(username="carlos")
user_one.is_delete = True
user_one.save()
During filter you do something like this:
user_one = CustomUser.objects.filter(is_delete=False)
You can make use of a package like django-soft-delete. This package will not remove the record, but add an extra BooleanField named is_deleted that is set to True in case the object is removed. But the record itself still exists.
The package will thus override the .delete() method of the model object, and also use record managers that will for example count the number of records with is_deleted set to False, at the same time the database will still enforce that no two records with the same name will exist.
I'm facing a big issue with django.
I'm trying to save object containing foreignKeys and 'ManyToMany` but i always get this error
ProgrammingError: column [columnName] does not exist
I've made serveral times all migrations but it doesn't works. I have no problem when i work with models that does not contain foreign keys. I have tried to delete the migration folder. It's seems my database doesn't want to update fields. I need to force it to create these column but i don't have any idea.
class Post(models.Model):
post_id = models.CharField(max_length=100,default="")
title = models.CharField(max_length=100,default="")
content = models.TextField(default="")
author = models.ForeignKey(Users, default=None, on_delete=models.CASCADE)
comments = models.ManyToManyField(Replies)
numberComments = models.IntegerField(default=0)
date = models.DateTimeField(default=timezone.now)
updated = models.DateTimeField(null=True)
def __str__(self):
return self.post_id
when i'm trying to retrieve this i have :
ProgrammingError: column numberComments does not exist
As i said before i made makemigrations and migrate, i even deleted the migration folder.
Any idea ?
To save a instance of the POST model with foreign key you need to insert the query object.
Code example:
user = Users.objects.get(pk = 1)
p = POST(
title = 'Hello',
...
author = user,
date = '2018-01-01'
)
p.save()
You don't need to create post_id column, django creates one for you automatically, and you can access that using .pk or .id
You neither need numberComments. You should calculate that from comments many to many relation. Well... you can have this on DB too.
Next, you cannot add a many to many relation on creation. Create the post first as above. Then query the comment you want to add, the add the object to the relation
r = Replies.objects.get(pk = 1)
p.comments.add(r)
Hope it helps
I am looking for a way to filter for all objects of the same type that have the same querysets for a M2M field.
class Comment(models.Model):
user = models.ForeignKey(User, related_name='comment_user')
content = models.CharField(max_length=5000, null=True)
private_to = models.ManyToManyField(User, null=True, related_name='private_to')
Given a comment object, I want to retrieve all other comments who have an equal M2M field (i.e. if the private_to field returns User 1 and User 2 for the comment, it will find all the other comments that contain exactly both of those users in the private_to field.)
Is there a concise, built-in way to do this?
Try something from this post:
comment = Comment.objects.all()[0] # Or the comment you want to filter by.
private_to_ids = list(comment.private_to.all().values_list('id', flat=True))
comments = Comment.objects.filter(private_to__exact=private_to_ids)
I would like to do a reverse relationship on my table Tickets.
Here is my model :
class Tickets(models.Model):
ticket_title = models.CharField(max_length=100)
ticket_content = models.TextField()
class User_Detail(models.Model):
user = models.OneToOneField(User)
tickets = models.ManyToManyField(Tickets, blank=True, null=True)
I create my ticket like that :
ticket = Tickets.objects.create(ticket_title="test", ticket_content="test content")
request.user.user_detail.tickets.add(ticket)
and the thing I'm having an issue to do is to get the username of the guy who post the ticket, (without request.user)
so I tried like that :
ticket = Tickets.objects.get(pk=1)
ticket.user_detail_set.user.username
but I get
AttributeError: 'ManyRelatedManager' object has no attribute 'user'
Thanks you for watching, I hope you'll understand.
Since you set up a many-to-many relationship, a Ticket may have many User_Detail objects. Therefore, Ticket.user_detail_set is a manager, not a single object. You could get the first user associated with a Ticket like this:
ticket.user_detail_set.first().user.username
But it sounds like you actually want a one-to-many relationship between Ticket and User_Detail, meaning you actually want Ticket to have a foreign key relationship. Your models should probably look like this:
class User_Detail(models.Model):
user = models.OneToOneField(User)
class Ticket(models.Model):
user = models.ForeignKey(User)
title = models.CharField(max_length=100)
contents = models.TextField()
Then you can do:
ticket = Ticket.objects.get(pk=1)
user = ticket.user
You might even be able to drop the User_Detail model entirely, unless you use it elsewhere in your application and/or it has more fields than what is shown here.
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.