Map multiple WTForm fields to one attribute using Flask-WTForm - python

I have a form that maps correctly to my model. What I want to do is have users input their date of birth using three SelectField (day, month, year) and write the combination of those three values to my model.dateOfBirth. I know of the existing DateField and DateTimeField options, but neither of them are suitable.
I've attempted this using a FormField but it fails when I call populate_obj on the whole Form 'str' object has no attribute 'day', assuming that it is trying to set model.dateOfBirth.day which of course, doesn't exist.
I can pull all the relevant data from form.data and write to model outside of populate_obj, but I can't seem to remove the dateOfBirth data to stop populate_obj from failing. There are of course other questions about how I could prefill the form data when passing obj on form creation, but I'm willing to sacrifice that for now.
I've looked at using a FieldList, but the docs say that it gives all its data back in a list, instead of a dict, which will still give me the same issues
Forms
class DOBForm(Form):
day = SelectField(u'Please enter your date of birth',
choices=days,
validators=[InputRequired(message=u' ')]
)
month = SelectField(u' ',
choices=months,
validators=[InputRequired(message=u' ')]
)
year = SelectField(u' ',
choices=years,
validators=[InputRequired(message=u' ')]
)
and
class MainForm(Form):
dateOfBirth = FormField(DOBForm)
Model
class Model
dateOfBirth = db.Column('dateOfBirth', Date)

You can write a function for this.
from datetime import datetime
def date_of_birth(**kwargs):
day = kwargs['day']
month = kwargs['month']
year = kwargs['year']
strip="-"
seq = (day,month,year)
date = datetime.strptime(strip.join(seq) , '%d-%m-%Y')
birthday = stringDate.strftime('%d-%m-%Y')
dob = Model()
dob.dateOfBirth = birthday
session = Session()
session.add(dob)
session.commit()
retval = row2dict(dob)
session.close()
return retval
Now you can call this function.
I don't test this function yet. If you get any error or have any query , let me know..

Related

Django Timezone filter returns wrong results

I wrote the following code:
date = self.request.query_params.get('date')
queryset = Fixture.objects.all().order_by('-date')
if(date):
date = pytz.utc.localize(datetime.strptime(date, "%Y-%m-%d")).astimezone(pytz.UTC)
queryset = Fixture.objects.filter(date__date=date).order_by('date')
Upon excuting this with date = "2020-09-02" the queryset returns values containing the date "2020-09-03". How come this happens and how can this be solved?
If you want to work with a date, why make it a datetime first? Your parsing could be simplified.
date = self.request.query_params.get('date')
queryset = Fixture.objects.all().order_by('-date')
if date:
date = datetime.strptime(date, "%Y-%m-%d").date()
queryset = Fixture.objects.filter(date__date=date).order_by('date')
But this parsing is also is sensitive for wrongly inserted data, and you'll get an error. Best practice imo would be creating a simple form with a DateField.
class ParseDateForm(forms.Form):
date = forms.DateField()
# This somewhere in a method
form = ParseDateForm(data=self.request.query_params)
queryset = Fixture.objects.all().order_by('-date')
if form.is_valid():
date = form.cleaned_data['date']
queryset = Fixture.objects.filter(date__date=date).order_by('date')

Django model history by date and datetime

Assume I have model like this:
class Account(models.Model):
balance = models.IntegerField()
debt = models.IntegerField()
history = HistoricalRecords()
I'm using django-simple-history to get instance of the model as it would have existed at the provided date and time:
inst = Account.history.as_of(datetime.datetime.now().date)
It's working fine, but I want to get instance where balance field is represented as it would have existed at the provided date and time, and then debt field will be most recent of that date. I don't know if this is possible, didn't find anything about that.
The history ORM will return back a model based off of the one you submitted, as it existed at that point in time.
account = Account.objects.create(balance=1, debt=1)
account.save()
history_obj = account.history.last()
print(history_obj.debt) # returns 1
account.debt = 222
account.save()
new_history_obj = account.history.last()
print(new_history_obj.debt) # returns 222
Assuming you're using the Account.history.as_of() method to return the history object that you intend to be reading from, you could do this:
yesterday = datetime.datetime.now() - datetime.timedelta(days=1)
history_obj = Account.history.as_of(yesterday)
print(history_obj.debt) # returns not the current debt, but the debt as-of yesterday
Unless I'm misunderstanding what you're hoping to accomplish, you could just do this with what you have in your question:
inst = Account.history.as_of(datetime.datetime.now().date)
print(inst.debt)

