I have a model task for which I've written the following generic form to give facility to add a new task:
class AddTask(generic.CreateView):
model = task
fields = ['project','task_name','expected_date']
success_url = reverse_lazy('home')
template_name = 'st_web/addtask.html'
This is working pretty fine. The only problem is that date field is an text type field. I read solutions for similiar questions, one of which proposed writing a date widget in my view like:
from django import forms
........................
class DateInput(forms.DateInput):
input_type = 'date'
.........................
.........................
class AddTask(generic.CreateView):
model = task
fields = ['project','task_name','expected_date']
widgets = {
'expected_date': DateInput()
}
success_url = reverse_lazy('home')
template_name = 'st_web/addtask.html'
However this doesn't work for me. Can please anyone suggest a simple answer(some of them were suggesting adding some i8j.js or something like that but it'd really be helpful if there is a shorter solution available) to this problem? Thanks.
In your forms.py :
from django import forms
class AddTask(forms.ModelForm):
class Meta:
model = task
fields = ('project','task_name','expected_date', )
expected_date = forms.DateField(
widget = forms.DateInput(
attrs= {
'type':'date',
}
)
)
Related
I want to override the basic view in the Article snippet selector, which does not display the checkbox correctly.
class ArticleChooserMixin(ModelChooserMixin):
def get_edit_item_url(self, item):
# for Wagtail 4.x
return reverse(
"wagtailsnippets_app_name_article:edit", args=(quote(item.pk),)
)
class ArticleChooserViewSet(ModelChooserViewSet):
icon = "user"
model = Article
page_title = _("Choose a article")
per_page = 10
order_by = "title"
fields = ["title", "body", "url", "categories", "countries"]
chooser_mixin_class = ArticleChooserMixin
piece of code from the Article model
from dal import autocomplete
...
#register_snippet
class Article(
DraftStateMixin,
RevisionMixin,
index.Indexed,
ClusterableModel,
Orderable,
SourceDataMixin,
):
...
categories = ParentalManyToManyField("app_name.ArticleCategory", blank=True)
countries = ParentalManyToManyField("app_name.Country", blank=True)
...
FieldPanel("categories", widget=autocomplete.ModelSelect2Multiple())
FieldPanel("countries", widget=autocomplete.ModelSelect2Multiple()),
...
Similar problem: https://github.com/wagtail/wagtail-generic-chooser/issues/65
View from the snippet creation how I want it to look and form elements that display the currently selected item
current problem
As per the wagtail-generic-chooser docs - The creation form presented within the chooser is a plain Django ModelForm, which does not make use of the model's panel definition. If you pass a fields attribute on the ViewSet class, it will construct a ModelForm with all of those fields at their default settings. To override this, you can define your own ModelForm class and pass that as form_class:
from django import forms
class ArticleForm(forms.ModelForm):
class Meta:
model = Article
fields = ["title", "body", "url", "categories", "countries"]
widgets = {
"categories": autocomplete.ModelSelect2Multiple(),
"countries": autocomplete.ModelSelect2Multiple(),
}
class ArticleChooserViewSet(ModelChooserViewSet):
# ...
form_class = ArticleForm
I have a model that looks like this:
models.py
class BHA_List(models.Model):
well = models.ForeignKey(WellInfo, 'CASCADE', related_name='bha_list')
bha_number = models.CharField(max_length=100)
class BHA_Drill_Bit(models.Model):
bha_number = models.ForeignKey(BHA_List, 'CASCADE', related_name='bha_drill_bit')
bit_type = models.CharField(max_length=111)
class BHA_overall(models.Model):
bha_number = models.ForeignKey(BHA_List, 'CASCADE', related_name='bha_overall')
drill_str_name = models.CharField(max_length=111)
class BHA_Motor(models.Model):
bha_number = models.ForeignKey(BHA_List, 'CASCADE', related_name='bha_drill_bit')
motor_type = models.CharField(max_length=111)
BHA_List is a parent model, and the rest are child models related by ForeignKey. The screenshot is the page I want to create
So, I want to generate a base page using one of the instances in model = BHA_List. In this page, I want to edit model instances that are related to BHA_List by ForeignKey relationship.
I currently have a view that looks like this, but its wrong:
class BHA_UpdateView(UpdateView):
model = BHA_List
pk_url_kwarg = 'pk_alt'
form_class = BHA_overall_Form
By setting model = BHA_List, I was able to get one of the instances in BHA_List, and generate url from it. Right now my views correctly return one of the instances in BHA_List: BHA 1
I attempted to edit child models by setting form_class = BHA_overall_Form. But this doesn't do anything, though it displayed form fields on the user side. After editing and clicking Submit button, the changes are not saved in DB. Someone pointed out that this is because my model in UpdateView and form does not match, as I set model = BHA_List, but form_class = BHA_overall_form.
How can I resolve this issue? Someone else also pointed out using multiple views, but I don't really know how to do it, as I'm very new to Django. Any help will be greatly appreciated. Thanks!
Just so that you know. UpdateView can be used if you want to update a single row in one table. When you set model = BHA_LIST you are saying Django. Hey, Django I want to update this model so render me a form with the fields from this table. You can do this by just setting fields attr on the model or use a form like you did which will customize which fields are shown. Now the good thing about allowing to set our own form is. Though we create a modelForm we can also add extra fields inside it. Now your BHAOverallForm should look like this to accommodate all the fields you need.
forms.py
class BHAOverallForm(forms.ModelForm):
well = models.ForeignKey(WellInfo, 'CASCADE', related_name='bha_list')
bha_number = models.CharField(max_length=100)
bit_type = models.CharField(max_length=111
drill_str_name = models.CharField(max_length=111)
motor_type = models.CharField(max_length=111)
class Meta:
model = BHAList
you can use this form inside your form like you do now. You can also add clean_field to add validations. Now coming to the update part. your views should look like this
views.py
class BHAUpdateView(UpdateView):
model = BHAList
form_class = BHAOverallForm
def form_valid(self, form):
super(BHAUpdateView, self).form_valid(form) # save BHAList to the DB
bha_list = form.instance
bha_drill_bit = bha_list.bhadrillbit_set.first() # assuming you have only one drill_bit per list, if you need more modify your question accordingly.
bha_drill_bit.bit_type = form.cleaned_data.get("bit_type)
bha_drill_bit.save()
# you can do the same for other models as well.
I have a simple model in django with a field using choices. As it is now, I am forced to use one of the available choices, how can I be able to use those choices and also be able to enter text manually?
WHERE_CHOICES = (
('CHL', 'Center HL'),
('CHD', 'Center HD')
)
class Event(models.Model):
ev_start = models.DateTimeField()
ev_end = models.DateTimeField()
where = models.CharField(max_length=3, default='CHL', choices=WHERE_CHOICES)
Thanks
You can override the admin form field widget with a datalist tag.
It would look like that (using the floppyforms library):
class EventAdminForm(ModelForm):
class Meta:
model = Event
fields = "__all__"
widgets = {
'where': floppyforms.widgets.Input(datalist=[v[0] for v in Event.WHERE_CHOICES])
}
class EventAdmin(admin.ModelAdmin):
form = EventAdminForm
admin.site.register(Event, EventAdmin)
I took a look at following SO question, but had no luck. I don't know, maybe I didn't understand the answers.
1) How to remove the “Currently” tag and link of a FileInput widget in Django?
2) Django ModelForm ImageField
My form:
class SettingsForm(forms.ModelForm):
company_logo = forms.ImageField(label=_('Company Logo'),required=False, error_messages = {'invalid':_("Image files only")})
class Meta:
model = Settings
fields = ("company_logo")
....
My model:
class Settings(models.Model):
strg=CustomFileSystemStorage(strict_name='images/company_logo.png',save_format='PNG')
company_logo=models.ImageField(upload_to='images',blank=True,null=True,storage=strg)
.....
After rendering:
I see from the first link, that the models.ImageField inherits the FileInput and adds the extra stuff, but I do not understand how to overcome this?
Thanks in advance.
The solution is:
class SettingsForm(forms.ModelForm):
company_logo = forms.ImageField(label=_('Company Logo'),required=False, error_messages = {'invalid':_("Image files only")}, widget=forms.FileInput)
class Meta:
model = Settings
fields = ("company_logo")
....
I added the widget forms.FileInput, in order to tell the ImageField to use the basic field, not the one inherited from FileInput.
#mtndesign, you might also want a "remove" option, which you can place wherever you like in your template.
class MyForm(forms.ModelForm):
photo = forms.ImageField(required=False, widget=forms.FileInput)
remove_photo = forms.BooleanField(required=False)
...
def save(self, commit=True):
instance = super(MyForm, self).save(commit=False)
if self.cleaned_data.get('remove_photo'):
try:
os.unlink(instance.photo.path)
except OSError:
pass
instance.photo = None
if commit:
instance.save()
return instance
You can change the widget used to render the form field by specifying it on initializing:
class SettingsForm(forms.ModelForm):
company_logo = forms.ImageField(label=_('Company Logo'),required=False, \
error_messages ={'invalid':_("Image files only")},\
widget=FileInput)
See the docs for widgets.
I have a model with a boolean value like that:
class TagCat(models.Model):
by_admin = models.BooleanField(default=True)
This appears as a checkbox in admin.
How could I use this as a radio button in admin?
Also, how do I make it be always with a certain selected value in admin?
Also, I want the default value to be the opposite, when a non-admin user adds a TagCat. This field should be hidden from him.
Can someone tell me how to do this? Django documentation doesn't seem to go in such details.
UPDATE 1: Code that gets me done with 1) (don't forget tot pass CHOICES to the BooleanField in the model)
from main.models import TagCat
from django.contrib import admin
from django import forms
class MyTagCatAdminForm(forms.ModelForm):
class Meta:
model = TagCat
widgets = {
'by_admin': forms.RadioSelect
}
fields = '__all__' # required for Django 3.x
class TagCatAdmin(admin.ModelAdmin):
form = MyTagCatAdminForm
admin.site.register(TagCat, TagCatAdmin)
The radio buttons appear ugly and displaced, but at least, they work
I solved with following info in MyModel.py:
BYADMIN_CHOICES = (
(1, "Yes"),
(0, "No"),
)
class TagCat(models.Model):
by_admin = models.BooleanField(choices=BYADMIN_CHOICES,default=1)
There is another way to do this that is, IMO much easier if you want every field of the same type to have the same widget. This is done by specifying a formfield_overrides to the ModelAdmin. For example:
from django.forms.widgets import Textarea
class MyModelAdmin(admin.ModelAdmin):
formfield_overrides = {
models.TextField: {'widget': Textarea},
}
More in the docs: https://docs.djangoproject.com/en/1.4/ref/contrib/admin/#django.contrib.admin.ModelAdmin.formfield_overrides
Here is a more dynamic extension of mgPePe's response:
class MyAdminForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(MyAdminForm, self).__init__(*args, **kwargs)
self.fields['by_admin'].label = 'My new label'
self.fields['by_admin'].widget = forms.RadioSelect()
class Meta:
model = TagCat
class MyAdmin(admin.ModelAdmin):
fields = ['name', 'by_admin']
form = MyAdminForm
This way you get full control over the fields.