Two InlineFormAdmin for one model class not working - flask-admin

I have one model class named Job and one model class named Node. One job can have many nodes of the type source or destination.
I have a SourceNodeInlineModelForm and a DestinationNodeInlineModelForm that both are based on model class Node. These works as expected if I use one of them in inline_models but when I use both of the only the last specified in inline_models is displayed. In below only DestinationNodeInlineModelForm is displayed.
class Job(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.Unicode(64))
class Node(db.Model):
id = db.Column(db.Integer, primary_key=True)
type = db.Column(db.String(16))
hostname = db.Column(db.Unicode(128))
port = db.Column(db.Integer)
job_id = db.Column(db.Integer, db.ForeignKey(Job.id))
job = db.relation(Job, backref='jobs')
class CustomInlineFieldListWidget(RenderTemplateWidget):
def __init__(self):
super(CustomInlineFieldListWidget, self).__init__('field_list.html')
class CustomInlineModelFormList(InlineModelFormList):
widget = CustomInlineFieldListWidget()
def display_row_controls(self, field):
return False
class CustomInlineModelConverter(InlineModelConverter):
inline_field_list_type = CustomInlineModelFormList
class SourceNodeInlineModelForm(InlineFormAdmin):
form_label = 'Source'
form_extra_fields = {
'type': HiddenField('type', default='source')
}
def __init__(self):
return super(SourceNodeInlineModelForm, self).__init__(Node)
class DestinationNodeInlineModelForm(InlineFormAdmin):
form_label = 'Destination'
form_extra_fields = {
'type': HiddenField('type', default='destination')
}
def __init__(self):
return super(DestinationNodeInlineModelForm, self).__init__(Node)
class JobAdmin(ModelView):
inline_model_form_converter = CustomInlineModelConverter
inline_models = (SourceNodeInlineModelForm(), DestinationNodeInlineModelForm())
def __init__(self):
super(JobAdmin, self).__init__(Job, db.session, name='Jobs')
Only the last entry in inline_models is being rendered. I expected both to be rendered.

Related

Using class as a phonebook dictionary

class PhoneBook:
def __init__(self):
self.contacts = {}
def __str__(self):
return str(self.contacts)
def add(self, name, mobile=None, office=None, email=None):
self.contacts["Name"] = name
self.contacts["Mobile"] = mobile
self.contacts["Office"] = office
self.contacts["Email"] = email
obj = PhoneBook()
obj.add("Kim", office="1234567", email="kim#company.com")
obj.add("Park", office="2345678", email="park#company.com")
print(obj)
I tried to make PhoneBook class to add up the dictionary lists as I put .add method to the class variable but every time the class variable calls the PhoneBook() class, the dictionary initialization occurs and only the last data remains in the dictionary(I suppose :S)
Is there any way to solve this problem? Thank you.
The issue is, you're using the same dictionary key "Name" to store your contacts. Instead, put real name as a key to dictionary and this key will hold another dictionary. For example:
import pprint
class PhoneBook:
def __init__(self):
self.contacts = {}
def __str__(self):
return pprint.pformat(self.contacts, width=30)
def add(self, name, mobile=None, office=None, email=None):
self.contacts[name] = {
"Mobile": mobile,
"Office": office,
"Email": email,
}
obj = PhoneBook()
obj.add("Kim", office="1234567", email="kim#company.com")
obj.add("Park", office="2345678", email="park#company.com")
print(obj)
Prints:
{'Kim': {'Email': 'kim#company.com',
'Mobile': None,
'Office': '1234567'},
'Park': {'Email': 'park#company.com',
'Mobile': None,
'Office': '2345678'}}

How do I explicitly specify language of email I want to send?

