let's say I've the following very simple models:
class Customer(models.Model):
name = models.CharField(max_length=50)
class Probe(models.Model):
OwnerInfo = models.CharField(max_length=50)
comments = models.CharField(max_length=50)
customer = models.ForeignKey(Customer, null=True, blank=True)
I've been able to add an InLine to the Admin gui, but I'd like to use a SELECT component, so I can just select several Probes and assign them to the Customer. From this question:
one-to-many inline select with django admin
I know thanks to Luke's answer (last one) that I should create a custom Form and assign it to my ModelAdmin.form but I can not wonder how to tie it all together to make it work.
May anyone help?
Thanks a lot in advance.
OK, I came a step further, and now I've the field added to the Form, like this:
from django.contrib import admin
from django import forms
from web_gui.models import Probe, Customer, Firmware
class CustomerForm(forms.ModelForm):
probes = forms.ModelMultipleChoiceField(queryset=Probe.objects.all())
def __init__(self, *args, **kwargs):
super(CustomerForm, self).__init__(*args, **kwargs)
self.fields['probes'].initial = [p.pk for p in Probe.objects.filter(customer_id=self.instance.pk)]
class Meta:
model = Customer
class CustomerAdmin(admin.ModelAdmin):
form = CustomerForm
admin.site.register(Probe)
admin.site.register(Customer, CustomerAdmin)
admin.site.register(Firmware)
but the initial values specified through "initial" are not being selected. What's wrong now? I assume that next will be to override the save() method to set the Probes on the Customer, am I right?
This is the best solution I've came up with. Let me know if there is any other better way of achieving this:
from django.contrib import admin
from django import forms
from django.contrib.admin.widgets import FilteredSelectMultiple
from web_gui.models import Probe, Customer, Firmware
class CustomerForm(forms.ModelForm):
probes = forms.ModelMultipleChoiceField(queryset = Probe.objects.all(), required=False)
probes.widget = FilteredSelectMultiple("Probes",False,attrs={'rows':'10'})
def __init__(self, *args, **kwargs):
super(CustomerForm, self).__init__(*args, **kwargs)
self.fields['probes'].initial = [p.pk for p in Probe.objects.filter(customer_id=self.instance.pk)]
def save(self, force_insert=False, force_update=False, commit=True):
c = super(CustomerForm, self).save(commit=False)
c.probe_set = self.cleaned_data['probes']
c.save()
return c
class Meta:
model = Customer
class CustomerAdmin(admin.ModelAdmin):
form = CustomerForm
admin.site.register(Probe)
admin.site.register(Customer, CustomerAdmin)
admin.site.register(Firmware)
Related
I've developed my personal blog to learn Django, I would like to make a backup of every post on a second model. Below there is an example of my aim:
from django.db import models
class mainModel(models.Model):
text = models.CharField(max_length=250)
class copyModel(models.Model):
main = models.ForeignKey(mainModel, on_delete=models.CASCADE)
text = models.CharField(max_length=250)
def save(self, *args, **kwargs):
self.text = mainModel.text
super(copyModel, self).save(*args, **kwargs)
When I create or modify a post into mainModel must be create a copy of it into copyModel. With the code above I can create a "post" but the save method from copyModel doesen't work.
Is this the right way?
You have to override mainModel save method instead of copyModel
from django.db import models
class mainModel(models.Model):
text = models.CharField(max_length=250)
def save(self, *args, **kwargs):
super(mainModel, self).save(*args, **kwargs)
copyModel.objects.create(
main=self, text=self.text)
class copyModel(models.Model):
main = models.ForeignKey(mainModel, on_delete=models.CASCADE)
text = models.CharField(max_length=250)
I am trying to convert django form from using standard select to select2. I have followed instruction and installed django-select-forms, added select2 to INSTALLED_APPS, and include select2 links and scripts in the header block
Here is my original code
Model.py
class Photographer(models.Model):
author_id = models.CharField(max_length=50, primary_key=True)
displayname = models.CharField(max_length=50)
forms.py
class UploadFileForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(UploadFileForm, self).__init__(*args, **kwargs)
self.fields['author'].required = True
self.fields['author'].queryset =
Photographer.objects.all().order_by('displayname')
Is ther anyway I can do this without changing my model?
Normally you only will need to specify the widget you use:
from django_select2.forms import Select2Widget
class UploadFileForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(UploadFileForm, self).__init__(*args, **kwargs)
self.fields['author'].required = True
self.fields['author'].queryset = Photographer.objects.order_by('displayname')
class Meta:
widgets = {'author': Select2Widget }
That being said, since you already are specifying some data in the __init__, it might be more elgant to define this as a class attribute instead:
from django_select2.forms import Select2Widget
class UploadFileForm(forms.ModelForm):
author = ModelChoiceField(
queryset=Photographer.objects.order_by('displayname'),
required=True,
widget=Select2Widget
)
How do I limit the values returned via the ManyToMany relationship and thus displayed in the <SELECT> field on my form to only show the spots which were created by the currently logged in user?
models.py
class Project(models.Model):
owner = models.ForeignKey(User, editable=False)
...
spots = models.ManyToManyField(to='Spot', blank=True, )
class Spot(models.Model):
owner = models.ForeignKey(User, editable=False)
spot_name = models.CharField(max_length=80, blank=False)
forms.py
from django import forms
from .models import Project, Spot
class ProjectForm(forms.ModelForm):
class Meta:
model = Project
exclude = ('owner', )
class SpotForm(forms.ModelForm):
class Meta:
model = Spot
exclude = ('owner', )
I'm using GenericViews for Update and Create and currently see all of the entries everyone has made into Spots when I'm updating or creating a Project. I want to see only the entries entered by the logged in user. For completeness sake, yes, the project.owner and spot.owner were set to User when they were created.
I've tried def INIT in the forms.py and using limit_choices_to on the manytomany field in the model. Either I did those both wrong or that's not the right way to do it.
thank you!
in your forms.py
class ProjectForm(forms.ModelForm):
class Meta:
model = Project
exclude = ('owner', )
def __init__(self, user_id, *args, **kwargs):
self.fields['spots'] = forms.ModelChoiceField(widget=forms.Select, queryset=Project.objects.filter(owner=user_id))
class SpotForm(forms.ModelForm):
class Meta:
model = Spot
exclude = ('owner', )
def __init__(self, user_id, *args, **kwargs):
self.fields['spot_name'] = forms.ModelChoiceField(widget=forms.Select, queryset=Spot.objects.filter(owner=user_id))
in your views.py
user_id = Project.objects.get(owner=request.user).owner
project_form = ProjectForm(user_id)
spot_form = SpotForm(user_id)
As I mentioned above, Dean's answer was really close, but didn't work for me. Primarily because request is not accessible in the view directly. Maybe it is in older Django versions? I'm on 1.9. Thank you Dean, you got me over the hump!
The gist of what's going on is adding User into the kwargs in the View, passing that to the ModelForm, remove User from the kwargs and use it to filter the Spots before the form is shown.
This is the code that worked for my project:
views.py
class ProjectUpdate(UpdateView):
model = Project
success_url = reverse_lazy('projects-mine')
form_class = ProjectForm
def dispatch(self, *args, **kwargs):
return super(ProjectUpdate, self).dispatch(*args, **kwargs)
def get_form_kwargs(self):
kwargs = super(ProjectUpdate, self).get_form_kwargs()
kwargs.update({'user': self.request.user})
return kwargs
forms.py
class ProjectForm(forms.ModelForm):
class Meta:
model = Project
exclude = ('owner', 'whispir_id')
def __init__(self, *args, **kwargs):
user_id = kwargs.pop('user')
super(ProjectForm, self).__init__(*args, **kwargs)
self.fields['spots'] = forms.ModelMultipleChoiceField(queryset=Spot.objects.filter(owner=user_id))
class SpotForm(forms.ModelForm):
class Meta:
model = Spot
exclude = ('owner', )
def __init__(self, *args, **kwargs):
user_id = kwargs.pop('user')
super(SpotForm, self).__init__(*args, **kwargs)
self.fields['spot_name'] = forms.ModelMultipleChoiceField(queryset=Spot.objects.filter(owner=user_id))
I was making a form for creation unpublished Artist instances and then adding Artwork to the artist before publishing.
I have manager to hide published=False artists and do not know how to bypass this yet in ForeignKey.
models.py
class PublishedManager(models.Manager):
"""Returns only published Artists in queryset"""
def get_query_set(self):
qs = super(VisibleManager, self).get_query_set()
qs = qs.filter(status='published')
return qs
class Artist(models.Model):
objects = PublishedManager() # Used overall on the site to hide published=False objects
admin_objects = models.Manager() # Default manager Will be used in admin to show invisible objects too
class Artwork(models.Model):
artist= models.ForeignKey(Artist)
forms.py
class ArtworkForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(ArtworkForm,self).__init(args,kwargs)
from django.db import models
self.fields['artist'].queryset = Artist.admin_objects.all()
shell
>>> form=Artwork_form(artist=180) #unpublished artist pk
>>> form.errors
Model artist with pk 180 does not exist
I need to make the form "see" the unpublished artists in FK, how can i achieve this?
Thank you.
I found the solution!!!
Original info is here http://www.hoboes.com/Mimsy/hacks/custom-managers-django-foreignkeys/
I implemented the CustomManagerForeignKey as the autor of this post had written with the one exception(otherwise in won't work properly):
usage:
class Artwork(models.Model):
artist= CustomManagerForeignKey(Artist, manager=Artist.admin_objects)
and a fix for this in the CustomManagerForeignKey:
class CustomManagerForeignKey(models.ForeignKey):
def __init__(self, *args, **kwargs):
if 'manager' in kwargs:
self.customManager = kwargs['manager'] #Here i removed the () in the end of the line
del kwargs['manager']
else:
self.customManager = None
super(CustomManagerForeignKey, self).__init__(*args, **kwargs)
I have following setup.
from django.db import models
from django.contrib.auth.models import User
class Event(models.Model):
name = models.CharField(max_length=64)
date = models.DateField()
ATTENDANCE_CHOICES = (
('A','Attending'),
('N','Absent'),
('L','Taken ill'),
)
class Attendance(models.Model):
student = models.ForeignKey(User)
event = models.ForeignKey(Event)
status = models.CharField(max_length=1, choices=ATTENDANCE_CHOICES)
In a nutshell: Students(User) attend or doesn't attend classes(Event), this is registered by Attendance.
Problem is adding those attendance records one at a time.
What I am looking for is a way to provide form for each class(each Event object) with list of all students and attendance status radio buttons or drop downs next to them.
Something like this:
http://i.imgur.com/jANIZ.png
I have looked at many discussions about multiple/bulk record insertion via django admin and am beginning to wonder is this even possible with django admin or do I have to create such form from scratch? Either way, what would be the best (most django-ish) approach?
"Is this even possible?" It's possible right out of the box.
Look into the django Admin app, Inlines, ModelForms, and the RadioSelect widget.
class MyForm(forms.ModelForm):
class Meta:
model = Attendance
def __init__(self, *args, **kwargs):
super(MyForm, self).__init__(*args, **kwargs
self.fields['status'].widget = forms.RadioSelect(choices=self.fields['status'].choices)
class AttendanceInline(admin.TabularInline):
model = Attendance
form = MyForm
class EventAdmin(admin.ModelAdmin):
inlines = [AttendanceInline]
def save_model(self, request, obj, form, change):
obj.save()
for user in User.objects.all():
obj.attendance_set.create(user=user, status='')
# you should consider a null field or a possible choice for "Undecided"
admin.site.register(Event, EventAdmin)