Datetime returning different date to input - django

I am having some issues with datetime and datepicker. I have a model form with 2 date picker field (To and From), the date can be selected and saved. The problem is, when I go to edit form, the dates seem to show up as either a day ahead/behind of input date or just show up the current date.
My model.py:
from_when = DateTimeField(_('From'), blank=True, null=True)
to_when = DateTimeField(_('To'), blank=True, null=True)
forms.py:
class ScheduleForm(ModelForm):
class Meta:
model = Schedule
fields = ['from_when', 'to_when',]
def __init__(self, *args, **kwargs):
super(ScheduleForm, self).__init__(*args, **kwargs)
self.name = 'scheduleform'
self.title = _('Add/Edit Schedule')
self.helper = FormHelper()
self.helper.form_tag = False
self.form_layout()
def form_layout(self):
self.helper.layout = Layout(
Div(
Div(
Div(
# use the jQuery datepicker plugin, if available
Field('from_when', css_class='datepicker'),
# use the jQuery datepicker plugin, if available
Field('to_when', css_class='datepicker'),
css_class='span4',
),
css_class='row-fluid',
),
),
)
def save(self, force_insert=False,
force_update=False, *args, **kwargs):
course = super(ScheduleForm, self).save(
commit=True, *args, **kwargs)
return course
Any ideas why this problem may occur?

Related

django - logging edit event - need to get id of logged in user

I've a product-stock model as given below.
TRANSACTION_TYPE=(('I','Stock In'),('O','Stock Out'))
class Stock(models.Model):
product=models.ForeignKey('product.Product', blank=False,null=False)
date=models.DateField(blank=False, null=False,)
quantity=models.PositiveIntegerField(blank=False, null=False)
ttype=models.CharField(max_length=1,verbose_name="Transaction type",choices=TRANSACTION_TYPE, blank=False, db_index=True)
I need to log the update activity on this model, along with the id of the user who updated it.
ACTIONS=(('EC','Edit Category'),
('EG','Edit Group'),
('EP','Edit Product'),
('ES','Edit Stock'))
class MyLog(models.Model):
user=models.ForeignKey(auth.models.User, blank=False)
action= models.CharField(max_length=2, choices=ACTIONS, null=False,blank=False)
date=models.DateTimeField(blank=False, auto_now=True)
data = JSONField()
I've the added following code to the Stock model.
def __init__(self, *args, **kwargs):
super(Stock, self).__init__(*args, **kwargs)
if self.pk != None :
self.__important_fields = ['product','date', 'quantity', 'ttype', ]
for field in self.__important_fields:
setattr(self, '__original_%s' % field, getattr(self, field))
field_name='__original_%s' % field
def save(self, *args, **kwargs):
if self.pk != None :
print("Editing")
flag=False
log=MyLog(user=?,action='ES')
log.data=[]
for field in self.__important_fields:
original=getattr(self, '__original_%s' % field)
if original != getattr(self, field):
flag=True
log.data.append({field : str(original)})
if flag:
log.save()
else:
print("Adding")
super(Stock, self).save(*args, **kwargs)
This works, when I hard code a user object into the line log=MyLog(user=?,action='ES').
I need to log the id of the user who performed this edit operation.
How can I achieve this?
Thanks.
Here's how I finally achieved my goal.
Instead of logging the event from the model, I switched my code to the forms.
Here's my final code.
mylog app model
ACTIONS=(('EC','Edit Category'),
('EG','Edit Group'),
('EP','Edit Product'),
('ES','Edit Stock'))
class MyLog(models.Model):
user=models.ForeignKey(settings.AUTH_USER_MODEL, blank=False)
model_id=models.IntegerField(default=0)
action= models.CharField(max_length=2, choices=ACTIONS, null=False,blank=False)
date=models.DateTimeField(blank=False, auto_now=True)
old_data = JSONField(default=None)
new_data = JSONField(default=None)
stock app - update view
class UpdateStock(UpdateView):
model=Stock
form_class=UpdateStockForm
def get_form_kwargs(self):
kwargs = super( UpdateStock, self).get_form_kwargs()
kwargs.update({'user_id': self.request.user.id})
return kwargs
stock app - update form
class UpdateStockForm(forms.ModelForm):
def __init__(self,pk= None, *args, **kwargs):
self.user_id=kwargs.pop('user_id')
super(UpdateStockForm, self).__init__(*args, **kwargs)
def clean(self):
cleaned_data = super(UpdateStockForm, self).clean()
quantity = cleaned_data.get('quantity')
date= cleaned_data.get('date')
priv_quantity=self.instance.quantity
priv_date=self.instance.date
if priv_quantity!=quantity or priv_date != date:
#log!
log=MyLog(user=auth.models.User.objects.get(pk=self.user_id),action='ES', model_id=self.instance.id)
log.old_data=[]
log.old_data.append({'date' : str(priv_date), 'quantity':priv_quantity })
log.new_data=[]
log.new_data.append({ 'date' : str(date), 'quantity':quantity })
log.save()
return cleaned_data

django can't relabel empty label in TypedChoiceField