I have a custom user model that have a preferred_language field. I want all the emails (activation and password reset) to be sent translated to the language that user specified in profile.
class CustomUser(AbstractBaseUser, PermissionsMixin):
...
LANGUAGE_CHOICES = (
(1, "English"),
(2, "Русский")
)
preferred_language = models.PositiveSmallIntegerField(choices=LANGUAGE_CHOICES, default=2,
verbose_name=_("Preferred language"))
I thought about setting custom email class but didn't saw in navive djoser's classes any points where I could explicitly set the language of outcome emails despite of ready-to-be-translated style of email templates:
class ActivationEmail(BaseEmailMessage):
template_name = 'email/activation.html'
def get_context_data(self):
context = super(ActivationEmail, self).get_context_data()
user = context.get('user')
context['uid'] = utils.encode_uid(user.pk)
context['token'] = default_token_generator.make_token(user)
context['url'] = settings.ACTIVATION_URL.format(**context)
return context
Reset password view (which's refference is settings.EMAIL.activation used in ActivationEmail class above):
class ResetPassword(ActionViewMixin, generics.GenericAPIView):
...
def send_password_reset_email(self, user):
context = {'user': user}
to = [get_user_email(user)]
settings.EMAIL.password_reset(self.request, context).send(to)
def send_activation_email(self, user):
context = {'user': user}
to = [get_user_email(user)]
settings.EMAIL.activation(self.request, context).send(to)
In your case I would use the override context manager that stores the current language on enter (in order to sent the email) and restores it on exit.
from django.utils import translation
def send_password_reset_email(self, user):
context = {'user': user}
to = [get_user_email(user)]
lang_code = user.lang_code # retrieve user's language code here
with translation.override(lang_code):
settings.EMAIL.password_reset(self.request, context).send(to)
def send_activation_email(self, user):
context = {'user': user}
to = [get_user_email(user)]
lang_code = user.lang_code # retrieve user's language code here
with translation.override(lang_code):
settings.EMAIL.activation(self.request, context).send(to)

Override default Model View

How can I override the Model View so by default all Model Views have exact same settings which I override?
For example:
I have 5 model views linked to some db models which are all custom,but I want all these 5 to have some default settings so I won't have to write code for each view in the ModelView class.
Use inheritance:
class BaseView(ModelView):
# Add common functionality here
pass
class ProductView(BaseView):
# Add specific functionality here
pass
class CategoryView(BaseView):
# Add specific functionality here
pass
A simple one file example below.
Class BaseView turns on can_view_details and formats the description column in upper case.
Notice the difference between ProductView, which inherits from BaseView, and ProductNotInheritedView which inherits directly from ModelView.
Note the code uses the Faker library to generate random data.
from flask import Flask
from flask_admin.contrib.sqla import ModelView
from flask_sqlalchemy import SQLAlchemy
from faker import Faker
from flask_admin import Admin
app = Flask(__name__)
# Create in-memory database
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite://'
app.config['SQLALCHEMY_ECHO'] = True
db = SQLAlchemy(app)
# Flask views
#app.route('/')
def index():
return 'Click me to get to Admin!'
class Supplier(db.Model):
__tablename__ = 'supplier'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.Unicode(100), nullable=False)
description = db.Column(db.UnicodeText(), nullable=True)
products = db.relationship("Product", back_populates="supplier")
def __str__(self):
return unicode(self).encode('utf-8')
def __unicode__(self):
return self.name
class Product(db.Model):
__tablename__ = 'product'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.Unicode(100), nullable=False)
code = db.Column(db.Unicode(32), nullable=False)
description = db.Column(db.UnicodeText(), nullable=True)
supplier_id = db.Column(db.Integer, db.ForeignKey('supplier.id'), index=True, nullable=False)
supplier = db.relationship(Supplier, back_populates='products')
def __str__(self):
return unicode(self).encode('utf-8')
def __unicode__(self):
return self.name
class BaseView(ModelView):
can_view_details = True
column_formatters = {
'description': lambda v, c, m, p: m.description.upper(),
}
class SupplierView(BaseView):
column_list = ('name', 'description', 'products')
class ProductView(BaseView):
pass
class ProductNotInheritedView(ModelView):
pass
admin = Admin(app, template_mode="bootstrap3")
admin.add_view(SupplierView(Supplier, db.session))
admin.add_view(ProductView(Product, db.session))
admin.add_view(
ProductNotInheritedView(Product, db.session, name='Product Not Inherited', endpoint='product-not-inherited'))
#app.before_first_request
def build_sample_db():
db.drop_all()
db.create_all()
fake = Faker()
_suppliers = []
for _ in range(20):
_supplier = Supplier(
name=fake.company(),
description=fake.paragraph(nb_sentences=fake.random.randint(1, 10))
)
_suppliers.append(_supplier)
for _ in range(fake.random.randint(1, 10)):
_supplier.products.append(
Product(
name=' '.join(fake.words(nb=fake.random.randint(1, 5))),
description=fake.paragraph(nb_sentences=fake.random.randint(1, 10)),
code=fake.isbn10(separator="-")
)
)
db.session.add_all(_suppliers)
db.session.commit()
if __name__ == '__main__':
app.run(port=5000, debug=True)

