Model formsets and Date fields - django

I have a model formset on a model with a couple of date fields - which again is a DateTimeField in the model.
But when it displays in the template, it is shown as a text field.
How can I show it as a drop down box ?
WFormSet = inlineformset_factory(UserProfile, W, can_delete=False,exclude=[<list of fields to be excluded>], extra=3)
This is how I am intializing the modelformset.
How do I override these settings

The usual way to do this is to override the default field types in your ModelForm definition.
The example below would work if you had a DateField in your model (I note you have a DateTimeField... I'll come back to that in a sec). You're going to be specifying the exact same field type as would normally be specified, but you'll pass a different widget to the form field constructor.
from django.db import models
from django import forms
from django.forms.extras import SelectDateWidget
class MyModel(models.Model):
a_date_field = models.DateField()
class MyModelForm(forms.ModelForm):
a_date_field = forms.DateField(widget=SelectDateWidget())
class Meta:
model = MyModel
There isn't, to my knowledge, an equivalent widget provided for the DateTimeField in Django 1.0.x. In this case, you'll want to make a custom widget, perhaps subclassing SelectDateWidget. I note from a quick google on SelectDateTimeWidget that there have been several others who've been making what appear to be the widget you're seeking. I've not used them, so caveat emptor, but something like this SelectDateTimeWidget patch might be a good place to start.
Edit: When using a ModelFormset or InlineModelFormset, you can still achieve this by passing form=MyModelForm to the inlineformet_factory function:
MyModelFormset = inlineformset_factory(MyParentModel, MyModel, form=MyModelForm)
This works because the two model formset factories actually call the regular formset_factory constructor in their own implementations. It's a little hard to figure out because it's not explicitly stated in the docs... rather the Django docs allude to this ability by mentioning in passing that the model formset factories extend the normal formset_factory. Whenever I'm in doubt, I open django/forms/models.py to check out the full signature of the formset factory functions.

Related

Django 1.9: How to make a dynamic form?

I have a model called Course:
class Course(models.Model):
number_of_semesters = models.PositiveIntegerField()
field = models.CharField(max_length=30)
qualification = models.ForeignKey(Qualification, on_delete=models.CASCADE)
I am trying to get a form in which you can input as many courses as the user wants from the webpage. How will I do this?
I know this is an old one, but I would recommend you to use Django Rest Framework. Although it is kind of tricky at first, you can use the ViewSets and Serializers to get multiple objects and save them in your database at once. (BTW, even though it is used for API's you can easily substitute the normal Django views with the ViewSets and use them as a standard).
I know this is not actually what you asked, but I have been developing in Django for a while now and I haven't been able to use the formsets in a clean way to save N objects without knowing N at first.
If you decide to go with my proposal, I would recommend you to read the following:
Viewsets
Serializers (they are basically the same as the DjangoForms)
Nested Serializers (for rendering/creating/linking your ForeignKey instance)
# SERIALIZER
from rest_framework import serializers
class QualificationSerializer(serializers.ModelSerializer):
class Meta:
model = Qualification
fields = (
# Insert the fields here, just like a form
)
class CourseSerializer(serializers.ModelSerializer):
qualification = QualificationSerializer() # Nested serializer
class Meta:
model = Course
fields = (
'number_of_semesters', 'field', 'qualification',
)
One way you could do this is to not use formsets but to get creative with the prefix that you use to load a form with. For example the + button loads an empty form with a prefix based on a counter posted to the view (including a tag, something like "course-4", so you get the form with SomeForm(request.POST, prefix="course-4")). When it's time to validate/save the view you simply parse the prefixes (with a regex) from the POST and save a form for every one of them.
It seems like a bit more work than to simply use formsets but every time I've tried to use them I had to abandon them at some point because they didn't provide enough flexibility.

django generic view update/create: update works but create raises IntegrityError

I'm using CreateView and UpdateView directely into urls.py of my application whose name is dydict. In the file forms.py I'm using ModelForm and I'm exluding a couple of fields from being shown, some of which should be set when either creating or updating. So, as mentioned in the title, update part works but create part doesn't which is obvious because required fields that I have exluded are sent empty which is not allowed in my case. So the question here is, how should I do to fill exluded fields into the file forms.py so that I don't have to override CreateView?
Thanks in advance.
Well, you have to set your required fields somewhere. If you don't want them to be shown or editable in the form, your options are to set them in the view (by using a custom subclass of CreateView) or if appropriate to your design in the save method of the model class. Or declare an appropriate default value on the field in the model.
It would also work to allow the fields into the form, but set them to use HiddenInput widgets. That's not safe against malicious input, so I wouldn't do that for purely automated fields.
You cannot exclude fields, which are set as required in the model definition. You need to define blank=True/null=True for each of these model fields.
If this doesn't solve your issue, then please show us the model and form definitions, so we know exactly what the code looks like.

Django Class-Based Generic Views and ModelForms

Like much documentation on generic views in Django, I can't find docs that explicitly describe how to use the new Class-Based Generic Views with Django Forms.
How is it done?
What have you tried so far? The class based views are pretty new, and the docs don't have a lot of examples, so I think you're going to need to get your hands dirty and experiment!
If you want to update an existing object, then try using UpdateView. Look at the mixins it uses (e.g ModelFormMixin, SingleObjectMixin, FormMixin) to see which methods you can/have to override.
Good luck!
The easiest way to use model forms with class based views is to pass in the model and keep a slug / pk captured in url, in which case you will not need to write any view code.
url(r'^myurl/$', CreateView.as_view(model=mymodel))
#Creates a model form for model mymodel
url(r'^myurl/(?<pk>\w+)/$', UpdateView.as_view(model=mymodel))
#Creates a model form for model mymodel and updates the object having pk as specified in url
url(r'^myurl/(?<slug>\w+)/$', DeleteView.as_view(model=mymodel, slug_field="myfield"))
#Creates a model form for model mymodel and deletes the object denoted by mymodel.objects.get(my_field=slug)
You can also override methods to obtain more complex logic. You can also pass a queryset instead of a model object.
Another way is to create a modelform in forms.py and then pass form_class to the url as
url(r'^myurl/$', CreateView.as_view(form_class=myform))
This method allows you to define form functions as well as Meta attributes for the form.

how to find associated Django ModelForm given the Model

I have dozens of Models, each with ONE associated ModelForm (whose Meta.model refers to the Model in question).
E.g.
class FooModel(Model):
pass
class FooModelForm(ModelForm):
class Meta:
model = FooModel
# current approach using a classmethod
FooModelForm.insert_in_model() # does cls.Meta.model.form = cls
So, obviously, it's easy to find FooModel given FooModelForm. What I want is to know the best way to do the REVERSE: find FooModelForm when I am presented with FooModel or even the string "Foo".
Assume only one ModelForm for each model, although solutions that return multiple are fine.
My current approach is to stash the model in the form class (as shown above), but I'm interested in knowing better approaches especially ones that could compute it centrally (without the final line above).
EDIT: I've reviewed things like Django: Display Generic ModelForm or predefined form but I believe this is a simpler question than those. The Django admin code must do something along the lines of what I seek. But get_model equivalent for ModelForms? suggests that might be voodoo and that it would be best to just do dict['Foo']=FooModelForm or its equivalent to keep track of the association explicitly. Seems repetitious.
If you have under 20 forms, sounds like mapping out a dictionary is the easiest way. Django does this kinda thing internally too.
For ModelForms, django admin just creates them on the fly via modelform_factory, so there is no comparable method to get_model
I do see, your method is bullet proof, but requires a line in ever model def.
If you only have one ModelForm per model, you could potentially iterate through the ModelForm subclasses until you find your form.
find FooModelForm when I am presented
with FooModel or even the string
"Foo".
modelforms = forms.ModelForm.__subclasses__()
def get_modelform(model):
try:
return filter(lambda x:x.Meta.model == model, modelforms)[0]
except IndexError:
print "apparently, there wasn't a ModelForm for your model"
If you want to pull the ModelForm as a string, you'll need to make sure both
app_label and __name__ are correct, which means it will be easier to use get_model('app', 'model') in the function.
You could combine this with your method and automatically place an attribute on your models that point to its ModelForm.
Hook into the class_prepared signal at the top of your apps, find the corresponding ModelForm and attach it to your Model class.
Hope that helps or gives you some ideas.

DJANGO - How to generate a form for a model not known in advance because of the contentType instance

I have the following model and it's form:
class Project(models.Model)
class ProjectForm(forms.ModelForm)
class Meta:
Model = Project
So it's easy to create a form by instantiating:
form = ProjectForm()
But in my case, I have several models aside from "Projects", and I don't know in advance for which of these models I will need to create the form.
So I would like to create the form from the ContentType instance of the Project model.
In other words, I'm looking for something that looks like:
myproject = Project()
form = createform(myproject.ContentType)
Presumably you have a certain limited selection of models that might be used. The simplest way is just to create form classes for each of them, then choose the one you need from a dictionary:
MODEL_FORMS = {
MyModel: MyModelForm,
MyOtherModel: MyOtherModelForm
}
my_form_class = MODEL_FORMS[my_project.content_type]
my_form = my_form_class()
Unfortunately, this was the best I could find - but a combination of get_model and form_for_model should do the trick. You'll need to use get_model to load up the model type you want to work on, and then form_for_model to get a form for that model.
Edit: Daniel's solution is a much better one if you know what models you're dealing with.
Thank you to both of you, this helps a lot !
I will go with Daniel's solution as I have a limited number of models.
I think maybe I will need to add model_class() to "my_project.content_type.model_class()" in order to get the model class (to be checked) ?
Just for the record, I had managed to make something work with model formset factories :
from django.forms.models import modelformset_factory
ProjectFormSet = modelformset_factory(my_project.content_type.model_class())
my_form = ProjectFormSet()
but this form would of course not get all the customisations made in my model forms... so that was not a good solution.