Flask-Admin: Inserting data in two tables at once - python

This is the first project that I've used flask/flask-admin on. We have an API, created using flask and are now working on an admin interface to it. One of the requirements is upon the creation of a record in TableA, a number of related records need to be created in TableB which includes the ROW_ID of the new TableA entry.
I've created a form for the entry of data in to TableA (which works fine), but don't know how to go about automatically adding data to TableB. Is the new (TableA) ROW_ID returned once the data has been committed to the table? Is there a better way to do this?
Any thoughts?

The docs don't have a great example of it, but you can override all of the CRUD operations for models, including creation. You can handle creating and saving the model yourself, at which you have the primary key, and can make any other queries and create any other models you need.
I cobbled this together out of our code, so hopefully it's complete enough. Let me know if any of it's confusing, or it doesn't answer your question.
http://flask-admin.readthedocs.org/en/latest/quickstart/#model-views
from your_models import Employee, Manatee
from flask.ext.admin import Admin
from flask.ext.admin.contrib.sqla import ModelView
class EmployeeAdminView(ModelView):
# this is called when a model is created
def create_model(self, form):
person = Employee() # create new Employee
form.populate_obj(person) # use WTForms to populate the model
# create a new manatee for this new employee
# everybody needs a manatee for business purposes
# this assumes there's a sqlalchemy relationship() between the two models
manatee = Manatee()
manatee.name = "Janet"
person.manatee = manatee
self.session.add(person)
self.session.commit()
# at this point person.id should be available, so you can use that here
# to make any other queries you need to
return True
admin = Admin(app)
admin.add_view(EmployeeAdminView(Employee, db.session))

Related

Using a single ManyToMany relation table instead of ManyToMany & ForeignKey field on multiple models?

I have a Django application that handles data analysis workflows, with database models that look something like this:
class Workflow(models.Model):
execution_id = models.UUIDField()
class WorkflowItem(models.Model):
workflow = models.ForeignKey(Workflow)
type = models.CharField(choices=["input", "output"])
files = models.ManyToManyField(File)
class File(models.Model):
path = models.CharField()
class FileMetadata(models.Model):
metadata = models.JSONField()
file = models.ForeignKey(File)
version = models.IntegerField()
A given Workflow will have many WorkflowItem's, which correspond to File's which can be used by WorkflowItem's across many Workflow's. Each File can have many associated FileMetadata's, of which the entry with the max version value is typically used for a given operation.
As the application has been growing, its getting tedious to build out all the different combinations of logic needed to find the entries in one table based on a given entry in another table just by using each tables' Foreign Key interface (Workflow <-> WorkflowItem <-> File <-> FileMetadata).
I am considering just building a table that holds all the foreign keys for every relationship in a single place. Something like this:
class WorkflowFile(models.Model):
workflow = models.ForeignKey(Workflow)
workflow_item = models.ForeignKey(WorkflowItem)
file = models.ForeignKey(File)
file_metadata = models.ForeignKey(FileMetadata)
However, I am not sure if this is a good idea or not. Its not clear to me if implementing a table like this is advantageous compared to just following all the foreign key relationships individually per-table. Its also not clear to me how I should set up such a table through Django, and if the new requirement for manually entering values into this table all the time would outweigh the reduced need for unique query logic every time I want to query these relationships. My end-goal is to provide a simpler, more consistent way to get all of the items in the relationship based on any of the other items in the relationship.
This question seems similar in premise, but I am not clear that the problem or proposed solution is relevant to what I am looking for here.
Not sure this will actually answer your question but if you want to go the way with multiple FK's then you may consider using through table in combination with m2m changed signal to add proper FK's to this model after adding M2M records to WorkflowItem.
It'll be something like:
from django.db.models.signals import m2m_changed
class WorkflowItem(models.Model):
workflow = models.ForeignKey(Workflow)
type = models.CharField(choices=["input", "output"])
files = models.ManyToManyField(File, through=IntermediateTable)
class IntermediateTable(models.Model):
file = models.ForeignKey(File, related_name='file')
workflow_item = models.ForeignKey(WorkflowItem, related_name='worflowitem')
workflow = models.ForeignKey(Workflow, null=True)
file_metadata = models.ForeignKey(FileMetadata)
def workflow_item_changed(sender, **kwargs):
sender.workflow = sender.workflow_item.workflow
...
sender.save()
m2m_changed.connect(workflow_item_changed, sender=WorkflowItem.files.through)

From where i can insert field input to odoo database

Hello im new in programming with openerp ODOO , well my issue is where i can find the functions of inserting into odoo database , well i created a new field and i want to insert the data of this field into the db
It sounds like as you said, you are just getting started.
I would advise going through the following tutorial for starters.
You need to get an understanding of how Models and Views work in Odoo first and foremost.
Assuming you have added a new field to your model you will need to add this new field to a view for this model.
You will notice that if you have the appropriate permissions you will have an "Edit" and "Save" button (depending on state) on the top left of your views.
These buttons are mapped to functions which can be found on your model.
When you define your model you will notice it inherits models.Model which adds a lot of functionality that you will need for your model. This includes all CRUD operations. You can overide the default function if needed like so
The CREATE METHOD
#api.model
#api.returns('self', lambda rec: rec.id)
def create(self, vals):
# CUSTOM CODE BEFORE RECORD CREATION
rec = super(FocusType, self).create(vals)
# CUSTOM CODE AFTER RECORD CREATION
return rec
THE WRITE METHOD
#api.multi
def write(self, vals):
# CUSTOM CODE BEFORE RECORD WRITE
result = super(FocusType, self).write(vals)
# CUSTOM CODE BEFORE RECORD WRITE
return result
If you want to store field value in database then add store=True within your field in python file. Then Your value store into database.

