SQLAlchemy - Filtering with multiple conditions - python

I append number of queries into a list and then filter the table using sqlachemies query function and or_. Table consists of warehouses, and I want to query them using names, available storage, prices and services. The logic should be correct but I get error
subquery must return only one column
#search.route('/search/filter', methods = ['POST'])
def filter():
name = request.form.get('name')
n_storage = request.form.get('n_storage')
#MIN PRICE MAX PRICE
min_p = request.form.get('min_p')
max_p = request.form.get('max_p')
#SERVICES
labelling = True if request.form.get('labelling') else False
manual_geo_data_entry = True if request.form.get('manual_geo_data_entry') else False
item_packaging = True if request.form.get('item_packaging') else False
palette_packaging = True if request.form.get('palette_packaging') else False
filters = []
if name:
filters.append(Warehouse.query.filter(Warehouse.name.match(name)))
if n_storage:
filters.append(Warehouse.query.filter(Warehouse.volume_available > n_storage))
#FILTERING BASED ON SERVICES
if labelling:
filters.append(Warehouse.query.filter(Warehouse.labelling.is_(True)))
if manual_geo_data_entry:
filters.append(Warehouse.query.filter(Warehouse.manual_geo_data_entry.is_(True)))
if item_packaging:
filters.append(Warehouse.query.filter(Warehouse.item_packaging.is_(True)))
if palette_packaging:
filters.append(Warehouse.query.filter(Warehouse.palette_packaging.is_(True)))
results = Warehouse.query.filter(or_(*filters)).all()
return render_template('search/search.html', title = 'Search', data = results)
sqlalchemy.exc.ProgrammingError: (psycopg2.errors.SyntaxError) subquery must return only one column
LINE 3: WHERE (SELECT "PilotApp_warehouse_test".id, "PilotApp_wareho...
^
[SQL: SELECT "PilotApp_warehouse_test".id AS "PilotApp_warehouse_test_id", "PilotApp_warehouse_test".name AS "PilotApp_warehouse_test_name", "PilotApp_warehouse_test".volume_available AS "PilotApp_warehouse_test_volume_available", "PilotApp_warehouse_test".volume_total AS "PilotApp_warehouse_test_volume_total", "PilotApp_warehouse_test".labelling AS "PilotApp_warehouse_test_labelling", "PilotApp_warehouse_test".manual_geo_data_entry AS "PilotApp_warehouse_test_manual_geo_data_entry", "PilotApp_warehouse_test".item_packaging AS "PilotApp_warehouse_test_item_packaging", "PilotApp_warehouse_test".palette_packaging AS "PilotApp_warehouse_test_palette_packaging", "PilotApp_warehouse_test".address AS "PilotApp_warehouse_test_address", "PilotApp_warehouse_test".email AS "PilotApp_warehouse_test_email", "PilotApp_warehouse_test".phone AS "PilotApp_warehouse_test_phone", "PilotApp_warehouse_test".owner AS "PilotApp_warehouse_test_owner"
FROM "PilotApp_warehouse_test"
WHERE (SELECT "PilotApp_warehouse_test".id, "PilotApp_warehouse_test".name, "PilotApp_warehouse_test".volume_available, "PilotApp_warehouse_test".volume_total, "PilotApp_warehouse_test".labelling, "PilotApp_warehouse_test".manual_geo_data_entry, "PilotApp_warehouse_test".item_packaging, "PilotApp_warehouse_test".palette_packaging, "PilotApp_warehouse_test".address, "PilotApp_warehouse_test".email, "PilotApp_warehouse_test".phone, "PilotApp_warehouse_test".owner
FROM "PilotApp_warehouse_test"
WHERE "PilotApp_warehouse_test".manual_geo_data_entry IS true) OR (SELECT "PilotApp_warehouse_test".id, "PilotApp_warehouse_test".name, "PilotApp_warehouse_test".volume_available, "PilotApp_warehouse_test".volume_total, "PilotApp_warehouse_test".labelling, "PilotApp_warehouse_test".manual_geo_data_entry, "PilotApp_warehouse_test".item_packaging, "PilotApp_warehouse_test".palette_packaging, "PilotApp_warehouse_test".address, "PilotApp_warehouse_test".email, "PilotApp_warehouse_test".phone, "PilotApp_warehouse_test".owner
FROM "PilotApp_warehouse_test"
WHERE "PilotApp_warehouse_test".item_packaging IS true)]

You should not pass to filter queries, but only conditions to avoid subqueries. I think it should work for you:
#search.route('/search/filter', methods = ['POST'])
def filter():
name = request.form.get('name')
n_storage = request.form.get('n_storage')
#MIN PRICE MAX PRICE
min_p = request.form.get('min_p')
max_p = request.form.get('max_p')
#SERVICES
labelling = True if request.form.get('labelling') else False
manual_geo_data_entry = True if request.form.get('manual_geo_data_entry') else False
item_packaging = True if request.form.get('item_packaging') else False
palette_packaging = True if request.form.get('palette_packaging') else False
filters = []
if name:
filters.append(Warehouse.name.match(name))
if n_storage:
filters.append(Warehouse.volume_available > n_storage)
#FILTERING BASED ON SERVICES
if labelling:
filters.append(Warehouse.labelling.is_(True))
if manual_geo_data_entry:
filters.append(Warehouse.manual_geo_data_entry.is_(True))
if item_packaging:
filters.append(Warehouse.item_packaging.is_(True))
if palette_packaging:
filters.append(Warehouse.palette_packaging.is_(True))
results = Warehouse.query.filter(or_(*filters)).all()
return render_template('search/search.html', title = 'Search', data = results)

Related

Exact match with filter() Flask

I'am new to python and iam coding a small webapp to search in a database. Its fonctionnal but doesnt function well.
Example : If i search for a 'lieu', a 'Annee' and a 'Signataire' it doesnt give me the exact matches, instead it gives me every 'Signataire' even if its not the 'Annee' or the 'lieu' that i was looking for.
Update : I changed to elif, it helps finding the right "signataire" but still gives me others "signataire" that comes with 'lieu' and 'annee' iam a bit lost.
Here is the code :
'''
def search_results(search):
results = []
lieu = search.data['Lieu']
annee = search.data['Annee']
signataire = search.data['Signataire']
cote = search.data['Cote']
if search.data['Lieu'] or search.data['Annee'] or
search.data['Cote']:
qry = db_session.query(Cote).filter(and_(Cote.lieu.contains(lieu),Cote.annee.contains(annee),Cote.cote.contains(cote))
)
results = qry.all()
elif search.data['Signataire']:
qry = db_session.query(Cote).filter(or_(Cote.signataire_nom.contains(signataire),Cote.signataire_titre.contains(signataire)))
results = qry.all()
if not results:
flash('No results !')
return redirect('/')
else:
table = Results(results)
table.border = True
return render_template('results.html', table=table)
'''
This is because you are using "if" the second time and not "elif". So if there exists the Signataire, then your results are always all the signataire.
To resolve this you should use something like this:
def search_results(search):
results = []
lieu = search.data['Lieu']
annee = search.data['Annee']
signataire = search.data['Signataire']
cote = search.data['Cote']
if search.data['Lieu'] or search.data['Annee'] or search.data['Cote']:
qry = db_session.query(Cote).filter(and_(
Cote.lieu.contains(lieu),Cote.annee.contains(annee),Cote.cote.contains(cote))
)
results = qry.all()
elif search.data['Signataire']:
qry = db_session.query(Cote).filter(or_(
Cote.signataire_nom.contains(signataire),Cote.signataire_titre.contains(signataire)))
results = qry.all()
if not results:
flash('No results !')
return redirect('/')
else:
table = Results(results)
table.border = True
return render_template('results.html', table=table)
Please add the indent to all the other lines except the define function line**
I found a way to solve this. Thank you for your collaboration i appreciate.
Now i get the exact match.
I changed the code to this ->
def search_results(search):
lieu = search.data['Lieu']
annee = search.data['Annee']
signataire_nom = search.data['Signataire_nom']
signataire_titre = search.data['Signataire_titre']
cote = search.data['Cote']
sujet_1 = search.data['Sujet_1']
sujet_2 = search.data['Sujet_2']
sujet_3 = search.data['Sujet_3']
categorie = search.data['Categorie']
conditions = [
Cote.lieu.contains(lieu),
Cote.annee.contains(annee),
Cote.cote.contains(cote),
Cote.categorie.contains(categorie),
Cote.signataire_nom.contains(signataire_nom),
Cote.signataire_titre.contains(signataire_titre),
Cote.sujet_1.contains(sujet_1),
Cote.sujet_2.contains(sujet_2), Cote.sujet_3.contains(sujet_3)
]
results = []
if search.data['Lieu'] or search.data['Annee'] or search.data['Cote'] or search.data['Categorie'] or search.data['Signataire_nom'] or search.data['Signataire_titre'] or search.data['Sujet']:
qry = Cote.query.filter(and_( * conditions))
results = qry.all()
if not results:
flash('No results !')
return redirect('/')
else :
table = Results(results)
table.border = True
return render_template('results.html', table = table)
Jaybe

python how to sort a list

i have to display a list shift wise like have to first show all day shift results then afternoon then night
but now it shows afternoon first then night then day
here is my code
views.py:
def get_queryset(self):
getall = self.request.GET.get("getall")
if self.request.user:
versions = LogVersion.objects.filter(
form__airport__id=self.request.user.aerosimple_user.airport_id
).exclude(status=DRAFT)
filters = self.request.GET.get("filters")
tags = self.request.GET.get("tags")
logs = Log.objects.none()
result = Log.objects.none()
for v in versions:
if len(v.operation_logs.order_by('-id').all())>0:
result = result | v.operation_logs.order_by('-id').all()
result = result.exclude(shift_name = None).exclude(shift_name='')
# if getall:
if getall:
return Log.objects.filter(
form__form__airport__id=self.request.user.aerosimple_user.airport.id)
if filters is not None:
filters = filters[:-2] if filters[-2:] == ',,' else filters
filters_list = filters.split(',,')
for filters in filters_list:
log = result.filter(Q(type = filters) | Q(subtype = filters))
if filters == 'Inspection Completed':
log = result.filter(Q(description = filters))
elif log != []:
for r in result:
if r.tags is not None and filters in r.tags:
log =result.filter(id=r.id)
else:
log = result.filter(Q(type = filters) | Q(subtype = filters))
logs = logs | log
return logs.all()
return result
how to sort it correctly
Example:
logs = sorted(logs, key=lambda x: dict(day=1, afternoon=2, night=3)[x.shift])

How create a sqlalchemy delete query with multiples parameter from a loop

I'm new in python and sqlalchemy.
I already have a delete method working if I construct the where conditions by hand.
Now, I need to read the columns and values from an enter request in yaml format and create the where conditions.
#enter data as yaml
items:
- item:
table: [MyTable,OtherTable]
filters:
field_id: 1234
#other_id: null
Here is what I try and can't go ahead:
for i in use_case_cfg['items']:
item = i.get('item')
for t in item['table']:
if item['filters']:
filters = item['filters']
where_conditions = ''
count = 0
for column, value in filters.items():
aux = str(getattr(t, column) == bindparam(value))
if count == 0:
where_conditions += aux
else:
where_conditions += ', ' + aux
count += 1
to_delete = inv[t].__table__.delete().where(text(where_conditions))
#to_delete = t.__table__.delete().where(getattr(t, column) == value)
else:
to_delete = inv[t].__table__.delete()
CoreData.session.execute(to_delete)
To me, it looks ok, but when I run, I got the error below:
sqlalchemy.exc.StatementError: (sqlalchemy.exc.InvalidRequestError) A value is required for bind parameter '9876'
[SQL: DELETE FROM MyTable WHERE "MyTable".field_id = %(1234)s]
[parameters: [{}]]
(Background on this error at: http://sqlalche.me/e/cd3x)
Can someone explain to me what is wrong or the proper way to do it?
Thanks.
There are two problems with the code.
Firstly,
str(getattr(t, column) == bindparam(value))
is binding the value as a placeholder, so you end up with
WHERE f2 = :Bob
but it should be the name that maps to the value in filters (so the column name in your case), so you end up with
WHERE f2 = :f2
Secondly, multiple WHERE conditions are being joined with a comma, but you should use AND or OR, depending on what you are trying to do.
Given a model Foo:
class Foo(Base):
__tablename__ = 'foo'
id = sa.Column(sa.Integer, primary_key=True)
f1 = sa.Column(sa.Integer)
f2 = sa.Column(sa.String)
Here's a working version of a segment of your code:
filters = {'f1': 2, 'f2': 'Bob'}
t = Foo
where_conditions = ''
count = 0
for column in filters:
aux = str(getattr(t, column) == sa.bindparam(column))
if count == 0:
where_conditions += aux
else:
where_conditions += ' AND ' + aux
count += 1
to_delete = t.__table__.delete().where(sa.text(where_conditions))
print(to_delete)
session.execute(to_delete, filters)
If you aren't obliged to construct the WHERE conditions as strings, you can do it like this:
where_conditions = [(getattr(t, column) == sa.bindparam(column))
for column in filters]
to_delete = t.__table__.delete().where(sa.and_(*where_conditions))
session.execute(to_delete, filters)

Make a sql select with a list in flask

I'm working in a code with flask and sql. I'm doing a json request to the datab base but i just need somecolumns so i have their names in a list and i have to pass them as params.
#app.route('/ajax-request', methods = ['POST'])
def ajax_request():
table = request.form['table']
columns = request.form.getlist('columns[]')
Model = ''
if table == 'Customer':
Model = Customer
elif table == 'Tile':
Model = Tile
elif table == 'Kind_of_tile':
Model = Kind_of_tile
elif table == 'Tile_example':
Model = Tile_example
columns_query = []
for x in columns:
columns_query.append(getattr(Model, x))
columns_query = tuple(columns_query)
for x in columns_query:
print(x)
query = ***Model.query.add_columns(', '.join(map(str, columns_query))).first()***
exit();

create and assign subcategories in revit using python

I have a question for some of you who are familiar with the Revit API and python:
I’ve been using the spring nodes package in dynamo to create a rather large series of freeform objects each in their own family. The way that the FamilyInstance.ByGeometry works, it takes a list of solids and creates a family instance for each using a template family file. The result is quite good. (spring nodes can be found here: https://github.com/dimven/SpringNodes)
However, the drawback is that that now I have roughly 200 separate instances, so to make changes to each is rather painful. I thought at first it would be possible to use dynamo to create a new subcategory and set the solid inside each family instance to this new subcategory. Unfortunately, I realized this is not possible since dynamo cannot be open in two different Revit environments simultaneously (the project I am working in and each instance of the family). This leads me to look to see if I can do this using python.
I have used python in rhino and can get along pretty well, I am still learning the Revit API however. But basically my idea would be to:
1. select a series of family instances in the Revit project environment
2. loop through each instance
3. save it to a specified location
4. create a new subcategory in each family instances (the subcategory would the same for all the selected family instances)
5. select the solid in each in instance
6. set the solid to this newly created subcategory
7. close the family instance and save
My question for you is does this sound like it is achievable based on your knowledge of the Revit API?
Many thanks for your time and advice.
UPDATE:
I've found a section in the revit api that describes what i'm looking to do: http://help.autodesk.com/view/RVT/2015/ENU/?guid=GUID-FBF9B994-ADCB-4679-B50B-2E9A1E09AA48
I've made a first pass at inserting this into the python code of the dynamo node. The rest of the code works fine except for the new section im adding (see below). Please excuse the variables, I am simply keeping with logic of the original author of the code i am hacking:
(Note: the variables come in are in arrays)
#set subcategory
try:
#create new sucategory
fam_subcat = famdoc.Settings.Categories.NewSubcategory(fam_cat, get_Item(subcat1.Name))
#assign the mataterial(fam_mat.Id) to the subcategory
fam_subcat.Material = famdoc.GetElement(fam_mat.Id)
#assign the subcategory to the element (s2)
s2.Subcategory = fam_subcat
except: pass
Any help or advice with this section of code would be much appreciated.
UPDATE:
See full code below for context of the section in question:
#Copyright(c) 2015, Dimitar Venkov
# #5devene, dimitar.ven#gmail.com
import clr
import System
from System.Collections.Generic import *
pf_path = System.Environment.GetFolderPath(System.Environment.SpecialFolder.ProgramFilesX86)
import sys
sys.path.append("%s\IronPython 2.7\Lib" %pf_path)
import traceback
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *
clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
doc = DocumentManager.Instance.CurrentDBDocument
app = DocumentManager.Instance.CurrentUIApplication.Application
clr.AddReference("RevitAPI")
from Autodesk.Revit.DB import *
from Autodesk.Revit.DB.Structure import StructuralType
clr.AddReference("RevitNodes")
import Revit
clr.ImportExtensions(Revit.Elements)
clr.ImportExtensions(Revit.GeometryConversion)
def tolist(obj1):
if hasattr(obj1,"__iter__"): return obj1
else: return [obj1]
def output1(l1):
if len(l1) == 1: return l1[0]
else: return l1
def PadLists(lists):
len1 = max([len(l) for l in lists])
for i in xrange(len(lists)):
if len(lists[i]) == len1:
continue
else:
len2 = len1 - len(lists[i])
for j in xrange(len2):
lists[i].append(lists[i][-1])
return lists
class FamOpt1(IFamilyLoadOptions):
def __init__(self):
pass
def OnFamilyFound(self,familyInUse, overwriteParameterValues):
return True
def OnSharedFamilyFound(self,familyInUse, source, overwriteParameterValues):
return True
geom = tolist(IN[0])
fam_path = IN[1]
names = tolist(IN[2])
category = tolist(IN[3])
material = tolist(IN[4])
isVoid = tolist(IN[5])
subcategory = tolist(IN[6])
isRvt2014 = False
if app.VersionName == "Autodesk Revit 2014": isRvt2014 = True
units = doc.GetUnits().GetFormatOptions(UnitType.UT_Length).DisplayUnits
factor = UnitUtils.ConvertToInternalUnits(1,units)
acceptable_views = ["ThreeD", "FloorPlan", "EngineeringPlan", "CeilingPlan", "Elevation", "Section"]
origin = XYZ(0,0,0)
str_typ = StructuralType.NonStructural
def NewForm_background(s1, name1, cat1, isVoid1, mat1, subcat1):
t1 = TransactionManager.Instance
TransactionManager.ForceCloseTransaction(t1)
famdoc = doc.Application.NewFamilyDocument(fam_path)
message = None
temp_path = System.IO.Path.GetTempPath()
sat_path = "%s%s.sat" % (temp_path, name1)
try:
if factor != 1:
s1 = s1.Scale(factor)
sat1 = Geometry.ExportToSAT(s1, sat_path)
satOpt = SATImportOptions()
satOpt.Placement = ImportPlacement.Origin
satOpt.Unit = ImportUnit.Foot
view_fec = FilteredElementCollector(famdoc).OfClass(View)
view1 = None
for v in view_fec:
if str(v.ViewType) in acceptable_views:
view1 = v
break
t1.EnsureInTransaction(famdoc)
satId = famdoc.Import(sat1, satOpt, view1)
opt1 = Options()
opt1.ComputeReferences = True
el1 = famdoc.GetElement(satId)
geom1 = el1.get_Geometry(opt1)
enum = geom1.GetEnumerator()
enum.MoveNext()
geom2 = enum.Current.GetInstanceGeometry()
enum2 = geom2.GetEnumerator()
enum2.MoveNext()
s1 = enum2.Current
famdoc.Delete(satId)
TransactionManager.ForceCloseTransaction(t1)
System.IO.File.Delete(sat_path)
except:
message = traceback.format_exc()
pass
if message == None:
try:
save_path = "%s%s.rfa" % (temp_path, name1)
SaveAsOpt = SaveAsOptions()
SaveAsOpt.OverwriteExistingFile = True
t1.EnsureInTransaction(famdoc)
#set the category
try:
fam_cat = famdoc.Settings.Categories.get_Item(cat1.Name)
famdoc.OwnerFamily.FamilyCategory = fam_cat
except: pass
s2 = FreeFormElement.Create(famdoc,s1)
if isVoid1:
void_par = s2.get_Parameter("Solid/Void")
void_par.Set(1)
void_par2 = famdoc.OwnerFamily.get_Parameter("Cut with Voids When Loaded")
void_par2.Set(1)
else: #voids do not have a material value
try:
mat_fec = FilteredElementCollector(famdoc).OfClass(Material)
for m in mat_fec:
if m.Name == mat1:
fam_mat = m
break
mat_par = s2.get_Parameter("Material")
mat_par.Set(fam_mat.Id)
except: pass
#set subcategory
try:
#create new sucategory
fam_subcat = document.Settings.Categories.NewSubcategory(document.OwnerFamily.FamilyCategory, get_Item(subcat1.Name))
#assign the mataterial(fam_mat.Id) to the subcategory
fam_subcat.Material = famdoc.GetElement(fam_mat.Id)
#assign the subcategory to the element (s2)
s2.Subcategory = fam_subcat
except: pass
TransactionManager.ForceCloseTransaction(t1)
famdoc.SaveAs(save_path, SaveAsOpt)
family1 = famdoc.LoadFamily(doc, FamOpt1())
famdoc.Close(False)
System.IO.File.Delete(save_path)
symbols = family1.Symbols.GetEnumerator()
symbols.MoveNext()
symbol1 = symbols.Current
t1.EnsureInTransaction(doc)
if not symbol1.IsActive: symbol1.Activate()
inst1 = doc.Create.NewFamilyInstance(origin, symbol1, str_typ)
TransactionManager.ForceCloseTransaction(t1)
return inst1.ToDSType(False), family1.ToDSType(False)
except:
message = traceback.format_exc()
return message
else:
return message
def NewForm_background_R16(s1, name1, cat1, isVoid1, mat1, subcat1):
t1 = TransactionManager.Instance
TransactionManager.ForceCloseTransaction(t1)
famdoc = doc.Application.NewFamilyDocument(fam_path)
message = None
temp_path = System.IO.Path.GetTempPath()
sat_path = "%s%s.sat" % (temp_path, name1)
try:
if factor != 1:
s1 = s1.Scale(factor)
sat1 = Geometry.ExportToSAT(s1, sat_path)
satOpt = SATImportOptions()
satOpt.Placement = ImportPlacement.Origin
satOpt.Unit = ImportUnit.Foot
view_fec = FilteredElementCollector(famdoc).OfClass(View)
view1 = None
for v in view_fec:
if str(v.ViewType) in acceptable_views:
view1 = v
break
t1.EnsureInTransaction(famdoc)
satId = famdoc.Import(sat1, satOpt, view1)
opt1 = Options()
opt1.ComputeReferences = True
el1 = famdoc.GetElement(satId)
geom1 = el1.get_Geometry(opt1)
enum = geom1.GetEnumerator()
enum.MoveNext()
geom2 = enum.Current.GetInstanceGeometry()
enum2 = geom2.GetEnumerator()
enum2.MoveNext()
s1 = enum2.Current
famdoc.Delete(satId)
TransactionManager.ForceCloseTransaction(t1)
System.IO.File.Delete(sat_path)
except:
message = traceback.format_exc()
pass
if message == None:
try:
save_path = "%s%s.rfa" % (temp_path, name1)
SaveAsOpt = SaveAsOptions()
SaveAsOpt.OverwriteExistingFile = True
t1.EnsureInTransaction(famdoc)
#set the category
try:
fam_cat = famdoc.Settings.Categories.get_Item(cat1.Name)
famdoc.OwnerFamily.FamilyCategory = fam_cat
except: pass
s2 = FreeFormElement.Create(famdoc,s1)
if isVoid1:
void_par = s2.LookupParameter("Solid/Void")
void_par.Set(1)
void_par2 = famdoc.OwnerFamily.LookupParameter("Cut with Voids When Loaded")
void_par2.Set(1)
else: #voids do not have a material value
try:
mat_fec = FilteredElementCollector(famdoc).OfClass(Material)
for m in mat_fec:
if m.Name == mat1:
fam_mat = m
break
mat_par = s2.LookupParameter("Material")
mat_par.Set(fam_mat.Id)
except: pass
#apply same subcategory code as before
#set subcategory
try:
#create new sucategory
fam_subcat = famdoc.Settings.Categories.NewSubcategory(fam_cat, get_Item(subcat1.Name))
#assign the mataterial(fam_mat.Id) to the subcategory
fam_subcat.Material = famdoc.GetElement(fam_mat.Id)
#assign the subcategory to the element (s2)
s2.Subcategory = fam_subcat
except: pass
TransactionManager.ForceCloseTransaction(t1)
famdoc.SaveAs(save_path, SaveAsOpt)
family1 = famdoc.LoadFamily(doc, FamOpt1())
famdoc.Close(False)
System.IO.File.Delete(save_path)
symbols = family1.GetFamilySymbolIds().GetEnumerator()
symbols.MoveNext()
symbol1 = doc.GetElement(symbols.Current)
t1.EnsureInTransaction(doc)
if not symbol1.IsActive: symbol1.Activate()
inst1 = doc.Create.NewFamilyInstance(origin, symbol1, str_typ)
TransactionManager.ForceCloseTransaction(t1)
return inst1.ToDSType(False), family1.ToDSType(False)
except:
message = traceback.format_exc()
return message
else:
return message
if len(geom) == len(names) == len(category) == len(isVoid) == len(material) == len(subcategory):
if isRvt2014:
OUT = output1(map(NewForm_background, geom, names, category, isVoid, material, subcategory))
else:
OUT = output1(map(NewForm_background_R16, geom, names, category, isVoid, material, subcategory))
elif len(geom) == len(names):
padded = PadLists((geom, category, isVoid, material, subcategory))
p_category = padded[1]
p_isVoid = padded[2]
p_material = padded[3]
p_subcategory = padded [4]
if isRvt2014:
OUT = output1(map(NewForm_background, geom, names, p_category, p_isVoid, p_material, p_subcategory))
else:
OUT = output1(map(NewForm_background_R16, geom, names, p_category, p_isVoid, p_material, subcategory))
else: OUT = "Make sure that each geometry\nobject has a unique family name."
Update:
Was able to get it working:
try:
#create new sucategory
fam_subcat = famdoc.Settings.Categories.NewSubcategory(famdoc.OwnerFamily.FamilyCategory, subcat1)
#assign the mataterial(fam_mat.Id) to the subcategory
#fam_subcat.Material = famdoc.GetElement(fam_mat.Id)
#assign the subcategory to the element (s2)
s2.Subcategory = fam_subcat
except: pass
As I answered on your initial query per email, what you are aiming for sounds perfectly feasible to me in the Revit API. Congratulations on getting as far as you have. Looking at the link to the Revit API help file and developer guide that you cite above, it seems that the code has to be executed in the family document while defining the family. The context in which you are trying to execute it is not clear. Have you used EditFamily to open the family definition document? What context are you executing in?

Categories