django admin - add multiple entries to db with single form submit - django

I have a model Point where i have a field called name charField. I trying to add multiple entries on Point with single Form submission. For example, the form has textarea field where i will entry 10 names line by line and then i try to split names one by one and save to point table.
class Point(models.Model):
name = models.CharField(blank=True)
class PointForm(forms.ModelForm):
pointlist = forms.CharField(widget=forms.Textarea, required=False)
class Meta:
model = Point
fields = '__all__'
def save(self, commit=True):
return super(Point, self).save(commit=False)
I tried to add multiple entries with single form submission in django admin page
getting below error:
super(type, obj): obj must be an instance or subtype of type

Related

Django one to many saving model is giving error

I have an exam model and I am trying to add a form to add multiple Quiz instance in the parent model. I am getting the following error
raise ValueError(
ValueError: Cannot assign "": "exam_quiz.quiz" must be a "Quiz" instance.
class ExamQuizAdminForm(forms.ModelForm):
class Meta:
model = exam_quiz
exclude = ['registrationDate','examdate']
quiz = forms.ModelMultipleChoiceField(
queryset=Quiz.objects.all(),
required=False,
label=_("Quiz"),
widget=FilteredSelectMultiple(
verbose_name=_("Quiz"),
is_stacked=False))
def __init__(self, *args, **kwargs):
super(ExamQuizAdminForm, self).__init__(*args, **kwargs)
if self.instance.pk:
self.fields['quiz'].initial = \
self.instance.quiz
def save(self, commit=True):
exam_quiz = super(ExamQuizAdminForm, self).save(commit=False)
exam_quiz.save()
exam_quiz.quiz_set.set(self.cleaned_data['Quiz'])
self.save_m2m()
return exam_quiz
class ExamQuizAdmin(admin.ModelAdmin):
form = ExamQuizAdminForm
list_display = ('examname','month','year')
Assuming exam_quiz.quiz is a m2m field...
I don't think you need to override the save function in this case. Use the save_m2m() function if you want to, say, add additional non form data, and then save both the normal and m2m data from the form. According to the docs
"Calling save_m2m() is only required if you use save(commit=False).
When you use a save() on a form, all data – including many-to-many
data – is saved without the need for any additional method calls."
Here, however, it looks like the only change you're making is adding the m2m data, which the normal save can handle.
Also, you might try making the Quiz lowercase, eg,
exam_quiz.quiz_set.set(self.cleaned_data['quiz'])
as I don't think 'label' or 'verbose_name' affect the HTML field name.

Display a Foreign Key Dropdown in Django Form as Text

Is there a way to show a foreign key field in a Django form as an read only text box?
forms.py
class NewModelForm(forms.ModelForm):
class Meta:
model = Model
fields = ['fk_field', 'other_field']
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['fk_field'].widget.attrs['readonly'] = True #the dropdown is still active when this is set
#self.fields['fk_field'] = forms.CharField(widget=forms.TextInput()) ##when I turn this on, I get an error that I am assigning to the wrong instance.
You can override any of your ModelForm's fields, even those that come from the model, by just setting it as class attribute like you would for a normal Form field:
class NewModelForm(ModelForm):
fk_field = forms.CharField(required=False, disabled=True)
class Meta:
model = MyModel
fields = ['fk_field', 'other_field']
The disabled option on a field sets the input to disabled.
Note that you should not trust the data submitted to contain the correct initial value for fk_field. Anyone can still submit a different fk_field if they know how to use curl or Postman, even if the <input> is disabled. So if just ignore whatever value is submitted and set it to the correct value in your view.

How can I achieve one single form, pre-populated with data from two different Profile instances?

I have a model, Pair, and another model Profile.
An instance of the model Pair will be made with a form that draws from two different Profile instances. So, how do I pre-populate a single form with bits of information from two Profiles?
Two models: Profile & Pair:
class Profile(models.Model):
...
favorites = models.CharField(max_length=150)
class Pair(models.Model):
requester = models.ForeignKey(Profile)
accepter = models.ForeignKey(Profile)
requester_favorite = models.CharField(max_length=50)
accepter_favorite = models.CharField(max_length=50)
The form so far:
class PairRequestForm(forms.Form):
your_favorites = forms.CharField(max_length=50)
partners_favorites = forms.CharField(max_length=50)
Code Explanation: The way it works is, a user(requester) will request the initiation of a pair with the PairRequestForm to the potential accepter.
The form should be pre-populated with the "favorite" of each individual user.
I'm not sure how to wire up the views.py since I need to obtain two objects.
class PairRequestView(FormView):
form_class = PairRequestForm
template_name = 'profile/pair_request.html'
success_url = "/"
def is_valid(self, form):
return
note: The pair form must be pre-populated with current information from the Profile. However, the form will not update any old information(will not save() any Profiles)--it will simply create a new Pair instance.
Assuming that the accepters page is visited at something like /profiles/2, you can capture the id of the accepter from the url, as you normally would.
Couple of things - you don't need to save the favourites into the Pair model, since for any use of the Pair model, you can just access them by doing
`p = Pair.objects.get(id=1) #or whatever query
p.requester.favourites
> Some of my favourites
p.accepter.favourites
> Some of your favourites.
If you, the proposer, are id=1, and visiting mine, the accepter's page (id=2), then you can populate the form - (I've done this in a very long manner for clarity)
accepterobj = Profile.objects.get(id=id_from_url_for_page)
proposerobj = Profile.objects.get(id=request.user.id)
form = PairRequestForm(accepter=accepterobj,
proposer=proposerobj,
accepter_favourites=accepterobj.favourites,
proposerobj_favourites=proposerobj.favourites)
in your CBV, you can do the queries above by overriding the get_initial method on your PairRequestView.
def get_initial(self):
"""
Returns the initial data to use for forms on this view.
"""
initial = super(PairRequestView, self).get_initial()
initial['proposer'] = self.request.user
...etc
return initial

Using an instance's fields to filter the choices of a manytomany selection in a Django admin view

I have a Django model with a ManyToManyField.
1) When adding a new instance of this model via admin view, I would like to not see the M2M field at all.
2) When editing an existing instance I would like to be able to select multiple options for the M2M field, but display only a subset of the M2M options, depending on another field in the model. Because of the dependence on another field's actual value, I can't just use formfield_for_manytomany
I can do both of the things using a custom ModelForm, but I can't reliably tell whether that form is being used to edit an existing model instance, or if it's being used to create a new instance. Even MyModel.objects.filter(pk=self.instance.pk).exists() in the custom ModelForm doesn't cut it. How can I accomplish this, or just tell whether the form is being displayed in an "add" or an "edit" context?
EDIT: my relevant code is as follows:
models.py
class LimitedClassForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(LimitedClassForm, self).__init__(*args, **kwargs)
if not self.instance._adding:
# Edit form
clas = self.instance
sheets_in_course = Sheet.objects.filter(course__pk=clas.course.pk)
self.Meta.exclude = ['course']
widget = self.fields['active_sheets'].widget
sheet_choices = []
for sheet in sheets_in_course:
sheet_choices.append((sheet.id, sheet.name))
widget.choices = sheet_choices
else:
# Add form
self.Meta.exclude = ['active_sheets']
class Meta:
exclude = []
admin.py
class ClassAdmin(admin.ModelAdmin):
formfield_overrides = {models.ManyToManyField: {
'widget': CheckboxSelectMultiple}, }
form = LimitedClassForm
admin.site.register(Class, ClassAdmin)
models.py
class Course(models.Model):
name = models.CharField(max_length=255)
class Sheet(models.Model):
name = models.CharField(max_length=255)
course = models.ForeignKey(Course)
file = models.FileField(upload_to=getSheetLocation)
class Class(models.model):
name = models.CharField(max_length=255)
course = models.ForeignKey(Course)
active_sheets = models.ManyToManyField(Sheet)
You can see that both Sheets and Classes have course fields. You shouldn't be able to put a sheet into active_sheets if the sheet's course doesn't match the class's course.

default value for ChoiceField in modelform

I have problem with django:
models.py:
SUSPEND_TIME = (
('0', '0'),
('10', '10'),
('15', '15'),
('20', '20'),
class Order(models.Model):
user = models.ForeignKey(User)
city = models.CharField(max_length=20)
...
processed = models.BooleanField(default=False)
suspend_time = models.CharField(max_length=2, choices=SUSPEND_TIME, default='0')
..
form.py:
class OrderForm(forms.ModelForm):
class Meta:
model = Order
fields = ('suspend_time', 'processed')
view.py:
try:
order = Order.objects.get(id=order_id)
except Order.DoesNotExist:
order = None
else:
form = OrderForm(request.POST, instance=order)
if form.is_valid():
form.save()
....
then I send ajax request to update instance with only "processed" param..
form.is_valid is always False if I don't send "suspend_time" !
if request contain {'suspend_time': 'some_value' ...} form.is_valid is True
I don't understand why ? suspend_time has default value.. and order.suspend_time always has some value: default or other from choices.
why after form = OrderForm(request.POST, instance=order) form['suspend_time'].value() is None, other fields (city, processed) has normal value .
The behavior is as expected. The form should validate with given data. i.e. Whatever required fields are defined in the form, should be present in the data dictionary to instantiate it.
It will not use data from instance to populate fields that are not provided in form data.
Text from django model forms
If you’re building a database-driven app, chances are you’ll have forms that map closely to Django models. For instance, you might have a BlogComment model, and you want to create a form that lets people submit comments. In this case, it would be redundant to define the field types in your form, because you’ve already defined the fields in your model.
For this reason, Django provides a helper class that let you create a Form class from a Django model.