Django 1.9.5:反向查找字段的FieldError偶尔

时间:2017-01-27 00:16:29

标签: django mod-wsgi apache2.4

在尝试为预取的objects.all()运行Queryset时,我在Django中遇到令人沮丧的间歇性错误。有一个问题,偶尔model._meta似乎缺少字段,在查询集的实例化和运行迭代之间。它几乎就像查询集的预取实际上没有及时运行对象列表的迭代一样。

在此示例中,data.service_log只是一个查询集,其中包含一些名为servicelog的预取项。当我在shell中运行查询集时,我可以查看查询集上self.names_to_path(lookup_splitted, self.get_meta())方法中的所有字段。他们都在那里,特别是" servicelog。"

注意这个错误的Traceback它说" servicelog"不是可用字段,但它将其列在可供选择的字段列表中。这似乎是一个Django错误,但我无法确定,因为我无法解释或隔离这种行为。我不可能是唯一得到此错误的人。它似乎位于django/db/models/sql/query.py方法的names_to_paths()中。这是未能解决的代码:

query.py names_to_paths():

field = None
try:
    field = opts.get_field(name)
except FieldDoesNotExist:
    if name in self.annotation_select:
        field = self.annotation_select[name].output_field

if field is not None:
    # Fields that contain one-to-many relations with a generic
    # model (like a GenericForeignKey) cannot generate reverse
    # relations and therefore cannot be used for reverse querying.
    if field.is_relation and not field.related_model:
        raise FieldError(
            "Field %r does not generate an automatic reverse "
            "relation and therefore cannot be used for reverse "
            "querying. If it is a GenericForeignKey, consider "
            "adding a GenericRelation." % name
        )
    try:
        model = field.model._meta.concrete_model
    except AttributeError:
        model = None
else:
    # We didn't find the current field, so move position back
    # one step.
    pos -= 1
    if pos == -1 or fail_on_missing:
        field_names = list(get_field_names_from_opts(opts))
        available = sorted(field_names + list(self.annotation_select))
        raise FieldError("Cannot resolve keyword %r into field. "
                         "Choices are: %s" % (name, ", .join(available)))
    break

field does not get set in the first try, then the condition statement如果字段不是无fails so we enter the其他block. There the pos gets reduced by one, but since this field is 'servicelog' it is already at 0. However, when I try this in the shell, it always finds the字段with opts.get_field(' servicelog') 。只有从WSGI和Apache2运行时才会发生此故障。同样,它并非始终如此,这使得测试非常困难。我对此感到困惑,不知道在哪里寻找线索。如果有人对任何探索的内容有任何想法,我会非常感激。

Traceback (most recent call last):

  File "/var/www/fast/services/views/edit.py", line 12897, in service_log
    for service in data.service_log:

  File "/usr/local/lib/python2.7/dist-packages/django/db/models/query.py", line 258, in __iter__
    self._fetch_all()

  File "/usr/local/lib/python2.7/dist-packages/django/db/models/query.py", line 1076, in _fetch_all
    self._prefetch_related_objects()

  File "/usr/local/lib/python2.7/dist-packages/django/db/models/query.py", line 656, in _prefetch_related_objects
    prefetch_related_objects(self._result_cache, self._prefetch_related_lookups)

  File "/usr/local/lib/python2.7/dist-packages/django/db/models/query.py", line 1457, in prefetch_related_objects
    obj_list, additional_lookups = prefetch_one_level(obj_list, prefetcher, lookup, level)

  File "/usr/local/lib/python2.7/dist-packages/django/db/models/query.py", line 1556, in prefetch_one_level
    prefetcher.get_prefetch_queryset(instances, lookup.get_current_queryset(level)))

  File "/usr/local/lib/python2.7/dist-packages/django/db/models/fields/related_descriptors.py", line 802, in get_prefetch_queryset
    queryset = queryset._next_is_sticky().filter(**query)

  File "/usr/local/lib/python2.7/dist-packages/django/db/models/query.py", line 790, in filter
    return self._filter_or_exclude(False, *args, **kwargs)

  File "/usr/local/lib/python2.7/dist-packages/django/db/models/query.py", line 808, in _filter_or_exclude
    clone.query.add_q(Q(*args, **kwargs))

  File "/usr/local/lib/python2.7/dist-packages/django/db/models/sql/query.py", line 1243, in add_q
    clause, _ = self._add_q(q_object, self.used_aliases)

  File "/usr/local/lib/python2.7/dist-packages/django/db/models/sql/query.py", line 1269, in _add_q
    allow_joins=allow_joins, split_subq=split_subq,

  File "/usr/local/lib/python2.7/dist-packages/django/db/models/sql/query.py", line 1149, in build_filter
    lookups, parts, reffed_expression = self.solve_lookup_type(arg)

  File "/usr/local/lib/python2.7/dist-packages/django/db/models/sql/query.py", line 1035, in solve_lookup_type
    _, field, _, lookup_parts = self.names_to_path(lookup_splitted, self.get_meta())

  File "/usr/local/lib/python2.7/dist-packages/django/db/models/sql/query.py", line 1330, in names_to_path
    "Choices are: %s" % (name, ", ".join(available)))

