Enter a valid date/time - Django Datetime Picker - django

I'm creating a CRUD application in Django, and one of the fields in the data requires the user to enter a datetime input. This was working smoothly until this evening when I started to work on it again, however I'm getting the below error when I try to add any data the the model.
start_datetimeEnter a valid date/time.
[01/Dec/2022 00:34:39] "POST /activities/new/ HTTP/1.1" 200 2253
I've tried quite a few ways to resolve this but nothing seems to be working; below if the code I have to create the activity
class ActivityForm(forms.ModelForm):
class Meta:
model = Activity
fields = ('name', 'start_datetime', 'end_time',
'location', 'town', 'description')
labels = {
'name': 'Activity Type',
'start_datetime': 'Date & Time of Activity',
'end_time': 'End Time',
'location': 'County',
'town': 'Town (optional)',
'description': 'Description',
}
widgets = {
'start_datetime': DateTimePickerInput(),
'end_time': TimePickerInput(),
}
class DateTimePickerInput(forms.DateTimeInput):
input_type = 'datetime-local'
This is the model field for the start_datetime:
start_datetime = models.DateTimeField()
Does anyone have any ideas on how to resolve this?
Thanks!

Works smoothly in my test:
forms.py
class ActivityForm(forms.ModelForm):
class Meta:
model = models.Activity
fields = ('name', 'start_datetime', 'end_time',
'location', 'town', 'description')
labels = {
'name': 'Activity Type',
'start_datetime': 'Date & Time of Activity',
'end_time': 'End Time',
'location': 'County',
'town': 'Town (optional)',
'description': 'Description',
}
widgets = {
'start_datetime': DateTimeInput(attrs={'type': 'datetime-local'}),
'end_time': TimeInput(attrs={'type': 'time'}),
}
Django expects the following datetime-input-formats:
[
'%Y-%m-%d %H:%M:%S', # '2006-10-25 14:30:59'
'%Y-%m-%d %H:%M:%S.%f', # '2006-10-25 14:30:59.000200'
'%Y-%m-%d %H:%M', # '2006-10-25 14:30'
'%m/%d/%Y %H:%M:%S', # '10/25/2006 14:30:59'
'%m/%d/%Y %H:%M:%S.%f', # '10/25/2006 14:30:59.000200'
'%m/%d/%Y %H:%M', # '10/25/2006 14:30'
'%m/%d/%y %H:%M:%S', # '10/25/06 14:30:59'
'%m/%d/%y %H:%M:%S.%f', # '10/25/06 14:30:59.000200'
'%m/%d/%y %H:%M', # '10/25/06 14:30'
]

Related

client.post is not passing the FK

