MongoEngine validate choices within ListField - python

Is it possible to use the choices option of a field object (in my case StringField) which is being used as an argument to ListField?
I’m trying to define a property on a collection like this:
my_list_property = ListField(StringField(choices=CHOICES), required=True)
and I am wanting MongoEngine to validate that the elements of my_list_property are in CHOICES on save.
EDIT - from comments
Having looked at the MongoEngine code, ListField inherits from ComplexBaseField. The validate method on ComplexBaseField calls validate on self.field (in my case, this is StringField).
StringField inherits from BaseField. BaseField.validate just passes.
When a BaseField e.g. StringField is the parent field, BaseField._validate is called as opposed to BaseField.validate, and ._validate does validation on choices. I wonder if ComplexBaseField.validate should actually call self.field._validate instead?

Related

Add a virtual field to a django query

I want to add an extra field to a query set in Django.
The field does not exist in the model but I want to add it to the query set.
Basically I want to add an extra field called "upcoming" which should return "True"
I already tried adding a #property method to my model class. This does not work because apparently django queries access the DB directly.
models.py
class upcomingActivity(models.Model):
title = models.CharField (max_length=150)
address = models.CharField (max_length=150)
Views.py
def get(self, request):
query = upcomingActivity.objects.all()
feature_collection = serialize('geojson', query ,
geometry_field='location',
fields= ( 'upcoming','title','address','pk' )
)
This answer is for the case that you do not want to add a virtual property to the model (the model remains as is).
To add an additional field to the queryset result objects:
from django.db.models import BooleanField, Value
upcomingActivity.objects.annotate(upcoming=Value(True, output_field=BooleanField())).all()
Each object in the resulting queryset will have the attribute upcoming with the boolean value True.
(Performance should be nice because this is easy work for the DB, and Django/Python does not need to do much additional work.)
EDIT after comment by Juan Carlos:
The Django serializer is for serializing model objects and thus will not serialize any non-model fields by default (because basically, the serializer in this case is for loading/dumping DB data).
See https://docs.djangoproject.com/en/2.2/topics/serialization/
Django’s serialization framework provides a mechanism for “translating” Django models into other formats.
See also: Django - How can you include annotated results in a serialized QuerySet?
From my own experience:
In most cases, we are using json.dumps for serialization in views and this works like a charm. You can prepare the data very flexibly for whatever needs arize, either by annotations or by processing the data (list comprehension etc.) before dumping it via json.
Another possibility in your situation could be to customize the serializer or the input to the serializer after fetching the data from the DB.
You can use a class function to return the upcoming value like this:
def upcoming(self):
is_upcoming = # some logic query or just basically set it to true.
return is_upcoming
then call it normally in your serializer the way you did it.
fields= ( 'upcoming','title','address','pk' )

How to add input fields to a form dynamically with custom validator?

I have a form with a few integer fields dynamically added in a view, those fields are for the user to rank from 1-N. I've had trouble figuring out how to write a validator that can ensure reach field.data has a unique value and are from from 1 to N.
I've figured out how to dynamically add fields to a form per wtforms' docs, but I'd like to validate them all against each other like this question and I haven't figured out how to properly reference the dynamic fields in the overridden validate function.
How can I reference the dynamic fields in my form instance in my validator? In the question linked above they do it in the line:
for field in [self.select1, self.select2, self.select3]:
But since I'm adding those fields dynamically with setattr I don't know those field names. I tried adding a list variable to the Form and appending to that list when I add the dynamic fields but they show up as:
<UnboundField(IntegerField, ('first',), {'validators': [<wtforms.validators.DataRequired object at 0x7ff75a6d7390>]})>
Instead of just IntegerFields if I reference a field like select1 in the example above:
<wtforms.fields.core.IntegerField object at 0x7fac1bd54910>
How can I reference and validate together these integer fields that I add to my form dynamically?
Turns out digging a little closer in the WTForms documentation, I should have been using a FieldList. And even better than that I can use a FieldList to enclose a list of FieldForms, this provides some more flexibility for adding fields dynamically.

Extending protorpc StringField

I would like to write custom validation for some fields in ProtoRPC messages.
The documentation says, that protorpc.messages.Field class cannot be extended by developers.
Does it mean I should not extend StringField?
E.g. StringField does not ensure that string is non-empty.
I've checked, and my custom string class with my validate_element method works as expected.
Is there any reason, I should not do that?
You can subclass protorpc.messages.MessageField to create a custom Field. See the DataTimeField source code for an example of this.

How do I make tags required with django-tagging?

I am using django-tagging to manage tags on my entities. How do I ensure that the user has entered at least one tag when filling out a form, other than using javascript validation on the front end?
Are you using the TagField()? If so, it extends the default Django CharField which accepts a required=True argument.
The above applies to a FormField, not ModelField. You can do this instead to make sure the Model field is always required in any subsequent form:
class MyModel(models.Model):
tags = TagField(blank=False)

Django ManyToMany field transformation on a ModelForm

I have this manytomany field in my model that I have overridden with a CharField that receives a csv list of the second models name attribute.
class PostForm(ModelForm):
tests = CharField(label="tests")
class Meta:
model = Post
fields = ('title','body')
def clean_tests(self):
# Here I clean, create or retrieve and return a list of Test objects.
Now, saving and validating is alright with this code, everything works, my problem comes when I create the PostForm with an existing instance, like PostForm(instance=current_post).
The CharField should contain a csv list but it contains nothing, obviously this happens because there is no conversion happening from Test object list to test name list, the problem is I do not know where to put that code, I see no method I could override to get this done, i've looked into initial data and default properties of fields.
I'm not sure if there's a method you could override to do this -- from a look at the BaseModelForm constructor though, it looks perfectly okay to specify both the instance and initial keyword arguments together -- the instance is converted into a dict (subject to the fields and exclude options in Meta), and that dict's update method is called with initial. Something like this should work:
# build your csv list somehow (just speculation here)
tests = ','.join(test.name for test in current_post.tests.all())
form = PostForm(instance=current_post, initial={'tests': tests})

Categories