I have a model that I use in django admin to keep track of action taken on a task. The model includes a user field to show which user added an action. The issue is when a new task update is added, django overwrite the previous user by the new user. As it can be seen bellow, I do not want to change the user (by field) whenever a new action is created.
class Action(models.Model):
action = models.ForeignKey(TaskAction, models.CASCADE)
by = models.ForeignKey('auth.User', models.CASCADE)
timestamp = models.DateTimeField(auto_now_add=True, editable=False)
note = models.TextField(blank=True, null=True)
def __str__(self):
return str(self.action)
class Meta:
verbose_name = 'Task Action'
verbose_name_plural = 'Task Actions'
db_table = 'task_actions'
In admin.py set readonly field for 'by' read more here
class ActionAdmin(ModelAdmin):
readonly_fields=('by',)
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.
In my django app i have a model like thisone:
class temp_case(models.Model):
id = models.AutoField(primary_key=True)
main_id = models.ForeignKey(temp_main, related_name="tm_tc", on_delete=models.CASCADE, verbose_name="Main Template")
descr = models.CharField(max_length=200, verbose_name="Case description")
dt = models.DateTimeField(auto_now=True, verbose_name="Created")
owner = models.ForeignKey('auth.User', related_name='tcase_owner', on_delete=models.CASCADE, verbose_name="API Owner")
well, when i go in my admin interface ad add a row, i would that field owner (models.ForeignKey('auth.User', related_name='tcase_owner', on_delete=models.CASCADE, verbose_name="API Owner") would automatically default populated with the current logged in user instead select it manually every time.
I have to manage my admin.py file? or directly into model?
so many thanks in advance
Overwrite ModelAdmin.get_changeform_initial_data:
#admin.py
class TempCaseAdmin(models.ModelAdmin):
def get_changeform_initial_data(self, request):
return {'owner': request.user}
admin.site.register(temp_case, TempCaseAdmin)
I want to link two models using foreignKey, The problem is when i try to do that, one model does not get foreignKey value for the next model in the database table.
The aim is for user to fill information on the first page (have its own model and template) then click next (fill more info in the next page having its own model and template) then click next for the same logic. then when other users view this post it must show all content from different models in one page. here is my code.
1st model
class Map(models.Model):
user = models.ForeignKey(User, default=None, blank=True, null=True, on_delete=models.CASCADE)
name = models.CharField(max_length=100)
position = GeopositionField()
HAVING ITS OWN TEMPLATE
2nd Model
class Post(models.Model):
parent = models.ForeignKey("self", default=None, blank=True, null=True, on_delete=models.CASCADE)
user = models.ForeignKey(settings.AUTH_USER_MODEL, default=None, on_delete=models.CASCADE)
title = models.CharField(max_length=50)
content = models.TextField()
map = models.ForeignKey(Map, related_name='mapkey', default=None, blank=True, null=True, on_delete=models.CASCADE)
HAVING ITS OWN TEMPLATE BUT also has serializer method(API) below:
class PostModelSerializer(serializers.ModelSerializer):
user = UserDisplaySerializer(read_only=True)
parent = ParentPostModelSerializer()
map = serializers.SerializerMethodField()
class Meta:
start_date = forms.DateField(widget = forms.SelectDateWidget())
end_date = forms.DateField(widget = forms.SelectDateWidget())
model = Post
fields = [
'id',
'user',
'title',
'content'
'image',
'map',
]
Please focus only on the map field as its isolated in the above codes
everything works perfectly, but the foreignKey. also i didnt see the need to include all the code here but snippets.
i have been struggling with this for days now. do i need to write an api for 1st model also? for views i used class based views.
the database table for model 2, on the map field it shows null all the time.
I have i have provided enough information.Thanks
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 the following in the models.py:
class Item(models.Model):
date = models.DateField(_('date'), blank=True, null=True)
description = models.CharField(_('description'), max_length=255)
content_type = models.ForeignKey(ContentType, verbose_name=_('content type'))
object_id = models.PositiveIntegerField(_('object id'), db_index=True)
object = generic.GenericForeignKey('content_type', 'object_id')
class ItemAccountAmountRef(Item):
""" Items of which a Quote or an Invoice exists. """
amount = models.DecimalField(max_digits=10, decimal_places=2)
reference = models.CharField(max_length=200)
debit_account = models.ForeignKey(Account, related_name='receivables_receipt_debit_account')
credit_account = models.ForeignKey(Account, related_name='receivables_receipt_credit_account')
class PaymentItem(ItemAccountAmountRef):
pass
class Payment(models.Model):
invoice = models.ManyToManyField(Invoice, null=True, blank=True)
date = models.DateField('date')
attachments = generic.GenericRelation(Attachment)
site = models.ForeignKey(Site, related_name='payment_site', null=True, blank=True
items = generic.GenericRelation(PaymentItem)
in the admin.py:
class PaymentItemInline(generic.GenericTabularInline):
model = PaymentItem
form = PaymentItemForm
class PaymentAdmin(admin.ModelAdmin):
inlines = [PaymentItemInline]
in forms.py:
class PaymentItemForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(PaymentItemForm, self).__init__(*args, **kwargs)
self.fields['credit_account'].label = "Bank Account"
In the PaymentItemInline the label is not changing. I have tried changing other attributes e.g. class which work. If I run through the init in debug mode I can see that the label variable is changing however when the form is rendered the field is still labelled credit account. Any suggestions?
You're 98% of the way there. Instead of trying to futz with the form field in __init__, just redefine it in your ModelForm. If you name it the same thing, django will be able to figure out that it is supposed to validate & save to the ForeignKey field. You can use the same formula to change a Field or Widget completely for a given field in a ModelForm.
You can find the default form field types for each model field type here: https://docs.djangoproject.com/en/dev/topics/forms/modelforms/#field-types
class PaymentItemForm(forms.ModelForm):
credit_account = forms.ModelChoiceField(label="Bank Account", queryset=Account.objects.all())
That's it. No need to override any functions at all : )
Incidentally, the docs for this field are here: https://docs.djangoproject.com/en/dev/ref/forms/fields/#modelchoicefield