'QuerySet' object has no attribute 'subs'

Can someone pls explain how can I filter users posts if user is subscriber or not?
'QuerySet' object has no attribute 'subs'
I use custom user
class Every(AbstractBaseUser):
user = models.OneToOneField(settings.AUTH_USER_MODEL, unique=True)
name = models.CharField(max_length=30, blank=True)
Here is post model:
class Post(models.Model):
user = models.ForeignKey(User, blank=True, null=True)
text = models.TextField(max_length=1200)
A subscriber model:
class Sub(models.Model):
user = models.OneToOneField(User, related_name='user')
subs = models.ManyToManyField(User, blank=True, related_name='subs')
A view that I'm trying to use:
def tape(request, every_id):
context = {}
context.update(csrf(request))
post_form = PostForm
pform = post_form
sub = Sub.objects.filter(subs=every_id)# here I get users that intersting for my user
tape = Post.objects.filter(user=sub.subs).order_by("-timestamp")
username = request.user
context = {"username": username, "pform": pform, "tape": tape, "sub": sub,}
return render(request, 'tape.html', context)
actually it would be better to use a class view. But here is an answer with an usual view. We need to get subscription's and subscribers's ids before we start filter posts
here is even a bit more :-)
def get_user_id_list(user):
"""Returns a list of subscribers's ids"""
try:
sub = user.user
Sub.DoesNotExist:
return []
return sub.subs.all().values_list('user_id', flat=True)
def get_user_id_list_2(user):
"""Returns a list of subscription's ids"""
return user.subs.values_list('user_id', flat=True)
def tape(request):
pform = PostForm
user_id_list = get_user_id_list_2(request.user)
logger.info('user_id_list = {}'.format(user_id_list))
tape = Post.objects.filter(user_id__in=user_id_list).order_by("-timestamp")
username = request.user
context = {
"username": username,
"pform": pform,
"tape": tape,
"sub": sub,
}
return render(request, 'tape.html', context)

Cannot convert instance of a document class to instance of its subclass - Mongoengine

I am using Flask + mongoengine to create a web application. Here is a part of my models
class Order(Document):
placed_on=DateTimeField(required=True)
order_id = SequenceField()
status = StringField(default="Request Received")
cart = ListField(DictField())
userMobile = StringField(required=True)
userEmail = StringField(required=True)
address = ReferenceField(Address)
sheet_id = IntField(default=0)
remarks = StringField(default="")
meta = {'allow_inheritance': True}
class ConfirmedOrder(Order):
delivery_slot_start = DateTimeField()
delivery_slot_end = DateTimeField()
meta = {'allow_inheritance': True}
I have an instance of class Order as order. I now want to convert it to a ConfirmedOrder.This is the code I am using for the conversion
try:
order = Order.objects.get(id=order_id)
cOrder = ConfirmedOrder(**order.to_mongo())
cOrder.delivery_slot_start = timest
cOrder.delivery_slot_end = timend
cOrder.save();
except Exception as e:
print e
I However, get this error:
The field '_id' does not exist on the document 'Order.ConfirmedOrder'