0

For people from the future. I have scrapped tastypie and had success using Django-Rest-Framework and itertools as was suggested in the approved answer to this question.

I have a 2 models I want to link the results on as they're associated by a FK.

I've made the class in my API.py as follows -

class JobmstResource(ModelResource):
    jobdtl_id = fields.ForeignKey(JobdtlResource, 'jobdtl_id')
    class Meta:
        jobdtlquery = Jobdtl.objects.using('Admiral').all()
        jobmstquery = Jobmst.objects.using('Admiral').all()
        queryset = chain(jobdtlquery, jobmstquery)
        resource_name = 'Jobmst'

I then hit my api from the URL calling an ID (common ID in both queries).

http://localhost:8080/api/jobmst/3296/?format=xml

When I run it it fails complaining about -

'itertools.chain' object has no attribute 'model'

It seems django has no clean and clear way to do inner joins when you want results from more than 1 model so curious where the break is? Should I be attacking this differently.

If I view the query from a simple HTML it is displaying the results but does separate the values into the 2 models fields and all.

I want the values to display as if from 1 model.

Here is the models.py for the 2 models in question -

class Jobdtl(models.Model):
    jobdtl_id = models.IntegerField(primary_key=True)
    jobdtl_cmd = models.TextField(blank=True)
    jobdtl_envfile = models.TextField(blank=True)
    jobdtl_retnsn = models.SmallIntegerField(blank=True, null=True)
    jobdtl_allowadhoc = models.CharField(max_length=1, blank=True)
    jobdtl_waitop = models.CharField(max_length=1, blank=True)
    jobdtl_fromdt = models.DateTimeField(blank=True, null=True)
    jobdtl_untildt = models.DateTimeField(blank=True, null=True)
    jobdtl_fromtm = models.DateTimeField(blank=True, null=True)
    jobdtl_untiltm = models.DateTimeField(blank=True, null=True)
    jobdtl_proxy = models.ForeignKey('Usrmst', db_column='jobdtl_proxy', related_name='Jobdtl_jobdtl_proxy',blank=True, null=True)
    jobdtl_proxy2 = models.ForeignKey('Usrmst', db_column='jobdtl_proxy2', related_name='Jobdtl_jobdtl_proxy2',blank=True, null=True)
    jobdtl_interval = models.SmallIntegerField(blank=True, null=True)
    jobdtl_intervalcnt = models.SmallIntegerField(blank=True, null=True)
    jobdtl_unit = models.CharField(max_length=1, blank=True)
    jobdtl_duration = models.IntegerField(blank=True, null=True)
    jobdtl_concur = models.SmallIntegerField(blank=True, null=True)
    jobdtl_priority = models.SmallIntegerField(blank=True, null=True)
    jobdtl_minrun = models.IntegerField(blank=True, null=True)
    jobdtl_maxrun = models.IntegerField(blank=True, null=True)
    jobdtl_failalarm = models.CharField(max_length=1, blank=True)
    nodmst_id = models.ForeignKey('Nodmst', db_column='Nodmst_id', related_name='Jobdtl_Nodmst_id', blank=True, null=True)
    nodlstmst_id = models.ForeignKey('Nodlstms', db_column='Nodlstmst_id', related_name='Jobdtl_Nodlstmst_id',blank=True, null=True)
    jobdtl_inhevent = models.CharField(max_length=1, blank=True)
    jobdtl_inhoptions = models.CharField(max_length=1, blank=True)
    jobdtl_inhagent = models.CharField(max_length=1, blank=True)
    jobdtl_inhrepeat = models.CharField(max_length=1, blank=True)
    jobdtl_inhtime = models.CharField(max_length=1, blank=True)
    jobdtl_timewin = models.SmallIntegerField(blank=True, null=True)
    jobdtl_saveoutput = models.CharField(max_length=1, blank=True)
    jobdtl_outputname = models.TextField(blank=True)
    jobdtl_trackmethod = models.SmallIntegerField(blank=True, null=True)
    jobdtl_trackcmd = models.TextField(blank=True)
    jobdtl_deplogic = models.SmallIntegerField(blank=True, null=True)
    jobdtl_rerun = models.CharField(max_length=1, blank=True)
    jobdtl_params = models.TextField(blank=True) # This field type is a guess.
    jobdtl_sapcount = models.IntegerField(blank=True, null=True)
    jobdtl_normalexit = models.SmallIntegerField(blank=True, null=True)
    jobdtl_normalrange = models.SmallIntegerField(blank=True, null=True)
    jobdtl_normalop = models.SmallIntegerField(blank=True, null=True)
    jobdtl_deprerun = models.CharField(max_length=1, blank=True)
    jobdtl_carryover = models.SmallIntegerField(blank=True, null=True)
    jobdtl_psjob = models.IntegerField(blank=True, null=True)
    jobdtl_savelogonly = models.CharField(max_length=1, blank=True)
    jobdtl_trxid = models.IntegerField(blank=True, null=True)
    jobdtl_rerunok = models.CharField(max_length=1, blank=True)
    jobdtl_workdir = models.TextField(blank=True)
    jobdtl_extinfo = models.TextField(blank=True) # This field type is a guess.
    servicemst_id = models.ForeignKey('Servicemst', db_column='Servicemst_id', blank=True, null=True)
    jobdtl_estmethod = models.SmallIntegerField(blank=True, null=True)
    jobdtl_nearoutage = models.SmallIntegerField(blank=True, null=True)
    jobdtl_trackcl = models.CharField(max_length=1, blank=True)
    jobdtl_statuscl = models.CharField(max_length=1, blank=True)
    jobdtl_abrtonclderr = models.CharField(max_length=1, blank=True)
    jobdtl_estdurexclude = models.IntegerField(blank=True, null=True)
    class Meta:
        managed = False
        db_table = 'jobdtl'