updating a field in model according to count "many to many" field

I have a django model called Friend that contains a many to many field called friends through another model called FriendshipInfo. For performance reasons i decided to hold a field that holds the number of friends each person has. So now in the migration scripts i need to update the existing friends in my db. This is how i did it:
def forward(...):
# ... adding the new count field ...
for person in Friend.objects.all():
person.friends_count = len(persion.friends.all())
person.uupdate()
I was wondering if there is any way to do this in a much more efficient way (bulk update somehow?)
Tech info:
I am using Python 2.7
I am using django 1.6
For migrations I'm using south
I was tempted to use the extra queryset method to grab the count of friends and bulk update your Friend objects like:
def forward(...):
# adding the new count field
Friend.objects.extra(select = {
'friends_number': 'SELECT COUNT(*) FROM <your_many_to_many_table_name> WHERE <your_many_to_many_table_name>.<your_FriendshipInfo_related_name> = <your_Friend_table_name>.id'
}).update(friends_count=F('friends_number'))
But, by the look of things, it is not possible. However, you can use the raw method custom SQL queries with an update from count query:
from django.db import connection
def forward(...):
# adding the new count field
cursor = connection.cursor()
cursor.execute('\
UPDATE <your_Friend_table_name>\
SET friends_count = \
(SELECT COUNT(*) FROM <your_many_to_many_table_name> WHERE <your_many_to_many_table_name>.<your_FriendshipInfo_related_name> = <your_Friend_table_name>.id)')
the right way it's in the migration file do the data migration (.py)
there you can put the sql query without a problem, the method is migrations.RUNSQL
here it's a example:
class Migration(migrations.Migration):
dependencies = [
('procesos', '0020_auto_20150703_1656'),
]
operations = [
migrations.RunSQL("UPDATE procesos_busquedainmueble SET tipo_inmueble_id=(filtros::json->>'tipo_inmueble')::int;"),

set first_name and second_name in python shell - django

I changed the register logic where now new users have to give their first and second names also. But old users in db don't have those fields filled up, they are empty.
I am wondering now how to set them manually with python manage.py shell, I am using sqlite3, so there is no UI for the db.
is there any solution for it?
the one which came to my mind is to write a update-page for users where they can update their personal info. but then I would need to tell every one of them to do this.
Firstly, I don't know what you mean by "there is no UI for the db" - sqlite has a shell just like any other database, you can go in and write direct SQL update statements.
Secondly, setting fields in the Django shell is just the same as in a view: you import your models, query the instances you want, update the fields, and save the model.
from myapp.models import MyModel
my_instance = MyModel.objects.get(id=whatever)
my_instance.first_name = 'foo'
my_instance.last_name = 'bar'
my_instance.save()
If you are using south, you can do a data migration which is like a schema migration, but deals with data.
You would create a migration, and then add the appropriate code to the forwards method. This way when this migration is applied, data is added for those users that do not have a first and last name.
The other option you have is to do this manually, from the django shell:
>>> from django.contrib.auth import get_user_model
>>> model = get_user_model()
>>> no_names = model.objects.filter(first_name='', last_name='')
>>> no_names.update(first_name='First Name', last_name='Last Name')

How django validates and saves inlineforms

I would like to implement my own functionality similar to Django inlineformsets. What I'm interested in is how Django deals with validation and saving of a main object together with it's related objects in inline forms.
Let's say I have two models: Blog and Entry. Entry has a foreign key to the Blog that is not null. I want to be able to create both the blog and it's entries in one place. This is how I would do it using Django inline forms:
blogform = BlogForm(request.POST)
if blogform.is_valid():
tmp = blogform.save(commit=False)
entriesform = EntryInlineFormset(request.POST, instance=tmp)
if entriesform.is_valid():
entriesform.save()
blog.save()
What's going under the hood here? How is Django able to validate entries without blog being saved to the database? I wanted to find this in Django code, but I wasn't able to find the place where they actually do this.
My gues is they create a transaction. They save the blogform and if the entriesform is invalid they rollback. However what if the entriesform is valid, what next? Does the blog instance stay saved? What if save never gets called then.
Or do they span the transaction over two methods (is_valid and save)? I don't think it's best practice to start the transaction in one method and end it in another.
You can validate them both before calling save on either. You can pass a blank instance into both the parent form and the formset.
blog = Blog()
blogform = BlogForm(request.POST, instance=blog)
entriesform = EntryInlineFormset(request.POST, instance=blog)
blog_valid = BlogForm.is_valid()
entries_valid = entriesform.is_valid()
if blog_valid and entries_valid:
... save ...
I validate the forms separately and save the results to variables to avoid short-circuiting.

Categories