<commit_before>from django.template import Library, Node, Variable, TemplateSyntaxError, VariableDoesNotExist
from django.template.loader import get_template
from django.conf import settings
from django.db.models.loading import get_model
from django.db.models.fields.related import ManyToManyRel
from django.db.models import Count
from django.db.models.query import QuerySet
from django.db.models.manager import Manager
from django.template.defaultfilters import slugify
from django.utils.encoding import smart_unicode
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes.generic import GenericForeignKey

from courant.core.utils.text import split_contents
from courant.core.gettag import gettag
from courant.core.dynamic_models.models import DynamicType

from datetime import timedelta, datetime, date

register = Library()

def model_from_name(name):
    model = gettag.from_name(name)
    if not model:
        raise TemplateSyntaxError, "Invalid model provided: %s" % name
    return model

def resolve_param(value, context, func=str):
   """
   Resolves a variable passed to a template tag if it exists in the request's
   context. Otherwise applies a specified function to convert it to the desired
   object type (e.g., string or integer)
   """
   if value in context:
      return Variable(value).resolve(context)
   return func(value)

def model_relationship_field(model, fk_model):
    for field in model._meta.fields:
        if hasattr(field, 'rel') and hasattr(field.rel, 'to'):
            if field.rel.to == fk_model:
                return field.name
    for f, m in model._meta.get_all_related_m2m_objects_with_model():
        if f.model == fk_model:
            return f.get_accessor_name()
    return None

class GetNode(Node):
   def __init__(self, params, varname):
      self.params = params
      self.varname = varname
      
   def render(self, context):
      # determine desired object type
      model = model_from_name(self.params['app_model'])
      model_name = model.__name__.lower()
      
      # Base queryset to filter on
      manager = model.live if hasattr(model, 'live') and isinstance(model.live, Manager) else model.objects
      opts = gettag.from_model(model)
      if opts.get('is_dynamic', False) and self.params['app_model'] not in opts.get('non_dynamic_names', ''):
         dType = DynamicType.objects.get(pk=gettag.from_model(model).get('dynamic_map').get(self.params['app_model'], None))
         q = manager.filter(dynamic_type=dType)
      else:
         q = manager.all()
      
      # flag to mark if a value was set before reaching the end of the render
      # function because of a special case
      valueSet = False
      
      # handle with clause
      if 'with_field' in self.params:
         field = self.params['with_field']
         
         # allow custom function to handle with clause for this model type
         custom_with = gettag.from_model(model).get('with', None)
         if callable(custom_with):
            cfield = Variable(self.params['with_field']).resolve(context)

            if 'with_value' in self.params:
               cvalue = Variable(self.params['with_value']).resolve(context)
               result = custom_with(cfield, cvalue)
            else:
               result = custom_with(cfield)
            
            if isinstance(result, QuerySet):
               # if the function returned a queryset, then we can continue on
               q = result
            else:
               # otherwise just return the value
               context[self.varname] = result
               return ''
         else:
            if not field in model._meta.get_all_field_names():
               raise TemplateSyntaxError, "get tag: field '%s' does not exist on model %s" % (field, model.__name__)
            elif 'with_value' in self.params and isinstance(model._meta.get_field(field).rel, ManyToManyRel):
               raise TemplateSyntaxError, "get tag: cannot match a value to m2m field '%s' on model %s" % (field, model.__name__)
            
            filter_params = {}
            if 'with_value' in self.params:
               # can only resolve a variable value or a quoted string,
               # but users could put an unquoted string/non-variable,
               # so we catch that exception and move on
               try:
                  value = Variable(self.params['with_value']).resolve(context)
               except VariableDoesNotExist:
                  value = self.params['with_value']
                  
               filter_params[str(field)] = value
            else:
               # only return results that have matching related objects
               # pk > 0 is a hack, as annotations/aggregations are not fast enough
               # (difficult to index properly + complicated joins)
               filter_params[str("%s__pk__gt" % field)] = 0
            q = q.filter(**filter_params)
      
      # handle 'in' clause(s)
      if 'in' in self.params:
         stack = [model]<commit_msg>Changed get tag to support null-value field matches in the 'with' clause (e.g., {% get sections with parent None as top_sections %})<commit_after>from django.template import Library, Node, Variable, TemplateSyntaxError, VariableDoesNotExist