Hope someone can help me out here, I am trying to test a post method on an API, but the post method is not working as expected.
When I pass the payload to the post method, the points and de code fields are loaded but the shopper and card fields, which are both Foreing Keys, are not loaded and a null value is passed, as they are required fields I ended up getting an error.
I did check, and the values for self.shopper.pk and self.card.pk are correct.
MYCARDS_URL = reverse('mycards:mycards-list')
def test_create_mycards(self):
"""Test creating a mycards"""
payload = {
'shopper': self.shopper.pk,
'card': self.card.pk,
'points': 0,
'code': "code",
}
res = APIClient().post(MYCARDS_URL, payload)
I did check to see if was something related to my serializer, but it is all good as you can see:
class MycardsSerializer(serializers.ModelSerializer):
"""Serializer for cards."""
class Meta:
model = MyCards
fields = ['id', 'shopper', 'card', 'updated', 'created']
read_only_fields = ['id', 'created']
class MycardsDetailSerializer(MycardsSerializer):
"""Serializer for card detail view."""
class Meta(MycardsSerializer.Meta):
fields = MycardsSerializer.Meta.fields + [
'points', 'code']
Here is also my viewset which seems to be ok:
class MycardsViewSet(viewsets.ModelViewSet):
"""View for manage card APIs."""
serializer_class = serializers.MycardsDetailSerializer
queryset = MyCards.objects.all()
authentication_classes = [TokenAuthentication]
permission_classes = [IsAuthenticated]
def get_queryset(self):
"""Retrieve cards for authenticated user."""
shoppers = list(Shopper.objects.all().filter(
user=self.request.user).values_list('id'))
return self.queryset.filter(shopper=shoppers[0]).order_by('-id')
def get_serializer_class(self):
"""Return the serrializer class for request."""
if self.action == 'list':
return serializers.MycardsSerializer
return self.serializer_class
def perform_create(self, serializer):
"""Create a new recipe."""
serializer.save()
I have printed the serializer.dict from inside the perform_create method and got the following:
{'_args': (), '_kwargs': {'data': <QueryDict: {'shopper': ['5'], 'card': ['15'], 'points': ['0'], 'code': ['code']}>, 'context': {'request': <rest_framework.request.Request: POST '/api/mycards/'>, 'format': None, 'view': <mycards.views.MycardsViewSet object at 0x7f7ebd4ce400>}}, 'instance': None, 'initial_data': <QueryDict: {'shopper': ['5'], 'card': ['15'], 'points': ['0'], 'code': ['code']}>, 'partial': False, '_context': {'request': <rest_framework.request.Request: POST '/api/mycards/'>, 'format': None, 'view': <mycards.views.MycardsViewSet object at 0x7f7ebd4ce400>}, '_creation_counter': 198, 'read_only': False, 'write_only': False, 'required': True, 'default': <class 'rest_framework.fields.empty'>, 'source': None, 'initial': None, 'label': None, 'help_text': None, 'style': {}, 'allow_null': False, 'field_name': None, 'parent': None, 'error_messages': {'required': 'This field is required.', 'null': 'This field may not be null.', 'invalid': 'Invalid data. Expected a dictionary, but got {datatype}.'}, 'url_field_name': 'url', 'fields': {'id': IntegerField(label='ID', read_only=True), 'shopper': PrimaryKeyRelatedField(read_only=True), 'card': PrimaryKeyRelatedField(read_only=True), 'updated': DateTimeField(read_only=True), 'created': DateTimeField(read_only=True), 'points': IntegerField(max_value=2147483647, min_value=-2147483648, required=False), 'code': CharField(allow_blank=True, allow_null=True, max_length=6, required=False)}, '_validators': [], '_validated_data': OrderedDict([('points', 0), ('code', 'code')]), '_errors': {}}
here I could notice 2 things, first that the values are passed to the serializer as noted on the line below:
'shopper': ['5'], 'card': ['15'], 'points': ['0'], 'code': ['code']
but at the end of the serializer.dict I could find the following message:
'_validated_data': OrderedDict([('points', 0), ('code', 'code')]), '_errors':
points and code are going through, but the shopper and the card are not, I just have no idea why is it happening :/

Flask-admin not recognising current_user in model View

