Django admin: postgres DateTimeRangeField not displayed properly - django

Some of my models have postgres-specific django.contrib.postgres.fields.DateTimeRangeFields, and those fields are exposed in the corresponding admin panels. I expected that the ranges forms would consist of two Django-style datetime pickers, with a separate one for the date part and a separate part for the time part (just like the DateTimeField would). However, I get two text inputs which expect input in a very particular format. Is there anything I am missing or have to configure separately?
The relevant code is:
from django.contrib.postgres.fields import DateTimeRangeField
...
class MyModel(models.Model):
time_off = DateTimeRangeField()
admin:
#register(MyModel)
class MyModelAdmin(admin.ModelAdmin):
pass

You are looking for SplitDateTimeWidget.
Simply change the admin part as:
class MyModelAdminForm(forms.ModelForm):
class Meta:
model = MyModel
widgets = {
'time_off': RangeWidget(SplitDateTimeWidget())
}
#register(MyModel)
class MyModelAdmin(admin.ModelAdmin):
form = MyModelAdminForm
or use formfield_overrides to override the widget if you wish.

Related

Two model in one UpdateView "Django"

my views :
from .models import Settings, SocialMediaSetting
class UpdateSocialMediaSetting(LoginRequiredMixin, UpdateView):
model = SocialMediaSetting
fields = '__all__'
template_name = "staff/settings/social-media-settings-update.html"
class UpdateSettings(LoginRequiredMixin, UpdateView):
model = Settings
fields = '__all__'
template_name = "staff/settings/settings-update.html"
two different class in models without any relation, I want show both in one html and one form both models has just one object
you'll need to ditch the UpdateView, but this way won't take long to implement
Use a TemplateView (at least you won't have to change your other mixin)
Create two ModelForms
override the get_context_data() to pass the forms to the template
when forms are submitted, override the post() method to save them yourself
mchesler613 wrote an awesome article explaining how to do this here.
(make sure to give him a star)

Django forms: How to simply include all attributes in the associated model

I am working through how to use Django's forms (https://docs.djangoproject.com/en/1.11/topics/forms/#more-on-fields) and I can't see a way to generate a form structure that is based on a defined Model. In Symfony, I remember I was able to get my form to automatically include all parameters of myModel (for example) even if any new attributes were later added to the model.
For example:
class myModel(models.Model):
name = models.CharField(max_length=50)
created=models.DateTimeField(null=False)
modified=models.DateTimeField(null=True)
myParameter= models.IntegerField(default=None)
// ... plus many more parameters
Rather than having to manually type corresponding rows into my class myModelForm(forms.Form):, I'm looking/hoping for a 'catch all'.
from django.forms import ModelForm
class myModelForm(ModelForm):
class Meta:
model = myModel
fields = '__all__'
More details selecting-the-fields-to-use

Hiding a model field in Django admin 1.9

I have registered some models to display in the admin area, but I would like for some fields to be hidden.
As an example, I have a TeachingClasses model with a BooleanField named 'Status' that is set to True or False depending if the class is open or not. But that is set somewhere else in the app. There is no need to have that field displayed in the admin area when someone wants to create a new class to attend.
As such, is there a way to hide that field in the admin area?
I have tried adding this to the app admin.py file but it did nothing
from django.contrib import admin
class MyModelAdmin(admin.ModelAdmin):
class TeachingClasses:
exclude = ('Status',)
but it's not working?
Any clue if this is the right way?
My model:
class TeachingClasses(models.Model):
name = models.Charfield('Class Name',max_lenght=64)
[...]
status = models.BooleanField('Status',default=True)
What you did is not the correct syntax, you need:
class TeachingClassesAdmin(admin.ModelAdmin):
exclude = ('status',)
admin.site.register(TeachingClasses, TeachingClassesAdmin)
Django doc about how to use exclude.
In the admin.py:
class TeachingClassesAdmin(admin.ModelAdmin):
list_display = ('name',) # plus any other fields you'd like to display
admin.site.register(TeachingClasses, TeachingClassesAdmin)`

Change default widgets of Django to custom ones

My usecase: I want to use a different DateInput. But I want to reduce code duplication. I want all forms, which don't explicitly want a different DateInput widget, to use my custom widget.
Any change to solve this without monkey patching?
Example
models.py:
class MyModel(models.Model):
date=models.DateField()
forms.py:
class MyForm(forms.ModelForm):
class Meta:
model=MyModel
The above code should use my custom widget. I don't want to change the above models.py and forms.py, since there are many.
Unfortunately, I don't think you can get this working with your exact code listed above.
Without hacking django, essentially there are 2 parts to this. The first is creating a custom form field, and the second is defaulting your custom model field to your newly created form field.
To create your custom Form Field, you could override the existing django forms.DateField and update the widget.
# form_fields.py
from django.forms import DateField
from myapp.widgets import MyWidget
class MyDateFormField(DateField):
widget = MyWidget
And then after you have your form field created, you're going to have to override the django model field to default to your new form field
# fields.py
from django.db.models import DateField
from myapp.form_fields import MyDateFormField
class MyDateField(MyDateFormField):
def formfield(self, **kwargs):
defaults = {'form_class': MyDateFormField}
defaults.update(kwargs)
return super(DateField, self).formfield(**defaults)
You would then have your custom model field, which you would need to slightly change your code to use.
from myapp.fields import MyDateField
class MyModel(models.Model):
date=MyDateField()
It's not exactly what you were asking for (have to change the model field), but hopefully this gets you in the right direction.
Create your field
Create form that will use this field by default
import this form instead of default form, when you use it
If you're using it in admin:
create your own ModelAdmin that will use your form by default
use that instead of default ModelAdmin.

Dynamical choices in model's field

I want my models to have order field, which will contain order of an item among all items of its kind.
And I want to use choices within that IntegerField, which would contain all the numbers of currently existing items in that table.
So it would need to be dynamic choices.
How do I load all existing "order" values of all existing items in a table, and use this list for choices?
It sounds like you want to build a manager for your model:
models.py
from django.db import models
class OrderManager(models.Manager):
def order_choices(self):
return [(i, i) for i in OrderModel.objects.values_list('order', flat=True)]
class OrderModel(models.Model):
objects = OrderManager()
order = models.IntegerField()
class Meta:
ordering = ['order']
def __unicode__(self):
return '%i' % self.order
forms.py
from django import forms
from yourapp.models import OrderModel
class OrderModelForm(forms.ModelForm):
order = forms.ChoiceField(choices=OrderModel.objects.order_choices())
class Meta:
model = OrderModel
admin.py
from django.contrib import admin
from yourapp.forms import OrderModelForm
from yourapp.models import OrderModel
class OrderModelAdmin(admin.ModelAdmin):
form = OrderModelForm
admin.site.register(OrderModel, OrderModelAdmin)
Edit
Managers are use to make general model queries without having an instance of a model object. If you don't understand the concept of managers, you can still refactor the code out of the manager class, stick it somewhere else and import that function across your code. Managers allow you to abstract custom general queryset that you can reuse. See more details https://docs.djangoproject.com/en/dev/topics/db/managers/
The code without the manager will look like
views.py or some other file
from app.models import OrderModel
def order_choices():
return [(i, i) for i in OrderModel.objects.values_list('order', flat=True)]
From anywhere in your code, if you want to reuse the above multiple times:
from app.views import oder_choices
order_choices()
as opposed to:
from app.models import OderModel
OrderModel.objects.order_choices()
If you only want to use the above once, you can leave it in the forms.py as shown in the other answer. It's really up to you on how you want to refactor your code.
Dont add the choices directly to the model, add them to a form represnting the model later, by overriding the field with a set of choices.
than, do something like:
class MyForm(..):
myfield_order_field = IntegerField(choices = [(i,i) for range(MyModel.objects.count)])
class Meta():
model = MyModel
if you want to use it in the admin, add to your Admin Class:
class MyModelAdmin(admin.ModelAdmin):
...
form = MyForm
it will override this field in the admin too.