coleifer / peewee

a small, expressive orm -- supports postgresql, mysql, sqlite and cockroachdb
http://docs.peewee-orm.com/
MIT License
11.19k stars 1.37k forks source link

join one table have 2 fk and one have another fk too, IndexError: list index out of range #2799

Closed wanghaisheng closed 1 year ago

wanghaisheng commented 1 year ago
1
3
2
4
5
8
Exception in Tkinter callback
Traceback (most recent call last):
  File "D:\Programs\anaconda\lib\site-packages\peewee.py", line 7160, in get
    return clone.execute(database)[0]
  File "D:\Programs\anaconda\lib\site-packages\peewee.py", line 4510, in __getitem__
    return self.row_cache[item]
IndexError: list index out of range

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "D:\Programs\anaconda\lib\tkinter\__init__.py", line 1892, in __call__
    return self.func(*args)

  File "D:\Download\audio-visual\saas\tiktoka\tiktoka-studio-uploader-genius\main.py", line 6077, in queryTasks
    task_rows=TaskModel.filter_tasks(status=status,type=platform,video_title=vtitle,video_id=vid,username=username)
  File "D:\Download\audio-visual\saas\tiktoka\tiktoka-studio-uploader-genius\src\models\task_model.py", line 139, in filter_tasks    
    print('filter tasks',i.video,i.setting)
  File "D:\Programs\anaconda\lib\site-packages\peewee.py", line 4657, in __get__
    return self.get_rel_instance(instance)
  File "D:\Programs\anaconda\lib\site-packages\peewee.py", line 4648, in get_rel_instance
    obj = self.rel_model.get(self.field.rel_field == value)
  File "D:\Programs\anaconda\lib\site-packages\peewee.py", line 6712, in get
    return sq.get()
  File "D:\Programs\anaconda\lib\site-packages\peewee.py", line 7163, in get
    raise self.model.DoesNotExist('%s instance matching query does '
src.models.youtube_video_model.YoutubeVideoModelDoesNotExist: <Model: YoutubeVideoModel> instance matching query does not exist:     
SQL: SELECT "t1"."id", "t1"."youtube_video_id", "t1"."video_local_path", "t1"."video_title", "t1"."video_description", "t1"."thumbnail_local_path", "t1"."publish_policy", "t1"."is_age_restriction", "t1"."is_paid_promotion", "t1"."is_automatic_chapters", "t1"."is_featured_place", "t1"."video_language", "t1"."captions_certification", "t1"."video_film_date", "t1"."video_film_location", "t1"."license_type", "t1"."is_allow_embedding", "t1"."is_publish_to_subscriptions_feed_notify", "t1"."shorts_remixing_type", "t1"."is_show_howmany_likes", "t1"."is_monetization_allowed", "t1"."first_comment", "t1"."subtitles", "t1"."is_not_for_kid", "t1"."categories", "t1"."comments_ratings_policy", "t1"."tags", "t1"."release_date", "t1"."release_date_hour", "t1"."inserted_at", "t1"."unique_hash", "t1"."is_deleted" FROM "youtubevideomodel" AS "t1" WHERE ("t1"."id" = ?) LIMIT ? OFFSET ?
Params: [<memory at 0x000001C8821E4100>, 1, 0]
class TaskModel(BaseModel):
    id = BlobField(primary_key=True)    

    video = ForeignKeyField(YoutubeVideoModel, backref='videos')
    setting = ForeignKeyField(UploadSettingModel, backref='settings')

class YoutubeVideoModel(BaseModel):
    id = BlobField(primary_key=True)        
    video_local_path = TextField(null=True,default=None)
    video_title = TextField(null=True,default=None)
    video_description = TextField(null=True,default=None)

class UploadSettingModel(BaseModel):
    id = BlobField(primary_key=True)    
    account = ForeignKeyField(AccountModel, backref='account_id')

    def filter_tasks(cls, status=None, type=None,uploaded_at=None,setting=None,inserted_at=None,video_title=None,video_id=None,username=None):
        query=TaskModel.select()
        # query = TaskModel.select(TaskModel,YoutubeVideoModel,UploadSettingModel,AccountModel)
        print('all tasks are2 ',list(query))      

        # 如果存在video 相关的查询参数,先找到对应的video id集合
        if video_title=='':
            video_title=None
        if status=='':
            status=None
        if video_id=='':
            video_id=None
        if username=='':
            username=None
        if video_title is not None :
            print('ding ding video title')
            # query = query.where(cls.video.video_title == video_title)
            query = query.join(YoutubeVideoModel).where(YoutubeVideoModel.video_title == video_title)
            query=query.switch(TaskModel)  # <-- switch the "query context" back to ticket.

        print('1')

        if video_id is not None:
            # query = query.where(cls.video.youtube_video_id == video_id)
            query = query.join(YoutubeVideoModel).where(YoutubeVideoModel.youtube_video_id == video_id)
            query=query.switch(TaskModel)  # <-- switch the "query context" back to ticket.

        print('3')        
        # 如果存在account 相关的查询参数,先找到对应的 setting id集合
        if username is not None:
            # query = query.where(cls.setting.account.username == username)
            query = query.join(UploadSettingModel).join(AccountModel).where(AccountModel.username == username)

            query=query.switch(TaskModel)  # <-- switch the "query context" back to ticket.
        print('2')

        for i in query:
            print('filter tasks',i.video,i.setting)
        try:
            result = list(query)
            for i in result:
                print('filter tasks',i.video,i.setting)

        except cls.DoesNotExist:
            result = None  # Set a default value or perform any other action

        return result
coleifer commented 1 year ago

I can’t make sense out of all that. Can you provide a minimal example that reproduces the issue? If so I will reopen.

wanghaisheng commented 1 year ago

@coleifer this is a minimal one


from peewee import Model, CharField, IntegerField,TextField,BooleanField,IntegerField,ForeignKeyField
from peewee import *
import random

db_uri='1.sqlite3'

db = SqliteDatabase(db_uri)

class BaseModel(Model):
    class Meta:
        database = db
class AccountModel(BaseModel):
    id = IntegerField(primary_key=True)    
    platform = IntegerField(null=True)
    username = TextField(null=True)
    password = TextField(null=True)  

class YoutubeVideoModel(BaseModel):
    id = IntegerField(primary_key=True)        
    video_title = TextField(null=True,default=None)

class UploadSettingModel(BaseModel):
    id = IntegerField(primary_key=True)   
    timeout = IntegerField(default=200000)
    account = ForeignKeyField(AccountModel, backref='account_id')

class TaskModel(BaseModel):
    id = IntegerField(primary_key=True)    
    status = IntegerField()

    video = ForeignKeyField(YoutubeVideoModel, backref='videos')
    setting = ForeignKeyField(UploadSettingModel, backref='settings')

    def filter_tasks(cls, status=None, type=None,uploaded_at=None,setting=None,inserted_at=None,video_title=None,video_id=None,username=None):
            query=TaskModel.select()
            # query = TaskModel.select(TaskModel,YoutubeVideoModel,UploadSettingModel,AccountModel)
            print('all tasks are2 ',list(query))      

            if video_title is not None :
                print('ding ding video title')
                query = query.join(YoutubeVideoModel).where(YoutubeVideoModel.video_title == video_title)
                query=query.switch(TaskModel)  # <-- switch the "query context" back to ticket.

            # 如果存在account 相关的查询参数,先找到对应的 setting id集合
            if username is not None:
                query = query.join(UploadSettingModel).join(AccountModel).where(AccountModel.username == username)

                query=query.switch(TaskModel)  # <-- switch the "query context" back to ticket.
            print('2')

            for i in query:
                print('filter tasks',i.video,i.setting)
            try:
                result = list(query)
                for i in result:
                    print('filter tasks',i.video,i.setting)

            except cls.DoesNotExist:
                result = None  # Set a default value or perform any other action

            return result

    def filter_tasks2(cls, status=None, type=None,uploaded_at=None,setting=None,inserted_at=None,video_title=None,video_id=None,username=None):
            query = (TaskModel
                    .select(TaskModel, YoutubeVideoModel, UploadSettingModel, AccountModel)
                    .join(YoutubeVideoModel)  # Join favorite -> user (owner of favorite).
                    .switch(TaskModel)
                    .join(UploadSettingModel)  # Join favorite -> tweet
                    .join(AccountModel))   # Join tweet -> user        
            print('999999999',query)
            for fav in query:
                print('================')
                print(fav.video,fav.setting)

            if video_title is not None :
                print('ding ding video title')
                query=query.switch(TaskModel)  # <-- switch the "query context" back to ticket.

                query = (query
                # .join(YoutubeVideoModel,on=(TaskModel.video_id == YoutubeVideoModel.id))
                # .where(YoutubeVideoModel.video_title.regexp(video_title))
                .where(YoutubeVideoModel.video_title==video_title)

                )
                query=query.switch(TaskModel)  # <-- switch the "query context" back to ticket.

            print('1')

            if video_id is not None:
                query = query.join(YoutubeVideoModel,on=(TaskModel.video == YoutubeVideoModel.id)).where(YoutubeVideoModel.youtube_video_id == video_id)
                query=query.switch(TaskModel)  # <-- switch the "query context" back to ticket.

            print('3')        
            # 如果存在account 相关的查询参数,先找到对应的 setting id集合
            if username is not None:
                query = query.join(UploadSettingModel,on=(TaskModel.setting == UploadSettingModel.id)).join(AccountModel,on=(UploadSettingModel.account == AccountModel.id)).where(AccountModel.username.regexp(username))

                query=query.switch(TaskModel)  # <-- switch the "query context" back to ticket.
            print('2')

            try:
                result = list(query)
                for i in result:
                    for att in dir(i):
                        print('===============')
                        print(att,getattr(i,att))
                    print('----------',i.video)
                    print('----------',i.setting)

            except cls.DoesNotExist:
                result = None  # Set a default value or perform any other action

            return result

db.create_tables([AccountModel,UploadSettingModel,YoutubeVideoModel,TaskModel])

test_user={
                "platform":random.choice([0,1,2,3]),
                "username":"y1",
                "password":"p1"

}

accounts=[]
for i in range(1,20):
        account=AccountModel.save(
          test_user

        )
        accounts.append(account)

test_setting={

"timeout":random.choice(range(200,2000)),

"account":random.choice(accounts),
}

settings=[]
for i in range(1,20):
        setting=UploadSettingModel.save(
                test_setting,account=random.choice(accounts)

        )
        settings.append(setting)

test_video={
        "video_title": 'test title'+str(random.choice(range(1,100)))
        }

videos=[]
for i in range(1,50):
        video=YoutubeVideoModel.save(
                test_video

        )
        videos.append(setting)

test_task={
        "type":'',

        "status":random.choice([0,1,2])
        }

tasks=[]

for i in range(1,100):
        t=TaskModel.save( 
                test_task,setting=random.choice(settings),video=random.choice(videos)

        )
        tasks.append(t)
TaskModel.filter_tasks( status=None, type=None,uploaded_at=None,setting=None,inserted_at=None,video_title=None,video_id=None,username=None)
TaskModel.filter_tasks( status=None, type=None,uploaded_at=None,setting=None,inserted_at=None,video_title='test',video_id=None,username=None)
TaskModel.filter_tasks2( status=None, type=None,uploaded_at=None,setting=None,inserted_at=None,video_title=None,video_id=None,username=None)
TaskModel.filter_tasks2( status=None, type=None,uploaded_at=None,setting=None,inserted_at=None,video_title='test',video_id=None,username=None)
coleifer commented 1 year ago

I'm sorry but this code is neither minimal nor readable.

Also, this code does not even work...

wanghaisheng commented 1 year ago

@coleifer try this


from peewee import Model, CharField, IntegerField,TextField,BooleanField,IntegerField,ForeignKeyField
from peewee import *
import random,os
os.remove('1.sqlite3')

db_uri='1.sqlite3'

db = SqliteDatabase(db_uri)

class BaseModel(Model):
    class Meta:
        database = db
class AccountModel(BaseModel):
    id = IntegerField(primary_key=True)    
    platform = IntegerField(null=True)
    username = TextField(null=True)
    password = TextField(null=True)  

class YoutubeVideoModel(BaseModel):
    id = IntegerField(primary_key=True)        
    video_title = TextField(null=True,default=None)

class UploadSettingModel(BaseModel):
    id = IntegerField(primary_key=True)   
    timeout = IntegerField(default=20)
    account = ForeignKeyField(AccountModel, backref='account_id')

class TaskModel(BaseModel):
    id = IntegerField(primary_key=True)    
    status = IntegerField()

    video = ForeignKeyField(YoutubeVideoModel, backref='videos')
    setting = ForeignKeyField(UploadSettingModel, backref='settings')

    @classmethod

    def filter_tasks2(cls, status=None, type=None,uploaded_at=None,setting=None,inserted_at=None,video_title=None,video_id=None,username=None):
            query=TaskModel.select()
            print('========show without filter========')
            print('======show attr=========')     

            for i in query:
                print(list(query))
                for att in dir(i):
                    if 'setting' in att:
                        print(att,getattr(i,att))           

                    if 'video'  in att:
                        print(att,getattr(i,att))           
            print('======show ids=========')     

            for i in query:
                print(i.id)

            print('======show fks=========')     
            for i in query:
                print(i.video,i.setting)
            query = (TaskModel
                    .select(TaskModel, YoutubeVideoModel, UploadSettingModel, AccountModel)
                    .join(YoutubeVideoModel)  # Join favorite -> user (owner of favorite).
                    .switch(TaskModel)
                    .join(UploadSettingModel)  # Join favorite -> tweet
                    .join(AccountModel))   # Join tweet -> user        
            print('========show with join========')

            for fav in query:
                print(fav.video,fav.setting)

            if video_title is not None :
                print('ding ding video title')
                query=query.switch(TaskModel)  # <-- switch the "query context" back to ticket.

                query = (query
                # .join(YoutubeVideoModel,on=(TaskModel.video_id == YoutubeVideoModel.id))
                # .where(YoutubeVideoModel.video_title.regexp(video_title))
                .where(YoutubeVideoModel.video_title==video_title)

                )
                query=query.switch(TaskModel)  # <-- switch the "query context" back to ticket.

            print('1')

            if video_id is not None:
                query = query.join(YoutubeVideoModel,on=(TaskModel.video == YoutubeVideoModel.id)).where(YoutubeVideoModel.youtube_video_id == video_id)
                query=query.switch(TaskModel)  # <-- switch the "query context" back to ticket.

            print('3')        
            # 如果存在account 相关的查询参数,先找到对应的 setting id集合
            if username is not None:
                query = query.join(UploadSettingModel,on=(TaskModel.setting == UploadSettingModel.id)).join(AccountModel,on=(UploadSettingModel.account == AccountModel.id)).where(AccountModel.username.regexp(username))

                query=query.switch(TaskModel)  # <-- switch the "query context" back to ticket.
            print('2')

            try:
                result = list(query)
                for i in result:
                    for att in dir(i):
                        print('======show attr=========')
                        print(att,getattr(i,att))
                    print('----------',i.video)
                    print('----------',i.setting)

            except cls.DoesNotExist:
                result = None  # Set a default value or perform any other action

            return result

db.create_tables([AccountModel,UploadSettingModel,YoutubeVideoModel,TaskModel])

test_accounts=[]
for i in range(1,5):

        account=AccountModel.create(platform=  random.choice([0,1,2,3]),   username='y1',password='p1'
        )
        test_accounts.append(account)
print('111',test_accounts)

test_settings=[]
for i in range(1,5):
        print('idnex',i)
        setting=UploadSettingModel.create(id=i,timeout=5,account=random.choice(test_accounts))

        test_settings.append(setting)

print('222',test_settings)

test_videos=[]
for i in range(1,10):
        video=YoutubeVideoModel(id=i,video_title='test title'+str(random.choice(range(1,100))))
        test_videos.append(video)

print('333',test_videos)

tasks=[]

for i in range(1,5):

        t = TaskModel.create(id=i,status=1,video=random.choice(test_videos),setting=random.choice(test_settings))
        tasks.append(t)
print('444',tasks)
TaskModel.filter_tasks2( status=None, type=None,uploaded_at=None,setting=None,inserted_at=None,video_title=None,video_id=None,username=None)
TaskModel.filter_tasks2( status=None, type=None,uploaded_at=None,setting=None,inserted_at=None,video_title='test',video_id=None,username=None)

you will see show att works but show fks falied

coleifer commented 1 year ago

That code does not work either, it dies on the following line:

t = TaskModel.create(id=i,status=1,video=random.choice(test_videos),setting=random.choice(test_settings))

Because you never called .create() on the YoutubeVideoModel... Bro I mean ... this is just shit.

When I finally fix your broken code and run it, I get the following output (no errors): out.txt.

wanghaisheng commented 1 year ago

I am sorry for this trouble