0

I have created 2 separate model files called 'Topics' and 'SubTopics'. My SubTopic model class import Topic class because sub topic cannot be created without a topic. This all works pretty well until i try to add the functionality to delete topics.

Before deleting the topic i have to check whether that selected topic has any sub topics, and if it does avoiding user from deleting that main topic. so in order to achieve this i had to import 'SubTopic' class inside 'Topic' to check the no of sub topics exists for the topic the user tries to delete.

this cause the app to crash because the 'SubTopic' already importing the 'Topic' so by importing 'SubTopic' inside 'Topic' created ImportError.

How to resolve this issue? I like to keep each model in separate classes for readability and cleanness.

This is my directory listing,

/
model/
  Topic.py
  SubTopic.py
run.py

Please find below the code,

Topic.py

import datetime
import uuid
import os

# from model.Questions import Questions  ---- > ImportError
# from model.SubTopics import SubTopics  -----> ImportError
from app import db
from flask.ext.admin.contrib.mongoengine import ModelView
from flask.ext.login import current_user
from Users import User
from flask import request, flash
from constants import *
from wtforms.fields import FileField
from flask.ext.admin.model.template import macro
from wtforms.validators import ValidationError


class Topics(db.Document):
    topicName = db.StringField(required=True)
    haveSubtopics = db.BooleanField()
    image = db.StringField()
    createdBy = db.ReferenceField(User)
    updatedBy = db.ReferenceField(User)
    createdDate = db.DateTimeField(default=datetime.datetime.now())

    def get_all_topics(self):
        topicList = Topics.objects.all()

        if(topicList):
            return topicList
        else:
            return None

    def get_topic(self, id):
        topic = Topics.objects.get(pk=id)

        if(topic):
            return topic
        else:
            return None


    def __unicode__(self):
        return self.topicName

    def delete(self):
        dataCnt = 0
        if self.haveSubtopics:
            dataCnt = SubTopics.objects(mainTopic=self.pk).count()  ---> Check sub topic exits before delete
        else:
            dataCnt = Questions.objects(topic=self.pk).count()  ----> Check questions exits before delete

        if dataCnt > 0:
            flash('Cannot delete this topic. Questions or sub topic exists under this topic')
            return False
        else:
            if not self.image is None:
                if os.path.isfile(self.image):
                 os.unlink(self.image)

            self.delete()
            return True

class TopicsView(ModelView):
    def is_accessible(self):
        if current_user.is_authenticated():
            return True
        else:
           return False

    column_list = ('topicName','createdDate','haveSubtopics')
    column_labels = dict(topicName='Topic', createdDate='Created Date', haveSubtopics='Sub Topics')

    form_excluded_columns = ('createdBy','createdDate', 'updatedBy')

    create_template = 'create_topic_form.html'
    edit_template = 'edit_topic_form.html'
    list_template = 'list_topics.html'

SubTopics.py

import datetime

from app import db
from model.Topics import Topics
from flask.ext.admin.contrib.mongoengine import ModelView
from flask.ext.login import current_user
from Users import User
from constants import *
from flask import request
from wtforms.validators import ValidationError
from flask.ext.admin.model.template import macro


class SubTopics(db.Document):
    subTopicName = db.StringField(required=True)
    mainTopic = db.ReferenceField(Topics, required=True)
    createdBy = db.ReferenceField(User, required=True)
    createdDate = db.DateTimeField(default=datetime.datetime.now())

    def get_all_subtopics(self, topicid):
        subTopicList = SubTopics.objects(mainTopic=topicid)

        if(subTopicList):
            return subTopicList
        else:
            return None

    def __unicode__(self):
        return self.subTopicName


class SubTopicsView(ModelView):
    def is_accessible(self):
        if current_user.is_authenticated():
            return True
        else 
           return False

    column_list = ('subTopicName','mainTopic', 'createdDate')
    column_labels = dict(subTopicName='Name', mainTopic='Topic', createdDate = 'Created Date')

    form_excluded_columns = ('createdBy','createdDate')

    def check_mainTopic(self, form):
        topi = request.form['mainTopic']
        topicObj = Topics.objects.with_id(topi)

        if topicObj:
            if not topicObj.haveSubtopics:
                raise ValidationError('Selected topic cannot have sub topics')

    form_args = dict(
        subTopicName=dict(label='Name'),
        mainTopic=dict(label='Topic', validators = [check_mainTopic])
    )

    list_template = 'list_sub_topics.html'

Thanks in advanced,

niroshan
  • 181
  • 10
  • This is a general question about python imports I think. BTW putting your code snippets will help to introduce a better solution, and you can always use dependency injection to avoid these problems. – mehdix Aug 17 '14 at 15:09
  • I have edited my question with code sample – niroshan Aug 18 '14 at 11:05
  • I strongly recommend you to read this Q&A http://stackoverflow.com/a/1556444/157216 and reconsider why you want to split your code into two modules when they are heavily tied together. – mehdix Aug 18 '14 at 14:58

3 Answers3

1

Do not import subtopic, or do not import topic. For example to check if topic has any subtopic it should be sufficient for you to check whether the children list is empty. Python's duck typing means you don't need the import in order access the methods of an object. If you post your code I can be more specific.

Oliver
  • 27,510
  • 9
  • 72
  • 103
0

If you look for a fast solution to your code you can import Question and SubTopic inside delete method:

def delete(self):
    import model
    dataCnt = 0
    if self.haveSubtopics:
        dataCnt = model.SubTopics.objects(mainTopic=self.pk).count()
    else:
        dataCnt = model.Questions.objects(topic=self.pk).count()

    if dataCnt > 0:
        flash('Cannot delete this topic. Questions or sub topic exists under this topic')
        return False
    else:
        if not self.image is None:
            if os.path.isfile(self.image):
             os.unlink(self.image)

        self.delete()
        return True
mehdix
  • 4,984
  • 1
  • 28
  • 36
0

just add __init__.py in model folder

cyberra
  • 579
  • 1
  • 6
  • 14