text: import copy
  from urllib.parse import urlsplit, urlunsplit
  
  from django.http import QueryDict
  from django.urls import reverse
  
  
  class URL:
      def __init__(
          self, url=None, netloc=None, path=None, port=None, query_string=None,
          query=None, scheme=None, viewname=None
      ):
          if path and viewname:
              raise RuntimeError(
                  'The arguments `path` and `viewname` are mutually exclusive.'
              )
  
          if viewname:
              path = reverse(viewname=viewname)
  
          # `url` argument defaults to '' to force urlsplit to return empty
          # strings and not bytes.
          self._split_result = urlsplit(url=url or '')
  
          self._netloc = netloc
          self._path = path
          self._port = port
          self._scheme = scheme
  
          self.query_dict = QueryDict(mutable=True)
  
          self.query_dict.update(
              QueryDict(query_string=self._split_result.query)
          )
  
          query_string = query_string or ''
  
          self.query_dict.update(
              QueryDict(query_string=query_string.encode('utf-8'))
          )
  
          query = query or {}
  
          for key, value in query.items():
              # Strings are iterables so tests for them explicitly.
              if isinstance(value, str):
                  self.query_dict[key] = value
              else:
                  try:
                      # Iterables other than strings.
                      result = []
                      for item in value:
                          result.append(item)
  
                      self.query_dict.setlist(key=key, list_=result)
                  except TypeError:
                      # Value is not iterable, add as is.
                      self.query_dict[key] = value
  
      @property
      def args(self):
          return self.query_dict
  
      def to_string(self):
          if self.query_dict.keys():
              query_string = self.query_dict.urlencode()
          else:
              query_string = ''
  
          split_result = copy.copy(self._split_result)
  
          if self._scheme:
              split_result = split_result._replace(scheme=self._scheme)
  
          if self._path:
              split_result = split_result._replace(path=self._path)
  
          if not split_result.netloc and self._netloc:
              split_result = split_result._replace(netloc=self._netloc)
  
          if self._port:
              netloc_parts = split_result.netloc.split(':')
              split_result = split_result._replace(
                  netloc='{}:{}'.format(netloc_parts[0], self._port)
              )
  
          split_result = split_result._replace(query=query_string)
  
          return urlunsplit(split_result)
  