Consider this model.py for a MariaDB-based setup:
class User(models.Model):
email = models.CharField(max_length=255)
class Newsletter(models.Model):
subscribers = models.ManyToManyField(User, blank=True)
title = models.CharField(max_length=255)
If I delete a User, I want the reference to it removed from any Newsletter's subscribers list. I do not want to delete the Newsletter itself at any point, even if the subscribers list is empty.
Is this possible automatically with some Django feature like on_delete=REMOVE_FROM_LIST?
Related
When I delete the parent table using Django rest due to on_delete it deletes the child table also (due to foreign key) but the Image and File content of the child table not deleted.
I want to delete those images and Files also..!
How to do that..?
My tables
1:Group
2:Posts
One To Many Relation
I delete the Group table as follows:
GroupsModel.objects.filter(id=py_data.get('group_id')).delete()
GroupsModel :
class GroupsModel(models.Model):
group_name = models.CharField(max_length=20, unique=True)
group_description = models.CharField(max_length=50)
group_joining_link = models.CharField(max_length=50, default='', unique=True)
user_id = models.ManyToManyField(UserModel, through='UserModelGroupsModel', related_name='u_g')
class Meta:
db_table = 'groups'
GroupPostsModel:
class GroupPostsModel(models.Model):
post_text = models.CharField(max_length=1000)
post_type = models.CharField(max_length=20)
image = models.ImageField(blank=True, null=True, upload_to='post_images/')
document = models.FileField(blank=True,null=True, upload_to='post_documents/')
likes = models.IntegerField(default=0)
time_stamp = models.DateTimeField(auto_now=True)
group = models.ForeignKey(GroupsModel, on_delete=models.CASCADE)
user = models.ForeignKey(UserModel, on_delete=models.CASCADE)
class Meta:
db_table = 'group_posts'
I want to delete image and document file also automatically.
When an instance is removed referred files are not deleted, since the ImageField/FileField is only a reference to the files. You can override the delete method of your model:
import os
class GroupPostsModel(models.Model):
post_text = models.CharField(max_length=1000)
post_type = models.CharField(max_length=20)
image = models.ImageField(blank=True, null=True, upload_to='post_images/')
document = models.FileField(blank=True,null=True, upload_to='post_documents/')
likes = models.IntegerField(default=0)
time_stamp = models.DateTimeField(auto_now=True)
group = models.ForeignKey(GroupsModel, on_delete=models.CASCADE)
user = models.ForeignKey(UserModel, on_delete=models.CASCADE)
def delete(self):
if self.image:
if os.path.isfile(self.image.path):
os.remove(self.image.path)
if self.document:
if os.path.isfile(self.document.path):
os.remove(self.document.path)
super().delete()
class Meta:
db_table = 'group_posts'
The delete method will not be called in the queryset you wrote, you need to delete each instance individually:
for instance in GroupsModel.objects.filter(id=py_data.get('group_id')):
instance.delete()
on_delete=models.CASCADE on a ForeignKey is something written and managed on the database schema. It is not Django that delete the child model on delete, but your database (MySQL, Postgres, ...) that automaticaly detect a failure on ForeignKey and perform a Cascade action (like a contraint).
models.ImageField and models.FileField are (at database level) just a CharField with the location on the file system of your file. The database cannot remove a file, so you cannot delegate this action to the database.
If you want automatic removal of file on Model .delete(), you have multiple possible strategy :
Periodic check that for each file, a model exists (if not, remove the file)
Overwrite the .delete() method of GroupPostsModel (but it will only work if you call .delete() on an instance of the model, not on a queryset, like on your exemple)
Add the removal feature on the delete endpoint.
I am building an Instagram like app and trying to make a like model. Each user can like a post however, it should not be possible to like the same post twice.
class Like(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
post = models.ForeignKey(Post, on_delete=models.CASCADE)
created = models.DateTimeField(auto_now_add=True)
This is my model however, I am able to create 2 identical objects. For example user 1 can have 2 like objects like to post 1.
Is there a way to do this?
Yes, you can mark the combination of the user and post field as unique with a UniqueConstraint [Django-doc]:
class Like(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
post = models.ForeignKey(Post, on_delete=models.CASCADE)
created = models.DateTimeField(auto_now_add=True)
class Meta:
constraints = [
models.UniqueConstraint(fields=['user', 'post'], name='like_once')
]
Prior to django-2.2, you can make use of the unique_together option [Django-doc]:
class Like(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
post = models.ForeignKey(Post, on_delete=models.CASCADE)
created = models.DateTimeField(auto_now_add=True)
class Meta:
unique_together = [['user', 'post']]
Note: It is normally better to make use of the settings.AUTH_USER_MODEL [Django-doc] to refer to the user model, than to use the User model [Django-doc] directly. For more information you can see the referencing the User model section of the documentation.
Basically, I have two models: User and Event. An event is always associated with one user.
class User(models.Model):
user_id = models.AutoField(primary_key=True)
username = models.CharField(max_length=255, unique=True)
hashed_password = models.CharField(max_length=255)
class Event(models.Model):
event_id = models.AutoField(primary_key=True)
title = models.CharField(max_length=255)
description = models.TextField(max_length=255, blank=True, default='')
user = models.ForeignKey(User)
And then I have the following form for Event.
class EventForm(forms.ModelForm):
class Meta:
model = Event
fields = ['title', 'description', 'user']
I can succesfully show this form in my template to create an event. I can also associate a user to a form successfully with Select field when the users number are still few.
Now the problem is, when I have 1M users in database, my browser crashes when loading the template. Any idea how to solve this one? I was thinking about using AJAX and then search user that matches the username, but I'd like to hear other better approaches. Thanks!
I'm fairly new to Django I'm trying to build a multichat app using Django 2.0.5 and my models are the following:
class DateTimeModel(models.Model):
date_created = models.DateTimeField(auto_now_add=True)
date_modified = models.DateTimeField(auto_now=True)
class Meta:
abstract = True
class Room(DateTimeModel):
id = models.UUIDField(primary_key=True, default=uuid.uuid4,
editable=False
)
members = models.ManyToManyField(User)
def __str__(self):
...
class Message(DateTimeModel):
sender = models.ForeignKey(User, on_delete=models.CASCADE)
room = models.ForeignKey(Room, on_delete=models.CASCADE)
text = models.TextField()
def __str__(self):
...
What I want to do: I want to set the database scheme such that each message knows who its recipients are in the room that it belongs to and somehow stores whether each member in that room has 'seen' the message. I am having a tough time trying to see how I could make it work.
Thanks in advance!
Ahmed
To get message recipients, use (for example if we have a message in the database, with id=1)
message = Message.objects.get(pk=1)
recipients = message.room.members
For the part where you said you would want to see who has seen the message. Use the following method(it's not the only way, but an example):
Add another field to your Message model which would be ManyToMany field.
Maybe like seen = models.ManyToManyField(User) Such that when you catch the event, maybe when a user clicks on the message, send a post/get request to the server, notifying it of a seen event and there you use the following code:
message = Message.objects.get(id=POST_DATA['message_id'])
user = request.user
if user not in message.seen:
message.seen.add(user)
'''
continue with app logic
'''
I hope you got an idea.
I currently have three models:
class Request(models.Model):
requester=models.CharField()
dateRequested = models.DateField(auto_now=True)
title= models.CharField(max_length=255)
description = models.TextField()
class RequestType(models.Model):
requestType=models.CharField('Request Type', max_length=256)
class RequestTypeInfo(models.Model):
requestType=models.ForeignKey('RequestType', verbose_name='Request Type')
title = models.CharField('title', max_length=256)
info = models.CharField(max_length=256, blank=True)
The idea is that each request shows the information common to all types of requests and additional fields are presented to the users to be filled in depending on the request type selected.
How would I change the models to allow this and how would i write the view to display the form to the user so that the additional information is displayed in-line with the base request. Would it be better to have a second view which asks for the additional information.
The end aim is that the admins can create new request types without creating models in python by just adding a new request and adding any additional info fields.
So are you saying that you want to create a Many-to-many relationship from Request to RequestTypeInfo using RequestType as your intermediate Model?
class Request(models.Model):
requester=models.CharField()
dateRequested = models.DateField(auto_now=True)
title= models.CharField(max_length=255)
description = models.TextField()
request_type = models.ManyToManyField(RequestType, through='RequestTypeInfo')
class RequestType(models.Model):
requestType=models.CharField('Request Type', max_length=256)
class RequestTypeInfo(models.Model):
requestType=models.ForeignKey('RequestType', verbose_name='Request Type')
title = models.CharField('title', max_length=256)
info = models.CharField(max_length=256, blank=True)
We can talk about inline admin models after this gets clarified.