I created my ModelView in flask-admin and want to give role choices to user such that only admin can create user with role manager,admin or user. And user shouldn't have choice to give admin privilidges or as such. I am trying this code but it's giving me:
AttributeError: 'NoneType' object has no attribute 'is_authenticated'
class UserView(ModelView):
column_exclude_list = ['logs', 'password_hash',]
form_excluded_columns = ['logs']
can_edit = True
if login.current_user or current_user.is_authenticated:
if login.current_user.role == 'a':
form_choices = {
'role': [ ('a', 'Admin'), ('m', 'Manager'), ('u', 'User') ]
}
if login.current_user.role == 'm':
form_choices = {
'role': [
('m', 'Manager'),
('u', 'User')
]
}
Any help would be highly appreciated.
Evaluating current_user always returns a NoneType unless it is within a Flask application context. Do something like the following:
def get_user_roles():
_roles = []
if current_user and current_user.is_authenticated:
if current_user.role == 'a':
_roles = [('a', 'Admin'), ('m', 'Manager'), ('u', 'User')]
elif login.current_user.role == 'm':
_roles = [('m', 'Manager'), ('u', 'User')]
return _roles
class UserView(ModelView):
form_choices = {
'role' : get_user_roles
}
Single file example. If you run this without logging in you will see only the "User" role in the role choices:
requirements.txt
Babel==2.11.0
blinker==1.5
click==8.1.3
colorama==0.4.6
dnspython==2.2.1
email-validator==1.3.0
Flask==2.2.2
Flask-Admin==1.6.0
Flask-BabelEx==0.9.4
Flask-Login==0.6.2
Flask-Mail==0.9.1
Flask-Principal==0.4.0
Flask-SQLAlchemy==3.0.2
Flask-WTF==1.0.1
greenlet==2.0.1
idna==3.4
itsdangerous==2.1.2
Jinja2==3.1.2
MarkupSafe==2.1.1
passlib==1.7.4
pytz==2022.6
speaklater==1.3
SQLAlchemy==1.4.44
Werkzeug==2.2.2
WTForms==3.0.1
app.py
import os
from datetime import datetime
from werkzeug.security import generate_password_hash, check_password_hash
import click
from flask import Flask, current_app
from flask_admin import Admin
from flask_admin.contrib.sqla import ModelView
from flask_login import current_user, UserMixin, LoginManager
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
login_manager = LoginManager()
class User(db.Model, UserMixin):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
first_name = db.Column(db.Unicode(length=255), nullable=False)
last_name = db.Column(db.Unicode(length=255), nullable=False, index=True)
# Identification Data: email & password
email = db.Column(db.Unicode(length=254), nullable=False, unique=True)
password = db.Column(db.Unicode(length=255), nullable=False)
active = db.Column(db.Boolean(), default=False)
role = db.Column(db.Unicode(length=255), nullable=False)
#login_manager.user_loader
def load_user(user_id):
return User.get(user_id)
basedir = os.path.abspath(os.path.dirname(__file__))
app = Flask(__name__)
app.config['SECRET_KEY'] = '123456790'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + os.path.join(basedir, 'database.db')
db.init_app(app)
login_manager.init_app(app)
#app.cli.command('create-database', short_help='Create sample database')
def create_database():
"""
Create database
"""
db.drop_all()
db.create_all()
users = [
{
'email': 'paul#example.net',
'first_name': 'Paul',
'last_name': 'Cunningham',
'password': generate_password_hash('pa$$word'),
'active': True,
'role': 'a',
},
{
'email': 'jane#example.net',
'first_name': 'Jane',
'last_name': 'Smith',
'password': generate_password_hash('pa$$word'),
'active': True,
'role': 'm'
},
]
for user in users:
_user_db = User(**user)
db.session.add(_user_db)
db.session.commit()
#app.route('/')
def index(): # put application's code here
return 'Click me to get to Admin!'
admin = Admin(app, template_mode="bootstrap3")
def get_user_roles():
# default role is a user
_roles = [('u', 'User')]
if current_user and current_user.is_authenticated:
if current_user.has_role('a'):
print('Current user is an admin')
_roles = [('a', 'Admin'), ('m', 'Manager'), ('u', 'User')]
elif current_user.has_role('m'):
print('Current user is a manager')
_roles = [('m', 'Manager'), ('u', 'User')]
print(f"Roles assigned to role choices: {_roles}")
return _roles
class UserView(ModelView):
column_list = ('first_name', 'last_name', 'email', 'role')
form_columns = column_list
form_choices = {
'role': get_user_roles
}
admin.add_view(UserView(User, db.session))
if __name__ == '__main__':
app.run()
Run the following command to initialize an SQLite DB.
flask create-database

Django: dynamic choice field for formsets