from django.template.loader import get_template
from django.conf import settings
from django.db.models.loading import get_model
from django.db.models.fields.related import ManyToManyRel
from django.db.models import Count
from django.db.models.query import QuerySet
from django.db.models.manager import Manager
from django.template.defaultfilters import slugify
from django.utils.encoding import smart_unicode
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes.generic import GenericForeignKey

from courant.core.utils.text import split_contents
from courant.core.gettag import gettag
from courant.core.dynamic_models.models import DynamicType

from datetime import timedelta, datetime, date

register = Library()

def model_from_name(name):
    model = gettag.from_name(name)
    if not model:
        raise TemplateSyntaxError, "Invalid model provided: %s" % name
    return model

def resolve_param(value, context, func=str):
   """
   Resolves a variable passed to a template tag if it exists in the request's
   context. Otherwise applies a specified function to convert it to the desired
   object type (e.g., string or integer)
   """
   if value in context:
      return Variable(value).resolve(context)
   return func(value)

def model_relationship_field(model, fk_model):
    for field in model._meta.fields:
        if hasattr(field, 'rel') and hasattr(field.rel, 'to'):
            if field.rel.to == fk_model:
                return field.name
    for f, m in model._meta.get_all_related_m2m_objects_with_model():
        if f.model == fk_model:
            return f.get_accessor_name()
    return None

class GetNode(Node):
   def __init__(self, params, varname):
      self.params = params
      self.varname = varname
      
   def render(self, context):
      # determine desired object type
      model = model_from_name(self.params['app_model'])
      model_name = model.__name__.lower()
      
      # Base queryset to filter on
      manager = model.live if hasattr(model, 'live') and isinstance(model.live, Manager) else model.objects
      opts = gettag.from_model(model)
      if opts.get('is_dynamic', False) and self.params['app_model'] not in opts.get('non_dynamic_names', ''):
         dType = DynamicType.objects.get(pk=gettag.from_model(model).get('dynamic_map').get(self.params['app_model'], None))
         q = manager.filter(dynamic_type=dType)
      else:
         q = manager.all()
      
      # flag to mark if a value was set before reaching the end of the render
      # function because of a special case
      valueSet = False
      
      # handle with clause
      if 'with_field' in self.params:
         field = self.params['with_field']
         
         # allow custom function to handle with clause for this model type
         custom_with = gettag.from_model(model).get('with', None)
         if callable(custom_with):
            cfield = Variable(self.params['with_field']).resolve(context)

            if 'with_value' in self.params:
               cvalue = Variable(self.params['with_value']).resolve(context)
               result = custom_with(cfield, cvalue)
            else:
               result = custom_with(cfield)
            
            if isinstance(result, QuerySet):
               # if the function returned a queryset, then we can continue on
               q = result
            else:
               # otherwise just return the value
               context[self.varname] = result
               return ''
         else:
            if not field in model._meta.get_all_field_names():
               raise TemplateSyntaxError, "get tag: field '%s' does not exist on model %s" % (field, model.__name__)
            elif 'with_value' in self.params and isinstance(model._meta.get_field(field).rel, ManyToManyRel):
               raise TemplateSyntaxError, "get tag: cannot match a value to m2m field '%s' on model %s" % (field, model.__name__)
            
            filter_params = {}
            if 'with_value' in self.params:
               # can only resolve a variable value or a quoted string,
               # but users could put an unquoted string/non-variable,
               # so we catch that exception and move on
               try:
                  value = Variable(self.params['with_value']).resolve(context)
               except VariableDoesNotExist:
                  value = self.params['with_value']
                  if value == 'None':
                     value = None

               filter_params[str(field)] = value
            else:
               # only return results that have matching related objects
               # pk > 0 is a hack, as annotations/aggregations are not fast enough
               # (difficult to index properly + complicated joins)
               filter_params[str("%s__pk__gt" % field)] = 0
            q = q.filter(**filter_params)
      
      # handle 'in' clause(s)
      if 'in' in self.params:
         stack = [model]
{'fraction_non_alphanumeric': 0.08418392145426266, 'fraction_numerical': 0.0007776805677068144, 'mean_word_length': 2.486275838698746, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '917591', 'n_tokens_mistral': 2764, 'n_tokens_neox': 2708, 'n_words': 878}