FieldError: Cannot resolve keyword u'servicelog' into field. Choices are: additional_county_worker_notes, adoption_disrupted, adoption_first_name, adoption_last_name, adoption_middle_name, adoption_placement_date, adoption_placement_reason, adoption_placement_reason_id, adoption_placement_type, adoption_risk_level, adoption_risk_level_id, adoption_termination_date, adoption_termination_destination, adoption_termination_reason, adoption_termination_reason_id, adoptive_placement, agency, agency_id, all_items_outstanding, all_items_past_due, appeal_process_date, attached_file, attends_college, attorney_email_address, attorney_email_address_id, attorney_fax, attorney_fax_id, attorney_investigator_email_address, attorney_investigator_email_address_id, attorney_investigator_fax, attorney_investigator_fax_id, attorney_investigator_name, attorney_investigator_phone, attorney_investigator_phone_id, attorney_name, attorney_phone, attorney_phone_id, blood_related_to_applicants, blood_relationship, casa_email_address, casa_email_address_id, casa_fax, casa_fax_id, casa_name, casa_phone, casa_phone_id, certification_items_outstanding, certification_items_past_due, classification, classification_id, client, client_id, county_adoption_worker, county_adoption_worker_cell, county_adoption_worker_cell_id, county_adoption_worker_email_address, county_adoption_worker_email_address_id, county_adoption_worker_fax, county_adoption_worker_fax_id, county_adoption_worker_office, county_adoption_worker_office_id, county_adoption_worker_phone, county_adoption_worker_phone_id, county_adoption_worker_title, county_case_number, county_worker, county_worker_cell, county_worker_cell_id, county_worker_email_address, county_worker_email_address_id, county_worker_fax, county_worker_fax_id, county_worker_office, county_worker_office_id, county_worker_phone, county_worker_phone_id, county_worker_title, court, court_case_name, court_case_number, court_department, court_id, created, current_grade, date_identified_adoptive, date_placed_with_home, deleted, discharge_summary, eligibility_worker, eligibility_worker_email_address, eligibility_worker_email_address_id, eligibility_worker_phone, eligibility_worker_phone_id, emergency_placement, employed_80_hours, enable_discharge_summary, expected_type, expected_type_id, extended_family_contact_allowed, final_payment_amount, finalization_date, foreign_placement, hearing_36626_date, homestudy, id, incident_placement_1, incident_placement_2, incident_placement_3, incident_placement_4, individualized_plan_review, inhousemove, interpretive_summary, item_due, items_approved, items_pending, items_rejected, items_update_requested, la_county_id, medi_cal, medi_cal_eligibility_phone, medi_cal_eligibility_phone_id, medi_cal_eligibility_worker, medi_cal_id, modified, monthly_monitored_visit_hours, mother_child, move_in_type, move_out_type, new_protective_custody_petition, non_minor_dependent, non_truant, notes, number_of_files_required, other_school_contact, other_school_contact_first_name, other_school_contact_last_name, parent_payment_override_annually, parent_payment_override_daily, parent_payment_override_monthly, parental_contact_allowed, parental_group, parental_group_id, payment_amount, percent_certified, percent_items_complete, person_number, placement, placement_date, placement_id, placement_payment_override_annually, placement_payment_override_daily, placement_payment_override_monthly, placement_reason, placement_reason_details, placement_reason_id, placement_self, placer_shelter_bed, prior_placement, progress_summary, projected_adoption_36626_date, projected_adoption_finalization_date, projected_adoption_placement_date, recordreview, requires_educational_support, requires_mental_health_services, respite, school, school_different, school_id, school_liaison_email, school_liaison_first_name, school_liaison_last_name, school_liaison_phone, school_liaison_phone_extension, school_notes, serial_number, servicecontact_onbehalf, servicedeliverylog, servicelog, social_worker_at_termination, social_worker_at_termination_id, special_health_care_needs, state_case_number, teachers, termination_date, termination_destination, termination_reason, termination_reason_details, termination_reason_id, therapist, therapy_code, therapy_supervision_requirements, treatment_abilities, treatment_needs, treatment_preferences, treatment_strengths, treatmentneed, update_requested, update_requested_by, update_requested_by_id, update_requested_date, update_requested_note, updateable, use_number_required, uses_psychotropic_medication, visit_frequency_override, visit_frequency_override_id, visitation_restrictions, who_can_pickup_at_home, who_can_pickup_at_school, who_can_visit

更新 - 添加模型/违规视图代码

models.py
class ParentalGroup(models.Model):
    many fields...

class Placement(models.Model):
    parental_group = models.ForeignKey(ParentalGroup, null=True, blank=True)
    many more fields...

class ServiceLog(models.Model):
    parental_group = models.ForeignKey(ParentalGroup, null=True, blank=True)
    placement = models.ManyToManyField(Placement, blank=True)
    many more fields...


views.py:
data.service_log = ServiceLog.objects.filter(
    parental_group=data.pg,
).prefetch_related(
    Prefetch(
        'placement',
        queryset=Placement.objects.all(),
        to_attr='placements'
    ),
)

for service in data.service_log:
    some code to generate data to pass to template...

return render_to_response(...)

1 个答案:

答案 0 :(得分:1)

我在Gunicorn / Django runserver上使用Django 1.8.6时遇到了类似的问题。我还没有设法在shell / notebook环境中重现错误。

我通过将related_name添加到ManyToManyField来解决随机发生的FieldError。我在ManyToManyField中使用了a through model

在你的情况下:

class ServiceLog(models.Model):
    parental_group = models.ForeignKey(ParentalGroup, null=True, blank=True)
    placement = models.ManyToManyField(Placement, blank=True, related_name='servicelog')