So I have a form
class DownloadForm(forms.Form):
title = forms.CharField()
device_family = forms.ChoiceField(label="Device Family",
widget=forms.Select(attrs={'class': 'form-control',
'data-toggle': 'select'}),
choices=LOG_ENTRY_TYPES, required=True
)
and in view.py I do
LOG_ENTRY_TYPES = (
('', 'All'),
('auth', 'Auth'),
('error', 'Error'),
('info', 'Info'),
('proxy', 'Proxy'),
)
DownloadFormSet = formset_factory(DownloadForm)
formsets = DownloadFormSet(initial=[
{'title': 'Django is now open source', 'device_family': LOG_ENTRY_TYPES},
{'title': 'Django source 2', 'device_family': LOG_ENTRY_TYPES},
{'title': 'Django source 3', 'device_family': LOG_ENTRY_TYPES}
])
This creates the device_family field but the LOG_ENTRY_TYPES choices are not generated. So how can I pass the LOG_ENTRY_TYPES choices to the device_family choices field so that the drop down shows the choices.

Django - ORM - datetime field different formats

i am currently working on a Django app where every single DateTimeField should have the exact same format... to start with, this is my abstract model:
from django.db import models
class AbstractModel(models.Model):
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
class Meta:
abstract = True
Both created and updated field have the same format, like this:
2019-01-01 12:12:12.123456+00 # right
BUT: When i add some other DateTimeField to any model, like:
some_other_field = models.DateTimeField()
and save it via django-admin, it gets this format in database:
2019-01-01 12:12:12+00 # wrong
WHY ?! Right now i have two different DateTimeField formats in my database, which is conceptually very bad..
Can anybody help me out? I simply want one format (the upper one) in every single datetime field..
Settings:
LANGUAGE_CODE = 'en-US'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = True
USE_TZ = True
I think you shoud use default value for custome datetime field:
some_other_field = models.DateTimeField()
and select default format value like created or updated field :
[
'%Y-%m-%d %H:%M:%S', # '2006-10-25 14:30:59'
'%Y-%m-%d %H:%M:%S.%f', # '2006-10-25 14:30:59.000200'
'%Y-%m-%d %H:%M', # '2006-10-25 14:30'
'%Y-%m-%d', # '2006-10-25'
'%m/%d/%Y %H:%M:%S', # '10/25/2006 14:30:59'
'%m/%d/%Y %H:%M:%S.%f', # '10/25/2006 14:30:59.000200'
'%m/%d/%Y %H:%M', # '10/25/2006 14:30'
'%m/%d/%Y', # '10/25/2006'
'%m/%d/%y %H:%M:%S', # '10/25/06 14:30:59'
'%m/%d/%y %H:%M:%S.%f', # '10/25/06 14:30:59.000200'
'%m/%d/%y %H:%M', # '10/25/06 14:30'
'%m/%d/%y', # '10/25/06'
]
A list of formats that will be accepted when inputting data on a datetime field.
you can read more django datetime format document.

Django migrations with multiple databases

