0

I want to do a query on the django User table like this:

u = User.objects.filter(member__in = member_list)

where:

class Member(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    dob = models.DateField('Date of Birth', blank=True, null=True)

and member_list is a list of eligible members.

The query works fine but the problem is I do not actually know the model member is called member. It could be called anything.

I store the name of the model I want in a model called Category. I have a link to the name of the model through content_type.Category is defined as:

class Category(models.Model):
    name = models.CharField('Category', max_length=30)
    content_type = models.ForeignKey(ContentType)
    filter_condition = JSONField(default="{}", help_text=_(u"Django ORM compatible lookup kwargs which are used to get the list of objects."))
    user_link = models.CharField(_(u"Link to User table"), max_length=64, help_text=_(u"Name of the model field which links to the User table.  'No-link' means this is the User table."), default="No-link")

    def clean (self):
        if self.user_link == "No-link":
            if self.content_type.app_label == "auth" and self.content_type.model == "user":
                pass
            else:
                raise ValidationError(
                    _("Must specify the field that links to the user table.")
                    )
        else:
            if not hasattr(apps.get_model(self.content_type.app_label, self.content_type.model), self.user_link):
                raise ValidationError(
                    _("Must specify the field that links to the user table.")
                    )            

    def __unicode__(self):
        return self.name

    def _get_user_filter (self):
        return str(self.content_type.app_label)+'.'+str(self.content_type.model)+'.'+str(self.user_link)+'__in'

    def _get_filter(self):
        # simplejson likes to put unicode objects as dictionary keys
        # but keyword arguments must be str type
        fc = {}
        for k,v in self.filter_condition.iteritems():
            fc.update({str(k): v})
        return fc

    def object_list(self):
        return self.content_type.model_class()._default_manager.filter(**self._get_filter())

    def object_count(self):
        return self.object_list().count()

    class Meta:
        verbose_name = _("Category")
        verbose_name_plural = _("Categories")
        ordering = ('name',)

So I can retrieve the name of the model that links to User but I then need to convert it into a class which I can include in a query.

I can create an object x = category.content_type.model_class() which gives me <class 'cltc.models.Member'> but when I them perform a query s = User.objects.filter(x = c.category.object_list()) I get the error Cannot resolve keyword 'x' into field.

Any thoughts most welcome.

HenryM
  • 5,557
  • 7
  • 49
  • 105

1 Answers1

2

The left hand side of the filter argument is a keyword, not a python object, so x is treated as 'x', and Django expects a field called x.

To get around this, you can ensure that x is a string, and then use the python **kwarg syntax:

s = User.objects.filter(**{x: c.category.object_list()})

Thanks to https://stackoverflow.com/a/4720109/823020 for this.

Community
  • 1
  • 1
nimasmi
  • 3,978
  • 1
  • 25
  • 41