I have a bunch of forms that have similar fields. To simplify my code, I'd like to define the fields outside of the forms and then add the fields to the forms as needed like this:
name = wt.StringField("name")
age = wt.StringField("age")
class Form1(FlaskForm):
name=name
class Form2(FlaskForm):
age=age
class Form3(FlaskForm):
name=name
age=age
This pattern seems to work, but I've never seen anyone do this before so I want to make sure that there are not edge cases where this will break. If so, are there better ways of doing this?
Although the pattern in my question works, I'm nervous about using it since it doesn't appear to be a recommended way of doing things. This is a safer approach that meets my needs:
def name_field(): return wt.StringField("name")
def age_field(): return wt.StringField("age")
class Form1(FlaskForm):
name=name_field()
class Form2(FlaskForm):
age=age_field()
class Form3(FlaskForm):
name=name_field()
age=age_field()
It seems to me FormField is what you're looking for.
class nameForm(Form):
name = wt.StringField("name")
class ageForm(Form):
age = wt.StringField("age")
class Form1(FlaskForm):
name = FormField(nameForm)
class Form2(FlaskForm):
age = FormField(ageForm)
class Form3(FlaskForm):
name = FormField(nameForm)
age = FormField(ageForm)
Here's some relevant documentation -> https://wtforms.readthedocs.io/en/2.3.x/fields/
Search this doc for the Field Enclosures Section
Related
I have one Parent form, and 2 Children forms, than inherit from it -
class ParentForm(FlaskForm):
number_a = StringField('A',
validators=[DataRequired()],
render_kw={"placeholder":"A", 'class_':'input', 'id':'number_a'})
number_b = StringField('B',
validators=[DataRequired()],
render_kw={"placeholder":"B", 'class_':'input', 'id':'number_b'})
class Child1Form(ParentForm):
number_c = StringField('C',
validators=[DataRequired()],
render_kw={"placeholder":"C", 'class_':'input', 'id':'number_c'})
class Child2Form(ParentForm):
number_d = StringField('D',
validators=[DataRequired()],
render_kw={"placeholder":"D", 'class_':'input', 'id':'number_d'})
For Child1Form I need number_a, number_b and number_c.
For Child2Form I need number_b and number_d, but I do not need number_a, so I don't submit it. This results in Validation error when I post the Child2Form, since in the ParentForm field is required.
How should I tackle this? Basically on certain forms I need to Validate the number_a field, on others I need to ignore it. But I don't want to type it multiple times, as I will potentially have a very large amount of forms.
Hopefully I got my point across, let me know if this is not the case.
This just sounds like the design problem in OOP of the "refused bequest". Something a child shouldn't do.
You should just arrange the inheritance hierarchy to cater for the needs of the child classes:
class ParentForm_B(FlaskForm):
number_b = ...
class ParentForm(ParentForm_B):
number_a = ...
class Child1Form(ParentForm):
number_c = ...
class Child2Form(ParentForm_B):
number_d = ...
For a Django model I'm using django-import-export package.
If need to export more then just available model fields, like properties or custom fields, new can be added with import_export.fields.Field class and optionally dehydrate_<field> method.
from import_export import resources, fields, instance_loaders
class ProductResource(resources.ModelResource):
categories = fields.Field()
price = fields.Field(attribute='unit_price')
class Meta:
model = Product
def dehydrate_categories(self, product):
return ';'.join(
'/%s' % '/'.join([c.name for c in cat.parents()] + [cat.name])
for cat in product.category.iterator() )
It does work well, but only for exporting. What about import, the reverse process ? Is there some counterpart to dehydrate_ method ?
So far I've overridden get_or_init_instance method:
class ProductResource(resources.ModelResource):
def get_or_init_instance(self, instance_loader, row):
row['unit_price'] = row['price']; row.pop('price')
return super(ProductResource, self).get_or_init_instance(instance_loader, row)
but doubt this is the right way.
Would appreciate any hint how to handle imports of custom fields.
You can override import_obj instead. See Import workflow for more details.
Another approach is to subclass Field and override export and save methods and do all required data manipulation in a field.
I know this is very old but I came across the same problem and this is how I fixed it (based on the direction the original asker was heading).
First, you can add any custom/modified fields you need by overriding the 'before_import_row' function, like so:
def before_import_row(self, row, **kwargs):
row['extra_info'] = 'Some Info'
return super(RetailLocationResource, self).before_import_row(row, **kwargs)
Then you can pass this into your instance by overriding get_or_init_instance like so:
def get_or_init_instance(self, instance_loader, row):
instance, bool = super(RetailLocationResource, self).get_or_init_instance(instance_loader, row)
instance.extra_info = row['extra_info']
return instance, bool
Hope this helps anyone!
Given the following models:
class Module(models.Model):
pass
class Content(models.Model):
module = models.ForeignKey(Module, related_name='contents')
class Blog(Module):
pass
class Post(Content):
pass
I would like to be able to get all the "post" objects owned by blog doing something like:
b = Blog.objects.get(pk=1)
b.posts.all()
However, I haven't figured out a good way of doing this. I can't use b.contents.all() as I need Post instances and not Content instances. I won't ever have a root content object, every content object is going to be subclassed, but I can't use abstract classes as I want a central table with all my content in it and then there will be content_blog etc tables for all the unique inherited pieces of content.
I also tried doing this
class Content(models.Model):
module = models.ForeignKey(Module, related_name='%(class)')
but that failed miserably as far as I could tell.
The simplest way might add a method to Blog model to return a Post queryset, like this:
class Blog(Module):
def _get_posts(self):
return Post.objects.filter(module=self)
posts = property(_get_posts)
The problem is you have to add method for every sub-model. The related_name seems only works for abstract base class.
This solution comes to my mind:
# ...
class Blog(Module):
#property
def posts(self):
return self.contents
class Post(Content):
pass
This way, doing blog.posts is the same as doing blog.contents:
>>> blog = Blog.objects.get(pk=1)
>>> blog.posts.all()
# [ ... ]
I'm trying to hold a kind of table of contents structure in my database. Simplified example:
models.py
class Section (models.Model):
title = models.CharField(max_length=80)
order = models.IntegerField()
class SectionClickable(Section):
link = models.CharField(max_length=80)
class SectionHeading(Section):
background_color = models.CharField(max_length=6)
views.py
sections = Section.objects.filter(title="Hello!")
for section in sections:
if(section.sectionheading):
logger.debug("It's a heading")
I need to do some processing operations if it's a SectionHeading instance, but (as in the Django manual), accessing section.sectionheading will throw a DoesNotExist error if the object is not of type SectionHeading.
I've been looking into alternatives to this kind of problem, and I'm skimming over Generic Foreign Keys in the contenttypes package. However, this seems like it would cause even more headaches at the Django Admin side of things. Could anyone advise on a better solution than the one above?
Edit: I avoided abstract inheritence because of the order field. I would have to join the two QuerySets together and sort them by order
well you could check the type:
if isinstance(section, SectionHeading)
but duck typing is generally preferred
edit:
actually, that probably won't work. the object will be a Section. but you can look for the attribute:
if hasattr(section, 'sectionheading')
or
try:
do_something_with(section.sectionheading)
except AttributeError:
pass # i guess it wasn't one of those
The solution I came up using involved an extra field pointing to the (rather useful) ContentType class:
class Section(models.Model):
name = models.CharField(max_length=50)
content_type = models.ForeignKey(ContentType,editable=False,null=True)
def __unicode__(self):
try:
return self.as_leaf_class().__unicode__()
except:
return self.name
def save(self, *args, **kwargs):
if(not self.content_type):
self.content_type = ContentType.objects.get_for_model(self.__class__)
super(Section, self).save(*args, **kwargs)
def as_leaf_class(self):
content_type = self.content_type
model = content_type.model_class()
if(model == Section):
return self
return model.objects.get(id=self.id)
If you're going through "base" object, I think this solution is pretty nice and comfortable to work with.
I've been using something similar to what second suggests in his edit:
class SomeBaseModel(models.Model):
reverse_name_cache = models.CharField(_('relation cache'), max_length=10,
null=True, editable=False)
def get_reverse_instance(self):
try:
return getattr(self, self.reverse_name_cache)
except AttributeError:
for name in ['sectionclickable', 'sectionheading']:
try:
i = getattr(self, name)
self.reverse_name_cache = name
return i
except ObjectDoesNotExist:
pass
Now, this isn't exactly pretty, but it returns the subclass instance from a central place so I don't need to wrap other statements with try. Perhaps the hardcoding of subclass reverse manager names could be avoided but this approach was enough for my needs.
OP here.
While second's answer is correct for the question, I wanted to add that I believe multi-table inheritence is an inefficient approach for this scenario. Accessing the attribute of the sub-class model would cause a query to occur - thus requiring a query for every row returned. Ouch. As far as I can tell, select_related doesn't work for multi-table inheritence yet.
I also ruled out ContentTypes because it wouldn't do it elegantly enough and seemed to require a lot of queries also.
I settled on using an abstract class:
class Section (models.Model):
title = models.CharField(max_length=80)
order = models.IntegerField()
class Meta:
abstract=True
ordering=['order']
Queried both tables:
section_clickables = SectionClickable.objects.filter(video=video)
section_headings= SectionHeading.objects.filter(video=video)
and joined the two querysets together
#Join querysets http://stackoverflow.com/questions/431628/how-to-combine-2-or-more-querysets-in-a-django-view
s = sorted(chain(section_headings, section_clickables), key=attrgetter('order'))
Lastly I made a template tag to check the instance:
from my.models import SectionHeading, SectionClickable
#register.filter()
def is_instance(obj, c):
try:
return isinstance(obj, eval(c))
except:
raise ObjectDoesNotExist('Class supplied to is_instance could not be found. Import it in the template tag file.')
so that in my template (HamlPy) I could do this:
- if s|is_instance:"SectionClickable"
%span {{s.title}}
- if s|is_instance:"SectionHeading"
%span{'style':'color: #{{s.color}};'}
{{s.title}}
The result is that I only used two queries, one to get the SectionClickable objects and one for the SectionHeading objects
I want a nice convenient attribute to do the following:
from django.contrib.auth.models import User
user = User.objects.get(id=2)
user.company
<Company: Big Company L.L.C>
I am currently solving this using lambda. In searching for an answer it looks like perhaps the "right" way to solve this would be to use types.MethodType but I can't seem to get my head around it. Yes, I have read Raymond excellent guide but I'm clearly missing something.. Here is my current solution for those who are interested..
# Defined Elsewhere
class User:
name = models.CharField(max_length=32)
class Company(models.Model):
users = models.ManyToManyField(User, related_name="companies", blank=True, null=True)
# Here is the meat of this..
class UserProfile(models.Model):
"""This defines Users"""
user = models.OneToOneField(User)
def get_company(self):
try:
companies = self.user.companies.all()[0]
except (AttributeError, IndexError):
return None
User.company = property(lambda u: UserProfile.objects.get_or_create(user=u)[0].get_company())
Right now this works.. But is there a better way - I'm not crazy about lambdas??
I'm not quite sure I understand correctly what your goal is, but from what I think I understand, it doesn't seem necessary to do any crazy stuff with descriptors here, let alone types.MethodType. A simple property is fine, and if you don't like the lambda, you can use an ordinary function decorated with #property:
class User:
name = models.CharField(max_length=32)
#property
def company(self):
return UserProfile.objects.get_or_create(user=self)[0].get_company())
Edit: If you can't touch the User class, you can create a derived class adding the desired property:
class MyUser(User):
#property
def company(self):
return UserProfile.objects.get_or_create(user=self)[0].get_company())
Building on #SvenMarnach's answer, you can still accomplish the same thing without using lambda. Though you still have to monkey-patch:
def _get_user_company(user):
return UserProfile.objects.get_or_create(user=user)[0].get_company()
User.company = property(_get_user_company)