【问题标题】:Insert queryset results into ManytoManyfield将查询集结果插入多对多字段
【发布时间】:2012-08-14 03:07:44
【问题描述】:

我有一个如下所示的 models.py 文件:

from django.db import models
from common.models import Record
from tinymce import models as tinymce_models

# Create your models here.
class Address(Record):
    def __unicode__(self):
        return unicode(self.ip)

    ip = models.IPAddressField(unique=True)
    notes = models.TextField(blank=True)

    class Meta:
        verbose_name_plural = "Addresses"

class Servers(models.Model):
    def __unicode__(self):
        return unicode(self.server_name)

    server_name = models.CharField(max_length=100)
    ip_address = models.ForeignKey(Address)
    secondary_ips = models.ManyToManyField(Address, verbose_name = 'Secondary IPs', blank=True, related_name='secondary_ips')

    class Meta:
        verbose_name_plural = "Servers"

我有系统中的 IP 和服务器列表。我试图让 ManytoManyField 仅显示当前未与服务器关联的 IP 列表。

我有以下查询集:

inner_qs = Servers.objects.values_list('ip_address_id', flat=True)
entries = Address.objects.exclude(id__in=inner_qs)

它只返回不在服务器表中的 IP 地址。我不知道如何将这些结果合并到我的 ManytoManyField 以及我应该放置查询集的位置。我目前只有进入django Shell才能得到结果

任何想法,

谢谢

【问题讨论】:

  • 你想对没有连接到服务器的 ip 做什么?
  • 我正在尝试让这些 IP 显示在我的 admin.py 文件中的 filter_horizo​​ntal = ('secondary_ips',) 中。这些应该是我可以选择的唯一IP。相反,它会列出我的地址表中的所有 IP 地址。

标签: django


【解决方案1】:

如果您想将查询集添加到多对多字段,请先将其更改为列表并使用 * 将其添加为位置参数

例子

# Returns a queryset
permissions = Permission.objects.all()

# Add the results to the many to many field (notice the *)

group = MyGroup.objects.get(name='test')

group.permissions.add(*permissions)

【讨论】:

  • 两个查询而不是一个:(
  • @DylanYoung 如果你有办法通过一个查询来做到这一点,请分享
  • 其实我错了;这是三个查询。假设您知道组 pk,这样的事情一分为二: ThroughModel = MyGroup.permissions.through; ThroughModel.objects.bulk_create(ThroughModel(permission=permission_id, mygroup=group_pk) for permission_id in Permission.objects.all())
  • 有点繁琐的模式。我的评论更多地是关于 Django ORM,而不是您的回答 :) 仍在为单一查询解决方案而苦苦挣扎。
【解决方案2】:

返回一个查询集

permissions = Permission.objects.all()