Django view objects filter with timezone.now().date or timezone.now().time-> expected string or bytes-like object

Hi i have some Django 11 project, my model look like
class Event(models.Model):
name = models.CharField(max_length=100, unique=True)
title = models.CharField(max_length=100)
info = models.CharField(max_length=100)
image = models.ImageField(upload_to='events/%Y/%m/%d')
start_date = models.DateField(default=timezone.now)
start_time = models.TimeField(default=timezone.now)
stop_date = models.DateField(default=timezone.now)
stop_time = models.TimeField(default=timezone.now)
place = models.ForeignKey('places.Place', on_delete=models.CASCADE)
company = models.ForeignKey('companies.Company', on_delete=models.CASCADE)
and my view look like
def place_website(request, place_id):
place_template = get_template('room.html')
place_obj = Place.objects.filter(id=place_id)
# filter for event obejts only for requested place, filtered for now and next events
place_event_now = Event.objects.filter(place=place_id, start_date=timezone.now().date, stop_date__gte=timezone.now().date)
place_events_next = Event.objects.filter(place=place_id, start_date=timezone.now(), stop_date__gte=timezone.now()).order_by('start_time')
place_context = {
'place_obj': place_obj,
'place_event_now': place_event_now,
'place_events_next': place_events_next,
}
return HttpResponse(place_template.render(place_context))
the thing i want to manage is to pass to template the list of filtered Event objects based on time.
Lets pick this line
place_event_now = Event.objects.filter(place=place_id, start_date=timezone.now().date, stop_date__gte=timezone.now().date)
it couse error "expected string or bytes-like object" but when i remove ".date" from "timezone.now()" error disappear (then filter do nothing) but i want to compare date to date and time to time.
How to do this properly ?
This approach to filter objects in view rather than in template is proper?
###### UPDATE ########
Its werid because after correction now i have no error but queryset is not filtered properly, look like only two first parameter is filtering ok and the another two is causing empty queryset.
place_event_now = Event.objects.filter(place=place_id, start_date=timezone.now().strftime('%Y-%m-%d'), start_time__lte=timezone.now().strftime('%H:%M:%S'), stop_time__gte=timezone.now().strftime('%H:%M:%S'))
I my database time is saved in format H:M:S and timezone.now().time() has different format so i modified filter with .strftime this didnt help, what i wont is to limit "place_event_now" queryset to particular object/objects that come true with condition start_time < currenttime < stop_time.
Another case is with place_event_next
place_events_next = Event.objects.filter(place=place_id, start_date=timezone.now().strftime('%Y-%m-%d'), stop_date__gte=timezone.now().strftime('%Y-%m-%d'), start_time__gt=timezone.now().strftime('%H:%M:%S')).order_by('start_time')
Event when i filter objects that start_time is greater than timezone.now() they still are in queryset.
Am I doing something wrong ?
I figured it out that timezone.now() return time not in my current timezone, i change it to timezone.localtime() and everything working perfect !!!
May be you need call date to date()
replace
filter(place=place_id, start_date=timezone.now().date, stop_date__gte=timezone.now().date)
# ^^^ ^^^
to
filter(place=place_id, start_date=timezone.now().date(), stop_date__gte=timezone.now().date())
# ^^^ ^^^

Django-tables2 - can't I use [A('argument')] inside the "text" parameter?

I'm trying to make this table with a clickable field which changes the boolean for the entry to its opposite value. It works, but I want an alternative text as "False" or "True" does not look nice, and the users are mainly Norwegian.
def bool_to_norwegian(boolean):
if boolean:
return "Ja"
else:
return "Nei"
class OrderTable(tables.Table):
id = tables.LinkColumn('admin_detail', args=[A('id')])
name = tables.Column()
address = tables.Column()
order = tables.Column()
order_placed_at = tables.DateTimeColumn()
order_delivery_at = tables.DateColumn()
price = tables.Column()
comment = tables.Column()
sent = tables.LinkColumn('status_sent', args=[A('id')])
paid = tables.LinkColumn('status_paid', args=[A('id')], text=[A('paid')])
class Meta:
attrs = {'class': 'order-table'}
If you look under the "paid" entry I am testing this right now, why can't I access the data with the same accessor as I do in the args? If I change the args to args=[A('paid')] and look at the link, it does indeed have the correct data on it. The model names are the same as the ones in this table, and "paid" and "sent" are BooleanFields.
This is kind of what I ultimately want:
text=bool_to_norwegian([A('paid')])
Here is what I send to the table:
orders = Order.objects.order_by("-order_delivery_at")
orders = orders.values()
table = OrderTable(orders)
RequestConfig(request).configure(table)
The text argument expects a callable that accepts a record, and returns a text value. You are passing it a list (which it will just ignore), and your function is expecting a boolean instead of a record. There is also no need for using accessors here.
Something like this should work:
def bool_to_norwegian(record):
if record.paid:
return "Ja"
else:
return "Nei"
Then in your column:
paid = tables.LinkColumn('status_paid', text=bool_to_norwegian)
(Note, it is not clear from your question where the data is coming from - is paid a boolean? You may need to adjust this to fit).
As an aside, the way you are passing args to your columns is weird (it seems the documentation also recommends this, but I don't understand why - it's very confusing). A more standard approach would be:
id = tables.LinkColumn('admin_detail', A('id'))
or using named arguments:
id = tables.LinkColumn('admin_detail', accessor=A('id'))

