Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
A perl script to parse a core-data model file, and generate a django model. The django model will still need to be edited, but it's a start. The code's kind of weird, because it originally generated a sql schema. Hows that for cross platform.
#!/usr/bin/env perl
use strict;
use warnings;
use XML::Simple;
use Data::Dumper;
use Scalar::Util 'reftype';
use JSON;
use Carp;
use DBI;
my %excluded_attributes;
my %excluded_relationships;
my %config;
my @methods;
my %relationships;
my %model;
my @reserved_words = qw(ACCESSIBLE ADD ALL ALTER ANALYZE AND AS ASC ASENSITIVE BEFORE BETWEEN BIGINT BINARY BLOB BOTH BY CALL CASCADE
CASE CHANGE CHAR CHARACTER CHECK COLLATE COLUMN CONDITION CONSTRAINT CONTINUE CONVERT CREATE CROSS CURRENT_DATE CURRENT_TIME
CURRENT_TIMESTAMP CURRENT_USER CURSOR DATABASE DATABASES DAY_HOUR DAY_MICROSECOND DAY_MINUTE DAY_SECOND DEC DECIMAL DECLARE
DEFAULT DELAYED DELETE DESC DESCRIBE DETERMINISTIC DISTINCT DISTINCTROW DIV DOUBLE DROP DUAL
EACH ELSE ELSEIF ENCLOSED ESCAPED EXISTS
EXIT EXPLAIN FALSE FETCH FLOAT FLOAT4 FLOAT8 FOR FORCE FOREIGN FROM FULLTEXT
GRANT GROUP HAVING HIGH_PRIORITY HOUR_MICROSECOND HOUR_MINUTE
HOUR_SECOND IF IGNORE IN INDEX INFILE INNER INOUT INSENSITIVE INSERT INT INT1
INT2 INT3 INT4 INT8 INTEGER INTERVAL INTO IS ITERATE JOIN KEY KEYS
KILL LEADING LEAVE LEFT LIKE LIMIT LINEAR LINES LOAD LOCALTIME LOCALTIMESTAMP LOCK
LONG LONGBLOB LONGTEXT LOOP LOW_PRIORITY MASTER_SSL_VERIFY_SERVER_CERT
MATCH MAXVALUE MEDIUMBLOB MEDIUMINT MEDIUMTEXT MIDDLEINT MINUTE_MICROSECOND MINUTE_SECOND MOD MODIFIES NATURAL NOT
NO_WRITE_TO_BINLOG NULL NUMERIC ON OPTIMIZE OPTION OPTIONALLY OR ORDER OUT OUTER OUTFILE
PRECISION PRIMARY PROCEDURE PURGE RANGE READ READS READ_WRITE REAL REFERENCES REGEXP RELEASE
RENAME REPEAT REPLACE REQUIRE RESIGNAL RESTRICT RETURN REVOKE RIGHT RLIKE SCHEMA SCHEMAS
SECOND_MICROSECOND SELECT SENSITIVE SEPARATOR SET SHOW SIGNAL SMALLINT SPATIAL
SPECIFIC SQL SQLEXCEPTION SQLSTATE SQLWARNING SQL_BIG_RESULT
SQL_CALC_FOUND_ROWS SQL_SMALL_RESULT SSL STARTING STRAIGHT_JOIN TABLE
TERMINATED THEN TINYBLOB TINYINT TINYTEXT TO TRAILING TRIGGER TRUE UNDO UNION UNIQUE
UNLOCK UNSIGNED UPDATE USAGE USE USING UTC_DATE UTC_TIME UTC_TIMESTAMP VALUES VARBINARY VARCHAR
VARCHARACTER VARYING WHEN WHERE WHILE WITH WRITE XOR YEAR_MONTH ZEROFILL TYPE);
sub proccess_relationship($$$){
my %r = %{shift @_};
my $source_entity = shift @_;
my $name = shift @_;
my $destination_entity = $r{'destinationEntity'};
my $sql_attribute;
my %relationship;
$relationship{"name"} = $name;
if($r{"toMany"} && $r{"toMany"} eq "YES"){
$relationship{"to_many"} = 1;
} else {
$relationship{"to_many"} = 0;
}
$sql_attribute = $name;
$relationship{"sql_field"} = $sql_attribute;
$relationship{"delete_rule"} = $r{"deletionRule"};
$relationship{"type"} = $destination_entity;
$relationship{"inverse_name"} = $r{"inverseName"};
$model{$source_entity}->{"relationships"}->{$name} = \%relationship;
}
sub is_reserved_word($){
my $name = uc(shift @_);
if ( grep { $_ eq $name} @reserved_words ){
return 1;
}else{
return 0;
}
}
sub parse_model{
my $xml = new XML::Simple;
my $data = $xml->XMLin($_[0]);
#print Dumper($data);
my %entities = %{$data->{'entity'}};
foreach my $entityName(keys(%entities)){
my %destination_entity;
my %source_entity = %{$entities{$entityName}};
my %source_attributes = %{$source_entity{'attribute'}};
foreach my $attributeName(keys(%source_attributes)){
my %this_source_attribute = %{$source_attributes{$attributeName}};
my $type = $this_source_attribute{'attributeType'};
if($type eq 'String'){
$type = "CharField";
}elsif($type eq 'Integer 16'){
$type = "SmallIntegerField";
}elsif($type eq 'Integer 32'){
$type = "IntegerField";
}elsif($type eq 'Integer 64'){
$type = "BigIntegerField";
}elsif($type eq "Decimal"){
$type = "DecimalField";
}elsif($type eq "Double"){
$type = "FloatField";
}elsif($type eq "Float"){
$type = "FloatField";
}elsif($type eq "Boolean"){
$type = "BooleanField";
}elsif($type eq "Date"){
$type = "DateField";
}elsif($type eq "Binary"){
$type = "BinaryField";
}elsif($type eq "Transformable"){
$type = "BinaryField";
}else{
print "ERROR: unknown type $type";
}
my %destination_attribute;
$destination_attribute{"type"} = $type;
if($this_source_attribute{'optional'} && $this_source_attribute{'optional'} ne "YES"){
$destination_attribute{"optional"} = 0;
}else{
$destination_attribute{"optional"} = 1;
}
my $sql_name;
if(is_reserved_word($attributeName)){
$destination_attribute{"original_name"} = $attributeName;
$sql_name = $attributeName . "_field";
}else{
$sql_name = $attributeName;
}
$destination_attribute{"sql_field"} = $sql_name;
$destination_entity{"attributes"}{$attributeName} = \%destination_attribute;
}
$model{$entityName} = \%destination_entity;
if($source_entity{'relationship'}){
my %relationships = %{$source_entity{'relationship'}};
foreach my $relationship_name (sort(keys(%relationships))){
if(!ref($relationships{$relationship_name})){
proccess_relationship(\%relationships, $entityName, $relationships{"name"});
last;
}else{
proccess_relationship($relationships{$relationship_name}, $entityName, $relationship_name);
}
}
}
}
}
sub generate_sql{
my $outfile = "models.py";
open schemaSQL, ">$outfile";
foreach my $entity_name(sort(keys(%model))){
my %entity = %{$model{$entity_name}};
my %attributes = %{$entity{"attributes"}};
my @attribute_keys = sort(keys(%attributes));
my $id_field = $config{"primary_keys"}->{$entity_name};
if(!$id_field){
$id_field = $entity_name . "_id";
}
$model{$entity_name}->{"primary_key"} = $id_field;
print schemaSQL "class $entity_name(models.Model):\n";
my @relationship_keys;
my %relationships;
if($entity{"relationships"}){
%relationships = %{$entity{"relationships"}};
foreach my $r(sort(keys(%relationships))){
if($relationships{$r}->{"sql_field"}){
my %relationship = %{$relationships{$r}};
#print Dumper(\%relationship);
if(! $relationship{"sql_field"}){
next;
}
my $sql_line = "";
$sql_line = "\t" . $relationship{"sql_field"} . " = models.ForeignKey(";
$sql_line .= "related_name='" . $relationship{"inverse_name"} . "'";
if($relationship{'delete_rule'} eq "Nullify") {
$sql_line .= ", on_delete=models.SET_NULL";
}elsif($relationship{'delete_rule'} eq "CASCADE") {
$sql_line .= ", on_delete=models.CASCADE";
}
$sql_line .= ")\n";
print schemaSQL $sql_line;
}
}
}
if($entity{"relationships"}){
while(my $relationship_name = shift @relationship_keys){
}
}
for(my $i = 0; $i <= $#attribute_keys; $i++){
my $attribute_name = $attribute_keys[$i];
my %attribute = %{$attributes{$attribute_name}};
my $sql_line = "\t" . $attribute{"sql_field"} . " = models." . $attribute{"type"} . "(";
if(!$attribute{"optional"}){
$sql_line .= "null=True, blank=True";
}
$sql_line .= ")\n";
print schemaSQL $sql_line;
}
print schemaSQL "\n\n";
}
close schemaSQL;
}
parse_model($ARGV[0]);
generate_sql();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.