将结果添加到多对多字段(注意*

group = MyGroup.objects.get(name='test')
group.permissions.add(*permissions)

【讨论】:

    【解决方案3】:

    你可以在这里使用这个答案:Filter ManyToMany box in Django Admin

    简而言之,您需要创建一个扩展django.forms.ModelForm 的自定义表单。在那里,在__init__-method 中,将新选项放置到正确的小部件 (secondary_ips)。最后,将form = YourOwnForm 添加到您正在使用的ServerAdmin 类中。

    我建议在Servers-model中修改related_names

    class Servers(models.Model):
        # ...
        ip_address = models.ForeignKey(Address, related_name='server')
        secondary_ips = models.ManyToManyField(Address, verbose_name = 'Secondary IPs', \
            blank=True, related_name='servers_secondary')
    

    然后,您可以使用一个不错的查询集:

    allowed_addresses = Address.objects.filter(server=None)
    

    辅助地址

    当然,这只会过滤某些服务器中作为主 IP 的 IP。如果您还想过滤掉其他服务器中作为 secondary_ip 的 ip,事情会变得有点棘手:

    您还需要过滤servers_secondary=None。但是你不能过滤掉为当前对象(在后台编辑的服务器)选择的IP,否则那些选择的IP也会消失。

    使用Q objects 完成此操作,并从kwargs 中获取当前选定的对象。您的自定义表单的__init__-方法将如下所示:

    def __init__(self, *args, **kwargs):
        super(YourOwnForm, self).__init__(*args, **kwargs)
        instance = kwargs.get('instance')
        allowed_addresses = Address.objects \
            .filter(server=None) \
            .filter(Q(servers_secondary=None) | Q(servers_secondary=instance))
        choices = []
        for choice in allowed_addresses:
            choices.append((choice.id, choice.ip))
        w = self.fields['secondary_ips'].widget
        w.choices = choices
    

    主要地址下拉菜单

    按照同样的方法,也可以在主IP地址下拉菜单中过滤项目。当然,必须注意不要从列表中删除选定的 IP 地址。

    【讨论】:

    • 谢谢米科。我会试试看,然后告诉你会发生什么。
    • 嗨 Mikko,如果我已经通过固定装置将服务器加载到数据库中,它就可以工作。但是如果我从一个干净的数据库开始,我可以添加 IP 就好了,但是当我尝试添加服务器时,我收到以下错误:异常类型:KeyError 异常值:'instance'
    • 您好,我可以通过添加 try/except 来修复它。尝试:instance = kwargs['instance'] except: instance = None 再次感谢您的帮助。
    • 是的,你是对的。如果kwargs['instance']None,应该有一些保护。 Try/except 是一个很好的解决方案,另一个是kwargs.get('instance')。我编辑了我的答案以使用get()
    【解决方案4】:

    我来到这里是因为我有一个模型,它有一个多字段指向这个模型“CampaignsProducts”,它的 str 属性正在生成许多查询:

    之前:

    class CampaignsProducts(mdlcom.CommonStructure):
     product = models.ForeignKey(
        'products.Product',
        verbose_name=u'Producto',
        null=False, on_delete=models.CASCADE,
        related_name="%(app_label)s_%(class)s_product_set",
     )
     campaign = models.ForeignKey(
        'prices.Campaigns',
        verbose_name=u'Campaña',
        null=False, on_delete=models.CASCADE,
        related_name="%(app_label)s_%(class)s_campaign_set",
     )
     def __str__(self):
        return '{} - {}'.format(self.product.name, self.campaign.name)
    

    为了修复它,我更改了以下“str”属性

    def __str__(self):
       return str(self.id)
    

    Mikko 提供的解决方案挽救了我的生命:

    class CouponForm(forms.ModelForm):
    NO_REQUIRED = [
        'sellers', 'platforms', 'campaigns_product',
    ]
    
    class Meta:
        model = mdlpri.Coupon
        fields = '__all__'
    
    def get_campaigns_choices(self):
        qscampaigns = (
            mdlpri.CampaignsProducts.objects.all()
            .select_related("product")
            .select_related("campaign")
            .order_by("id")
        )
        choices = []
        for item in qscampaigns:
            wdescription = '{} - {}'.format(
                item.product.name, item.campaign.name
            )
            choices.append((item.id, wdescription))
    
        return choices
    
    def __init__(self, *args, **kwargs):
        super(CouponForm, self).__init__(*args, **kwargs)
        for wfield in self.NO_REQUIRED:
            self.fields[wfield].required = False
    

    个性化选择

        w = self.fields["campaigns_product"].widget
        w.choices = self.get_campaigns_choices()
    

    变更前查询(按产品):

    SELECT "products_product"."id", "products_product"."name", "products_product"."custom", "products_product"."created_at", "products_product"."updated_at", "products_product"."active", "products_product"."position", "products_product"."url", "products_product"."for_bonus_platform", "products_product"."for_cms_platform", "products_product"."for_store_platform", "products_product"."for_call_center_platform", "products_product"."for_ibk_platform", "products_product"."for_scotiabank_platform", "products_product"."for_bbva_platform", "products_product"."for_refurbished_platform" FROM "products_product" WHERE "products_product"."id" = 1
    

    修改后查询:

    SELECT "prices_campaignsproducts"."id", "prices_campaignsproducts"."date_created_at", "prices_campaignsproducts"."created_at", "prices_campaignsproducts"."updated_at", "prices_campaignsproducts"."user_id", "prices_campaignsproducts"."last_user_modified_id", "prices_campaignsproducts"."product_id", "prices_campaignsproducts"."campaign_id", "prices_campaignsproducts"."price", "prices_campaignsproducts"."is_active", "prices_campaignsproducts"."expiration_from", "prices_campaignsproducts"."expiration_to", "products_product"."id", "products_product"."name", "products_product"."custom", "products_product"."created_at", "products_product"."updated_at", "products_product"."active", "products_product"."position", "products_product"."url", "products_product"."for_bonus_platform", "products_product"."for_cms_platform", "products_product"."for_store_platform", "products_product"."for_call_center_platform", "products_product"."for_ibk_platform", "products_product"."for_scotiabank_platform", "products_product"."for_bbva_platform", "products_product"."for_refurbished_platform", "prices_campaigns"."id", "prices_campaigns"."date_created_at", "prices_campaigns"."created_at", "prices_campaigns"."updated_at", "prices_campaigns"."user_id", "prices_campaigns"."last_user_modified_id", "prices_campaigns"."name", "prices_campaigns"."is_active" FROM "prices_campaignsproducts" INNER JOIN "products_product" ON ("prices_campaignsproducts"."product_id" = "products_product"."id") INNER JOIN "prices_campaigns" ON ("prices_campaignsproducts"."campaign_id" = "prices_campaigns"."id") ORDER BY "prices_campaignsproducts"."id" ASC
    

    只是想分享我的经验。

    最好的问候,

    【讨论】:

      猜你喜欢
      • 2013-12-25
      • 2011-04-07
      • 2021-01-22
      • 2012-04-30
      • 1970-01-01
      • 1970-01-01
      • 2012-04-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多