I have a hard time with creating data migrations. I use two databases for my apps. I configured databases in settings.py and also created a router like in Django docs.
# settings.py
DB_HOST = 'localhost'
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'helios',
'HOST': DB_HOST,
'OPTIONS': {
'read_default_file': join(dirname(__file__), 'default.cnf'),
},
},
'other': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'gala_pol',
'HOST': DB_HOST,
'OPTIONS': {
'read_default_file': join(dirname(__file__), 'other.cnf'),
},
},
DATABASE_APPS_MAPPING = {
'contenttypes': 'default',
'auth': 'default',
'admin': 'default',
'sessions': 'default',
'messages': 'default',
'staticfiles': 'default',
'woodsmen': 'default',
'helios': 'default',
'hush': 'default',
'hunt': 'other',
'meat': 'other',
'beast': 'other',
}
# routers.py
class DatabaseAppsRouter(object):
def db_for_read(self, model, **hints):
if model._meta.app_label in settings.DATABASE_APPS_MAPPING:
return settings.DATABASE_APPS_MAPPING[model._meta.app_label]
return None
def db_for_write(self, model, **hints):
if model._meta.app_label in settings.
return settings.DATABASE_APPS_MAPPING[model._meta.app_label]
return None
def allow_relation(self, obj1, obj2, **hints):
db1 = settings.DATABASE_APPS_MAPPING.get(obj1._meta.app_label)
db2 = settings.DATABASE_APPS_MAPPING.get(obj2._meta.app_label)
if db1 and db2:
return db1 == db2
return None
def allow_migrate(self, db, app_label, model_name=None, **hints):
if db in settings.DATABASE_APPS_MAPPING.values():
return settings.DATABASE_APPS_MAPPING.get(app_label) == db
elif app_label in settings.DATABASE_APPS_MAPPING:
return False
Here is the model and migrations of one of those apps:
# hunt.models.py
class Dish(models.Model):
"""
Investigation case
"""
display_name = models.CharField(max_length=64, unique=True)
department = models.ForeignKey(Kitchen, null=True)
case_type = models.PositiveSmallIntegerField(choices=CASE_TYPE_CHOICES, default=DEF_CASE_TYPE)
created_at = models.DateTimeField(blank=True, null=True)
comment = models.CharField(max_length=256, blank=True, null=True)
class Meta:
verbose_name = 'case'
app_label = 'hunt'
def __unicode__(self):
return (u'%s (%s)' % (self.display_name, self.created_at)).strip()
# hunt.migrations.0001_initial.py
class Migration(migrations.Migration):
app_label = 'hunt'
dependencies = [
]
operations = [
migrations.CreateModel(
name='Dish',
fields=[
('id', models.AutoField(verbose_name='ID', auto_created=True, primary_key=True, serialize=False)),
('display_name', models.CharField(max_length=64, unique=True)),
('case_type', models.PositiveSmallIntegerField(default=0, choices=[(0, 'Unknown'), (1, 'General'), (2, 'Terror'), (3, 'Narco'), (4, 'Fraud'), (5, 'Slavery'), (6, 'Traffic'), (7, 'RICO'), (8, 'War'), (9, 'Cyber'), (20, 'Other')])),
('created_at', models.DateTimeField(null=True, blank=True)),
('comment', models.CharField(max_length=256, null=True, blank=True)),
],
options={
'verbose_name': 'case',
},
),
]
# hunt.migrations.0002_add_hunts.py
def create_initial_hunts(apps, schema_editor):
if settings.DEBUG:
print('\nContent added')
class Migration(migrations.Migration):
dependencies = [
('hunt', '0001_initial'),
]
operations = [
migrations.RunPython(create_initial_hunts, hints={'schema_editor': 'other'}),
]
The problem is:
When i run "migrate" command, only applications that connected to default database are migrated. The migrations in rest of the apps are never run. If I launch migrate for such an app with --database option - it works fine.
How can I specify the database per migration? Isn't the router supposed to manage exactly this? Or I missed something else?
You have to run migrate once for each database, specifying the target with --database. Each time it will consult your router to see which migrations to actually perform on that database.
I'm guessing it was designed this way to favor explicitness over implicitness. For example, your workflow might require you to migrate the different databases at different times.
Note, though, that you won't be able to tell from the output which migrations were actually performed, since:
If allow_migrate() returns False, any migration operations for the model_name will be silently skipped when running migrate on the db.
Using these nice helpers you can run Python/SQL migrations on specific Database
[Helpers]
from django.db.migrations import RunPython, RunSQL
def run_python_specific_db_migration(migration_func, use_db):
"""calls RunPython command only for specific database """
return RunPython(migration_func, hints={'use_db': use_db})
def run_sql_specific_db_migration(sql_commands, use_db):
"""Runs one or list of sql commands only on specific database """
return RunSQL(sql_commands, hints={'use_db': use_db})
# ** Your specific db_helpers for your DB_KEY **
def run_sql_your_db_migration(sql_commands):
return run_sql_specific_db_migration(sql_commands, use_db=DB_KEY)
def run_python_your_db_migration(migration_func):
return run_python_specific_db_migration(migration_func, use_db=DB_KEY)
[Usage]
def data_migration(apps, schema_editor):
...your data migration logic..better to wrap with #atomic...
class Migration(migrations.Migration):
operations = [ run_python_your_db_migration(data_migration) ]