Django Admin class to auto-populate user field - python

I am trying to populate the field 'owner' in the my NoteForm. I read in documentation that I need to use the Admin for that.But i still get this error : note_note.owner_id may not be NULL. Need help. Code:
forms.py:
class NoteForm(forms.ModelForm):
class Meta:
model = Note
fields = ('title','body')
models.py:
class Note(models.Model):
title = models.CharField(max_length=200)
body = models.TextField()
cr_date = models.DateTimeField(auto_now_add=True)
owner = models.ForeignKey(User, blank=False)
admin.py
class NoteAdmin(admin.ModelAdmin):
def save_model(self, request, obj, form, change):
obj = form.save(commit=False)
obj.owner = request.user
obj.save()
def save_formset(self, request, form, formset, change):
instances = formset.save(commit=False)
for instance in instances:
instance.user = request.user
instance.save()
else:
fromset.save_m2m()
admin.site.register(Note, Noteadmin)
views.py:
def create(request):
if request.POST:
form = NoteForm(request.POST, request.FILES)
if form.is_valid():
form.save()
return HttpResponceRedirect('/notes/all')
else:
form = NoteForm()
args = {}
args.update(csrf(request))
args['form'] = form
return render_to_response('create_note.html', args)

I do not understand the point of Admin over here. From the code, what I understood is you creating a simple django form for your site and getting the error on form submission. If that's case, the solution is quiet easy. This error is generated because you are try to save a record in your Note model without any reference to User. As there's a db constraint on the foreign key field, it raises the error. Solution is easy, just add owner to the list of fields in the form or modify the save method to assign an owner to the note. If you'll use the first option, the user will be able to see and select the owner. And if you want to pre-populate that particular field, pass initial value to the form.

Related

Django: update a model with the current user when an non-model form field is changed

