Django: values_list() multiple fields concatenated

后端 未结 3 883
予麋鹿
予麋鹿 2021-02-19 02:16

I have a Person model and I am using a django form to edit another object with a foreign key to Person. The person model has first_name an

相关标签:
3条回答
  • 2021-02-19 02:44

    It sounds like the annotate() function got more flexible in Django 1.8. You can combine two fields with a Concat expression and then annotate the queryset with that expression.

    # Tested with Django 1.9.2
    import sys
    
    import django
    from django.apps import apps
    from django.apps.config import AppConfig
    from django.conf import settings
    from django.db import connections, models, DEFAULT_DB_ALIAS
    from django.db.models.base import ModelBase
    from django.db.models.functions import Concat, Value
    
    NAME = 'udjango'
    
    
    def main():
        setup()
    
        class Person(models.Model):
            first_name = models.CharField(max_length=30)
            last_name = models.CharField(max_length=30)
    
        syncdb(Person)
    
        Person.objects.create(first_name='Jimmy', last_name='Jones')
        Person.objects.create(first_name='Bob', last_name='Brown')
    
        print(Person.objects.annotate(
            full_name=Concat('first_name',
                             Value(' '),
                             'last_name')).values_list('id', 'full_name'))
        # >>> [(1, u'Jimmy Jones'), (2, u'Bob Brown')]
    
    
    def setup():
        DB_FILE = NAME + '.db'
        with open(DB_FILE, 'w'):
            pass  # wipe the database
        settings.configure(
            DEBUG=True,
            DATABASES={
                DEFAULT_DB_ALIAS: {
                    'ENGINE': 'django.db.backends.sqlite3',
                    'NAME': DB_FILE}},
            LOGGING={'version': 1,
                     'disable_existing_loggers': False,
                     'formatters': {
                        'debug': {
                            'format': '%(asctime)s[%(levelname)s]'
                                      '%(name)s.%(funcName)s(): %(message)s',
                            'datefmt': '%Y-%m-%d %H:%M:%S'}},
                     'handlers': {
                        'console': {
                            'level': 'DEBUG',
                            'class': 'logging.StreamHandler',
                            'formatter': 'debug'}},
                     'root': {
                        'handlers': ['console'],
                        'level': 'WARN'},
                     'loggers': {
                        "django.db": {"level": "WARN"}}})
        app_config = AppConfig(NAME, sys.modules['__main__'])
        apps.populate([app_config])
        django.setup()
        original_new_func = ModelBase.__new__
    
        @staticmethod
        def patched_new(cls, name, bases, attrs):
            if 'Meta' not in attrs:
                class Meta:
                    app_label = NAME
                attrs['Meta'] = Meta
            return original_new_func(cls, name, bases, attrs)
        ModelBase.__new__ = patched_new
    
    
    def syncdb(model):
        """ Standard syncdb expects models to be in reliable locations.
    
        Based on https://github.com/django/django/blob/1.9.3
        /django/core/management/commands/migrate.py#L285
        """
        connection = connections[DEFAULT_DB_ALIAS]
        with connection.schema_editor() as editor:
            editor.create_model(model)
    
    main()
    
    0 讨论(0)
  • 2021-02-19 02:45

    I have in mind 2 sugestions for you:

    • First one is to concatenate fields in database with extra . For me is a dirty solutions but can run.

    Sample:

    persons =  GetPersons().extra(select={'full_name': "concatenate( first, last) "} )
    choices = persons.values_list('id', 'full_name')
    

    and ...

    • the second one use list comprehension:

    Sample:

    choices = [ ( p.id, '{0} {1}'.format( p.first, p.last ),) for p in GetPersons() ]
    

    Edited 2018

    Concat is now available as database function:

    >>> from django.db.models import CharField, Value as V
    >>> from django.db.models.functions import Concat
    >>> persons = GetPersons().annotate(
    ...     full_name=Concat(
    ...         'last', V(', '), 'first', V('.'),
    ...         output_field=CharField()
    ...     )
    ... )
    
    0 讨论(0)
  • 2021-02-19 03:00

    Per: Is it possible to reference a property using Django's QuerySet.values_list?, avoiding values_list when not applicable, using a comprehension instead.

    models.py:
    class Person(models.Model):
        first_name = models.CharField(max_length=32)
        last_name = models.CharField(max_length=64)
        def getPrintName(self):
            return self.last_name + ", " + self.first_name
    
    views.py:
    data.form.fields['person'].choices = [(person.id, person.getPrintName()) for person in GetPersons()]
    
    0 讨论(0)
提交回复
热议问题