How to convert Django's TimeField to Postgres' timestamp with time zone

In my Django app, the program gets the time of an event from the user, say user inputs 10:30 for the time of an event. The program uses modelformset_factory to create a whole bunch of forms:
#forms.py
class EventForm(ModelForm):
class Meta:
model = Event
fields = ['entry', 'time', 'work']
localized_fields = ('time', )
widgets = {
'work': Textarea(attrs = {'cols': 40, 'rows': 8}),
}
#models.py
class Event(models.Model):
'''
Each day there are many events, e.g. at 10 am, the framer orders material, etc.
'''
entry = models.ForeignKey(Entry)
time = models.TimeField()
work = models.TextField()
#views.py:
EventFormSet = modelformset_factory( Event, form = EventForm, exclude = ('entry',),extra = 5)
eventset = self.EventFormSet(request.POST)
all_errors = eventset.errors # All errors returns [{}, {}, {}, {}, {}], so the data is free of error.
try:
eventset.is_valid()
except ValidationError:
return render(request, self.template_name, {'form': self.day_log(initial = self.initial_values), 'eventforms': self.event_formset})
events_instances = eventset.save(commit = False)
for instance in events_instances:
if instance.time:
event_date = datetime.date(the_year, the_month, the_day) # Naive date
event_time = instance.time # Naive time
naive_event_time = timezone.is_naive(event_time) # Checking naivaty
event_datetime = datetime.datetime.combine(event_date, event_time) # Naive datetime object
is_aware_event_datetime = timezone.is_aware(event_datetime) # Checking to see if the datetime object is aware or naive
event_aware_datetime = datetime.datetime(the_year, the_month, the_day, instance.time.hour, instance.time.minute, instance.time.second, tzinfo = pytz.utc) # Making an aware time
is_aware_event_aware_datetime = timezone.is_aware(event_aware_datetime) # Making sure the event_aware_datetime is indeed aware
instance.time = event_aware_datetime
awareness_test = timezone.is_aware(instance.time) # Making sure instance.time is aware
eventset.save() # Here is where the exception is thrown.
The Django app fails to save time data to Postgres. The exception type is DataError with the exception value:
invalid input syntax for type timestamp with time zone:
LINE 1: ...y_event" ("entry_id", "time", "work") VALUES (14, '18:43:04....
with ^ pointing at ' of '18:
Edit:
Here is my database:
CREATE TABLE site_activity_event
(
id serial NOT NULL,
entry_id integer NOT NULL,
"time" time without time zone NOT NULL,
work text NOT NULL,
CONSTRAINT site_activity_event_pkey PRIMARY KEY (id),
CONSTRAINT site_activity_event_entry_id_fkey FOREIGN KEY (entry_id)
REFERENCES site_activity_entry (id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION DEFERRABLE INITIALLY DEFERRED
)
I did sqlall my app to ensure that the data type of model field correspond to that of the app and all is well there. This seems to be a postgres issue, but Django is supposed to take care of all those pesky interface issues with Postgres (https://docs.djangoproject.com/en/1.8/topics/i18n/timezones/#migration-guide), so that makes me think I am missing something. Any help is much appreciated.
Well, is "18:43:04" a valid timestamp with a timezone? Do you think it specifies a unique point in time? If you do then you have uncovered a major bug in PostgreSQL's date/time handling. If not, then you should either supply a valid timestamp or use the correct type in your database - I can't say which without knowing more about these events.
Your Event has a TimeField but it looks like the database was created with a DateTimeField.

Categories

Resources