I can't seem to relabel the empty label in a form's ModelChoiceField.
I have tried. (note I am using django crispy forms for the form layout - shouldn't interfere with this)
Forms.py
class PaymentForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['payment_day'].empty_label = 'test something'
self.helper = FormHelper(self)
self.helper.label_class = 'sr-only'
self.helper.form_tag = False
self.helper.layout = Layout(
......
PrependedText('payment-day', '<i class="fa fa-calendar"></i>', placeholder="What"),
)
class Meta:
model = DirectDebit
fields = [
......
'payment_day',
]
models.py
class DirectDebit(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL)
......
DAYS_OF_MONTH_CHOICES = [(i, i) for i in range(32)]
payment_day = models.IntegerField(choices=DAYS_OF_MONTH_CHOICES)
time_stamp = models.DateField(auto_now=True)
By the time you set empty_label it may be too late, as the field's choices have already been calculated. Try reassigning the queryset to itself, to see whether that triggers the choices to be recalculated.
super().__init__(*args, **kwargs)
self.fields['payment_day'].empty_label = 'test something'
self.fields['payment_day'].queryset = self.fields['payment_day'].queryset
Solved with:
self.fields['payment_day'].choices = [('', '---- Please select your payment day ----')] + list(
self.fields['payment_day'].choices[1:])

Pass parameters to Django class meta

I am trying to display a form with Django, but I want to remove a field if the user language is 'en'. I would like to avoid doing it in Javascript or doing a second template just for it. So I wonder if it possible to pass parameter to the Meta() class of my UserForm() class. That way I could pass the user and check with an if statement his language.
Here is what I have so far:
class UserForm(forms.ModelForm):
first_name = forms.CharField(required=True, label=_('*First name'))
last_name = forms.CharField(required=True, label=_('*Last name'))
postal_code = FRZipCodeField(required=False, label=_('My postcode'))
birthday = forms.DateField(
widget=forms.DateInput(format='%d/%m/%Y'),
required=False,
input_formats=['%d/%m/%Y'],
label=_('My birthday'))
def __init__(self, *args, **kwargs):
super(UserForm, self).__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.layout = Layout(
Field('gender'),
Field('first_name'),
Field('last_name'),
Field('birthday'),
Field('country'),
Field('language'),
Field('payment_preference'),
Div('addr1', css_class='hidden', css_id='addr1_container'),
Div('addr2', css_class='hidden', css_id='addr2_container'),
Div('addr3', css_class='hidden', css_id='addr3_container'),
Div('postal_code', css_class='hidden', css_id='pc_container'),
Div('city', css_class='hidden', css_id='city_container'),
ButtonHolder(
Submit('save', _('update'), css_class='pull-right'),
)
)
class Meta():
model = User
fields = (
"first_name", "last_name", "gender", "birthday", "country",
"payment_preference", "addr1", "addr2", "addr3", "postal_code",
"city", "language",)
With an if, I could set two different fields variable in the Meta() class and so show two different forms for each user language.
You can't pass it into the Meta, but you can pass it into the __init__ and hide the field you want to hide:
class UserForm(forms.ModelForm):
# ... as before
def __init__(self, user, *args, **kwargs):
super(UserForm, self).__init__(*args, **kwargs)
if user.language == 'en':
self.fields['field_name'].widget = forms.HiddenInput()
# ... as before
Then when you call the form, pass the user as the first argument:
form = UserForm(request.user, ...)

Creating form widgets based on instance values

I have the following model:
VARIABLE_CHOICES = (
('bool', 'On/Off'),
('date', 'Date'),
('float', 'Number'),
('text', 'Text'),
)
class LetterVariable(models.Model):
name = models.CharField(max_length=20)
type = models.CharField(max_length=5, choices=VARIABLE_CHOICES)
data = models.CharField(max_length=100)
I want to create a form that when I pass it an instance of LetterVariable from the db it will create the corrosponding widget for data bassed upon type.
Any ideas how I might do this?
class LetterVariableForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(LetterVariableForm, self).__init__(*args, **kwargs)
if not self.instance:
raise Exception('You forgot the instance!');
if self.instance.type == 'something':
self.fields['data'].widget = forms.SomeWidget()

Dynamic Form fields in `__init__` in Django admin

I want to be able to add fields to django admin form at runtime. My model and form:
#admin.py
class SitesForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(SitesForm, self).__init__(*args, **kwargs)
self.fields['mynewfield'] = forms.CharField()
class SitesAdmin(admin.ModelAdmin):
form = SitesForm
admin.site.register(Sites,SitesAdmin)
#model.py
class Sites(models.Model):
url = models.URLField(u'URL')
is_active = models.BooleanField(default=True, blank=True)
is_new = models.BooleanField(default=False, blank=True)
group = models.ForeignKey('SitesGroup')
config = models.TextField(blank=True)
Field mynewfield isn't displayed in form. Why?
You shouldn't be adding a new field to your form in that way, you can just do it as you would any other field and the form will contain both the Model's original fields and your new fields:
class SitesForm(forms.ModelForm):
mynewfield = forms.CharField(max_length=255, blank=True)
class Meta:
model = Sites
class SitesAdmin(admin.ModelAdmin):
form = SitesForm
admin.site.register(Sites, SitesAdmin)
Edit: Sorry, should have read what you had written a little better. If you want a dynamic field like that, then you need to do the following and it will do exactly what you want:
class SitesForm(forms.ModelForm):
class Meta:
model = Sites
def __init__(self, *args, **kwargs):
self.base_fields['mynewfield'] = forms.CharField(max_length=255, blank=True)
super(SitesForm, self).__init__(*args, **kwargs)
class SitesAdmin(admin.ModelAdmin):
form = SitesForm
admin.site.register(Sites, SitesAdmin)
It's the base_fields that gets composed by the metaclass that holds the fields that the form will use.
Solution:
class AdminForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(AdminForm, self).__init__(*args, **kwargs)
self.fields.insert(1, 'myfield', forms.CharField())
class MyAdmin(admin.ModelAdmin):
form = AdminForm
def get_fieldsets(self, request, obj=None):
return (
(None, {
'fields': (..., 'myfield',),
}),
)