I'm building a page that allows users to edit Task and related Activity records (one task can have many activities), all on the same page. I want to allow the user to "adopt" one or more activities by ticking a box, and have their user record linked to each activity via a ForeignKey. Here are extracts from my code...
models.py
from django.contrib.auth.models import User
class Task(models.Model):
category = models.CharField(max_length=300)
description = models.CharField(max_length=300)
class Activity(models.Model):
task = models.ForeignKey(Task, on_delete=models.CASCADE)
title = models.CharField(max_length=150)
notes = models.TextField(blank=True)
owner = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True)
The activity "owner" is linked to a User from the Django standard user model.
I added an extra field in the form definition for the adopt field - I don't want to add it to the model as I don't need to save it once it's done it's job.
forms.py
class ActivityForm(forms.ModelForm):
adopt = forms.BooleanField(required=False)
class Meta:
model = Activity
fields = '__all__'
views.py
def manage_task(request, pk):
task = Task.objects.get(pk = pk)
TaskInlineFormSet = inlineformset_factory(Task, Activity,
form = ActivityForm)
if request.method == "POST":
form = TaskForm(request.POST, instance = task)
formset = TaskInlineFormSet(request.POST, instance = task)
if form.has_changed() and form.is_valid():
form.save()
if formset.has_changed() and formset.is_valid():
## ? DO SOMETHING HERE ? ##
formset.save()
return redirect('manage_task',pk=task.id)
else:
form = TaskForm(instance = task)
formset = TaskInlineFormSet(instance = task)
context = {'task': task, 'task_form': form, 'formset': formset}
return render(request, 'tasks/manage_task.html', context)
When the adopt field is ticked on the form, I want to be able to set the owner field in that form to the current user before the associated model instance is updated and saved.
I just can't figure out how to do that - if it was a single form (rather than an InlineFormSet), I think I could put code in the view to change the owner value in the form field before it was saved (I haven't tried this). Or try save(commit = False) and update the model instance then save() it.
Maybe I have to iterate through the formset in the view code and try one of those options when I find one that had adopt=True?
When the adopt field is ticked on the form, I want to be able to set the owner field in that form to the current user before the associated model instance is updated and saved.
formset = TaskInlineFormSet(request.POST, instance = task)
if formset.adopt:
# If True
formset.user = request.user
formset.save()
I think I could put code in the view to change the owner value in the form field before it was saved (I haven't tried this).
You should give it a try.
I'm not happy with this solution but it does work. I iterate through the forms and change the object instance if my adopt field is set.
views.py
def manage_task(request, pk):
task = Task.objects.get(pk = pk)
TaskInlineFormSet = inlineformset_factory(Task, Activity,
form = ActivityForm)
if request.method == "POST":
form = TaskForm(request.POST, instance = task)
formset = TaskInlineFormSet(request.POST, instance = task)
if form.has_changed() and form.is_valid():
form.save()
if formset.has_changed() and formset.is_valid():
## HERE'S WHAT I ADDED ##
for form in formset:
if form.cleaned_data['adopt'] is True:
form.instance.owner = request.user
## END OF ADDITIONS ##
formset.save()
## return redirect('manage_task',pk=task.id) # CHANGED THIS BECAUSE I WASN'T RETURNG ERRORS!
if not form.errors and not formset.total_error_count():
return redirect('manage_task',pk=task.id)
else:
form = TaskForm(instance = task)
formset = TaskInlineFormSet(instance = task)
context = {'task': task, 'task_form': form, 'formset': formset}
return render(request, 'tasks/manage_task.html', context)
I wish I could find more in the docs about how the form saving works but I think I'll have to look into the code if I want more detail.

Can someone help? Sending notifications to all users or some users in django forms

I want to send a single notification message to multiple users or all users. I have tried many to many fields but the sent to id won't save the i.d's of the users that i have sent the message to.
Models.py
class Notifications(models.Model):
id=models.AutoField(primary_key=True)
sent_to = models.ManyToManyField(CustomUser)
message = models.TextField(null=True)
message_reply = models.TextField(null=True)
created_at=models.DateTimeField(auto_now_add=True)
updated_at=models.DateTimeField(auto_now=True)
Views.py
def add_notification(request):
notifs = Notifications.objects.all()
users = CustomUser.objects.filter(is_staff=True)
if request.method == 'POST':
form = AddNotifForm(request.POST)
if form.is_valid():
instance = form.save(commit=False)
instance.message_reply = "none"
instance.save()
sent_to = form.cleaned_data.get('sent_to')
messages.success(request, f'Message has been successfully sent .')
return redirect('add_notif')
else:
form = AddNotifForm()
context={
'notifs' : notifs,
'form' : form,
'users' : users,
}
template_name ='main-admin/add-notif.html'
return render(request, template_name, context)
Forms.py
class AddNotifForm(forms.ModelForm):
sent_to = forms.ModelMultipleChoiceField(
queryset=CustomUser.objects.filter(is_staff=True).exclude(is_superuser=True),
widget=forms.CheckboxSelectMultiple,
required=True)
class Meta:
model = Notifications
fields = ['sent_to', 'message']
From the docs:
every time you save a form using commit=False, Django adds a save_m2m() method to your ModelForm subclass. After you’ve manually saved the instance produced by the form, you can invoke save_m2m() to save the many-to-many form data.
So you'll have to call save_m2m() after instance.save() if you are using commit=False:
instance = form.save(commit=False)
instance.message_reply = "none"
instance.save()
form.save_m2m() # <-- Add this

How to save Username instead of Object name(None) automatically while saving the model in django

check the updated pic
When I save the model, The object name is None, but I need to save the username instead of object name (None) automatically while I saving the Model
here is pic of admin site
Models.py
class solo_21_6_2021(models.Model):
user = models.OneToOneField(User,null=True,on_delete=models.CASCADE)
player1_pubg_id = models.PositiveIntegerField(null=True,blank=True)
player1_pubg_name = models.CharField(max_length=15,null=True,blank=True)
def __str__(self):
return str(self.user)
Views.py
def solo(request):
form = SoloForm()
if request.method=="POST":
form=SoloForm(request.POST)
if form.is_valid():
form.save()
return render(request, 'bgmiapp/solo.html',{'form':form})
Forms.py
class SoloForm(forms.ModelForm):
class Meta():
model = solo_21_6_2021
fields=['player1_pubg_id','player1_pubg_name'
Admin.py
class SoloAdmin(admin.ModelAdmin):
list = ('user','player1_pubg_id','player1_pubg_name')
admin.site.register(Profile)
admin.site.register(solo_21_6_2021,SoloAdmin)
you have set user field to null so the model is created without it, so when you want to show objects by user, it does not have this info so it shows None.
modify models to :
class solo_21_6_2021(models.Model):
user = models.OneToOneField(User,on_delete=models.CASCADE)
player1_pubg_id = models.PositiveIntegerField(null=True,blank=True)
player1_pubg_name = models.CharField(max_length=15,null=True,blank=True)
def __str__(self):
return str(self.user)
so now it is required and related as it is supposed to be
and inf the forms:
class SoloForm(forms.ModelForm):
class Meta():
model = solo_21_6_2021
fields=['user','player1_pubg_id','player1_pubg_name']
so it display the choice of user in the html form
now when you submit the form, the user name will display in the admin page
*Alternatively you could make your authenticated user the one who is creating the object, so no need to show list of your users to everyone:
def solo(request):
form = SoloForm()
if request.method=="POST":
form=SoloForm(request.POST)
if form.is_valid():
f = form.save(commit=False)
f.user = request.user
f.save()
return render(request, 'bgmiapp/solo.html',{'form':form})
and get rid of user in forms:
class SoloForm(forms.ModelForm):
class Meta():
model = solo_21_6_2021
fields=['player1_pubg_id','player1_pubg_name']
Ps: since you have a OnetoOne relation, you can create only one object by user, creating another will throw a user_id unique constraint error

Prepopulate ModelForm fields based on referring URL

I have a website which catalogs local hikes. Users can "log" that they have completed these hikes. I have both of these models+forms working as intended. Right now, though, in order to log a hike, you have to select the hike from a long list which contains all the hikes in the database. I'd like to be able to pre-populate that field so that if you are coming from the detail page of the hike in question, then that field is filled in with the hike.
Here's some code:
models.py:
model Hike(models.Model):
name = CharField(max_length=255)
slug = models.SlugField(unique=True)
...other fields...
model UserLog(models.Model):
hike = models.ForeignKey(Hike, on_delete=models.CASCADE)
user = models.ForeignKey(User, on_delete=models.CASCADE)
forms.py:
class LogHike(forms.ModelForm):
class Meta:
model = UserLog
fields = ('hike', 'date', ... other fields)
views.py:
def hike_detail(request, slug):
hike = Hike.objects.get(slug=slug)
log = UserLog.objects.filter(hike__slug=slug)
... more stuff here ...
return render(request, 'hikes/hike_detail.html' {
'hike': hike,
'log': log,
})
def log_hike(request):
if request.method == "POST":
form = LogHike(request.POST)
if form.is_valid():
obj = form.save(commit=False)
userid = request.user
obj.user = request.user
obj.save()
return redirect('user_profile', uid=userid.id)
else:
form = LogHike()
return render(request, 'log_hike.html', {'form': form})
So if a user is viewing the "hike_detail" view, I want to have a link that sends them to the "log_hike" view, but with the "Hike" field pre-populated based on the "Hike" that they came from. I think it might have something to do with the instance function? But I don't have a ton of experience with it. Is there an easy way to pass the data from the referring page in order to pre-populate the form?
You probably want to override your ModelForm __init__ method:
def __init__(self, *args, **kwargs):
super(LogHike, self).__init__(*args, **kwargs)
if 'hike' in kwargs:
self.fields['hike'].value = kwargs['hike']
Now all you need is another view which accepts a parameter passed and you're set. Extend your urls.py for that and then do something like:
def log_hike_with_pre_set_hike(request, *args, **kwargs):
if request.method == 'POST':
# see your code
else:
form = LogHike(hike=kwargs['hike'])
return render(request, 'log_hike.html', {'form': form})
Untested code, you might have to adapt it, I come from class-based views so it might be different for you.
You can pre-populate that form in log_hike when the request.method is get in the same way as when in post.
form = LogHike({'hike':hike_id})
The other thing is form where you'll take the hike_id. But that can come from request.GET for example.

Django claas Admin auto-populate user field

I am trying to populate the field 'owner' in the my NoteForm. I read in documentation that I need to use the Admin for that.But i still get this error : note_note.owner_id may not be NULL. Need help.
Code:
forms.py:
class NoteForm(forms.ModelForm):
class Meta:
model = Note
fields = ('title','body')
models.py:
class Note(models.Model):
title = models.CharField(max_length=200)
body = models.TextField()
cr_date = models.DateTimeField(auto_now_add=True)
owner = models.ForeignKey(User, blank=False)
class NoteAdmin(admin.ModelAdmin):
def save_model(self, request, obj, form, change):
form.owner = request.user
form.save()
views.py:
def create(request):
if request.POST:
form = NoteForm(request.POST, request.FILES)
if form.is_valid():
form.save()
return HttpResponceRedirect('/notes/all')
else:
form = NoteForm()
args = {}
args.update(csrf(request))
args['form'] = form
return render_to_response('create_note.html', args)
i also tried to write the class NoteAdmin in admin.py , just in case. Same error.What i am doing wrong? I am just following the documentation.
You are trying to save Note without owner field and the error said it. Try like:
if form.is_valid():
obj = form.save(commit=False)
obj.owner = request.user
obj.save()
The other way is to set null=True for the owner field if you can write data without owners.

Categories

Resources