class Jobmst(models.Model):
    jobmst_id = models.IntegerField(primary_key=True)
    jobmst_type = models.SmallIntegerField()
    jobmst_prntid = TreeForeignKey('self', null=True, blank=True, related_name='children', db_column='jobmst_prntid')
    jobmst_active = models.CharField(max_length=1, blank=True)
    evntmst_id = models.IntegerField(blank=True, null=True)
    jobmst_evntoffset = models.SmallIntegerField(blank=True, null=True)
    jobmst_name = models.TextField(db_column='jobmst_name', blank=True)
    jobmst_mode = models.SmallIntegerField(blank=True, null=True)
    jobmst_owner = models.ForeignKey('Owner', db_column='jobmst_owner', related_name = 'Jobmst_Jobmst_owner', blank=True, null=True)
    jobmst_desc = models.TextField(blank=True) # This field type is a guess.
    jobmst_crttm = models.DateTimeField()
    jobdtl_id = models.ForeignKey('Jobdtl', db_column='jobdtl_id', blank=True, null=True)
    jobmst_lstchgtm = models.DateTimeField(blank=True, null=True)
    jobmst_runbook = models.TextField(blank=True) # This field type is a guess.
    jobcls_id = models.IntegerField(blank=True, null=True)
    jobmst_prntname = models.TextField(blank=True)
    jobmst_alias = models.CharField(max_length=10, blank=True)
    jobmst_dirty = models.CharField(max_length=1, blank=True)
    class MPTTMeta:
        order_insertion_by = ['jobmst_id']
    class Meta:
        managed = True
        db_table = 'jobmst'
whoisearth
  • 4,080
  • 13
  • 62
  • 130
  • 2 things : Try `itertools.chain.from_iterable([jobdtlquery, jobmstquery])` If this does not work, can you update the question with the entire stacktrace ? – karthikr Dec 17 '13 at 19:23
  • doing your suggestion gives - name 'itertools' is not defined so I added "import itertools" at the beginning of the api.py and error now comes up as 'itertools chain' object has no attribute 'model'. as for the stacktrace still trying to figure out how to enable it in tastypie as all I get in the shell is the api calls. – whoisearth Dec 17 '13 at 19:30

2 Answers2

1

Have you tried converting itertools.chain to a list:

queryset = list(chain(jobdtlquery, jobmstquery))

Update You can concatenate the queries on the same model like this:

queryset = query1 | query2

Update As the error message implies, your queryset has to have only one model. You cannot achieve your goal with two different models.

This question seems like a dublicate.

Community
  • 1
  • 1
niekas
  • 8,187
  • 7
  • 40
  • 58
  • I have updated the answer, have you tried concatenating the querysets with ``|`` operator? – niekas Dec 17 '13 at 19:02
  • "cannot combine queries on two different base models" – whoisearth Dec 17 '13 at 19:03
  • Yup, you are right. Its impossible to combine querysets on different models. – niekas Dec 17 '13 at 19:11
  • yup. the chain works fine but as it displays it separates the models which I'm assuming is what causes tastypie to not like the response. It's looking for 1 model in it's return. Is it possible to do a queryset where the results return like they're from 1 model? Maybe a 3rd model in the models.py that actually references the 2 separate models? – whoisearth Dec 17 '13 at 19:23
  • Never tried it, but here is [model inheritance documentation](https://docs.djangoproject.com/en/dev/topics/db/models/#model-inheritance) – niekas Dec 17 '13 at 19:27
  • I'm going to give model inheritance a go. I think I understand where it's coming from. – whoisearth Dec 17 '13 at 19:33
  • If I understand correctly: if your inherited models have different fields (SQL table columns), you cannot create a single queryset for them several of them. Anyway, you can try it. – niekas Dec 17 '13 at 19:38
  • there is a PK/FK relationship between the two models (updated to include my models.py) – whoisearth Dec 17 '13 at 19:40
  • This did end up being the correct answer but tastypie was not the correct solution for me. Using django-rest-framework and itertools and having 100% success thus far. – whoisearth Dec 19 '13 at 15:18
0

Because a ResourceModel is made to allow a REST client to make queries that filter, paginate and sort, which then trigger the appropriate SQL query, it's not possible to just use an iterator which cannot be as flexible.

Maybe you can hack something that works but looks like the cleanest stuff is to use a plain Resource and add your own logic. See this answer Tastypie: How can I fill the resource without database? which refers to Resource VS ModelResource in the documentation http://django-tastypie.readthedocs.org/en/latest/resources.html#why-resource-vs-modelresource

Community
  • 1
  • 1
vincent
  • 6,368
  • 3
  • 25
  • 23