1
votes

Django reste framework, champ qui est un choix ou du texte

Existe-t-il un moyen de créer un champ qui est un champ de texte, mais avec des choix. que les choix sont les objets existants sur le terrain? Et si le mot passé n'est pas dans les données existantes, ajoutez-le?

J'ai cherché sur tout Internet un champ comme celui-ci ou un exemple de celui-ci, que ce soit dans Django ou dans le framework reste, mais je n'ai pas pu en trouver .

Mon utilisation pour cela, par exemple, serait:

class Point(models.Model):
    location_name = models.TextField(verbose_name="Location name",
                                     unique=True,
                                     # This would include the existing names.
                                     choices=,
                                     )
    latitude = models.FloatField(name="GDT1Latitude",
                                 verbose_name="GDT 1 Latitude",
                                 unique=False, max_length=255, blank=False,
                                 help_text="Enter the location's Latitude, first when extracting from Google Maps.",
                                 default=DEFAULT_VALUE)
    longitude = models.FloatField(name="GDT1Longitude",
                                  verbose_name="GDT 1 Longitude",
                                  unique=False, max_length=255, blank=False,
                                  help_text="Enter the location's Longitude, second when extracting from Google Maps.",
                                  default=DEFAULT_VALUE)

Donc, il pourrait être utilisé lors d'une demande de publication au lieu de déjà saisir la latitude , longitude Il serait extrait de l'objet existant.


1 commentaires

Jetez un œil ici


3 Réponses :


1
votes

Au niveau de la base de données, un champ ne peut pas être à la fois un champ de type "choix" et un champ de texte libre.

Ce que vous voulez réellement, c'est une abstraction au-dessus de quelques champs DB cachés

class Book(models.Model):
   THEME_CHOICES = (
     ('Horror', 'Horror'),
     ('Romance', 'Romance')
   )
   _theme = models.CharField(choices=THEME_CHOICES, max_length=258, null=True, blank=True)
   _other_theme = models.CharField(max_length=258)

   @property
   def theme(self):
      if self._other_theme:
          return self._other_theme
      else:
          return self._theme

Ceci n'est que le premier "niveau DB", mais vous devrez également personnaliser la méthode '.save ()', ajouter un setter avec @ property.setter code >.

Une autre option serait d'écrire cette abstraction au niveau Form au lieu du niveau Model .


0 commentaires

0
votes

Cela ressemble un peu à la recherche de la fonction django get_or_create . Étant donné un modèle comme Point , vous pouvez l'appeler comme;

obj, created = Point.objects.get_or_create(
    location_name ='Location',
    defaults={'latitude': 1, 'longitude': 2},
)

et il renvoie une instance obj et un booléen créé qui indique si cet objet est nouveau ou préexistant.

Par conséquent, si vous lui donnez un location_name existant, il récupérera l'objet existant pour vous, mais si vous donnez-lui un nouveau, il créera un nouvel objet avec ce nom.


0 commentaires

0
votes

En me fondant sur la logique proposée par Timothe ici, j'ai construit une sorte de contournement au problème que j'ai présenté.

Premièrement, le modèle utilisant le modèle Point comme champ de choix:

  • Le point a été renommé KnownLocation.
gdt = return_data_by_name(data=get_known_location(), query=location_name)

le champ gdt n'hérite pas directement du modèle ponctuel, afin que je puisse faire ce qui suit:

Ici, je ne peux pas montrer exactement ce que j'ai fait, mais au début, je viens d'ajouter un autre champ appelé add_gdt, qui est un champ lié au modèle de localisation connu.

Et comme Timothe l'a suggéré, si ce n'est pas le cas, choisissez le champ gdt, si aucun choix n'a été fait sur gdt, puis ajoutez le champ add_gdt à la base de données de l'emplacement connu en tant que champ connexe normal.

Sérialiseur:

def repack(data, return_type=DICT):
    """
    This function receives a list of ordered dictionaries to to unpack and reassign every dict to it's first value.
    data: the data to unpack
    return_type: specify the returned data type; dict or list.
    'dict' is default
    """
    try:
        repacked_dict = {next(iter(d.values())): d for d in data}
        if return_type is DICT:
            return repacked_dict
        elif return_type is LIST:
            repacked_list = list(repacked_dict.items())
            return repacked_list
        raise TypeError('requested return type is not valid.')
    except:
        raise TypeError('data is not a list.')




def return_data_by_name(data, query) -> list:
    """
    This function receive a nested dictionary and matches a given the query to the keys of the dictionary,
    If there's a match, than that match is returned.
    :param dict data:
    :param str query:
    """
    for name, values in data.items():
        if query.lower() in name.lower():
            values = list(values.values())
            return values

utilisez gdt ici comme champ de choix, en utilisant le paresseux de django pour créer des noms correspondant au champ du modèle de points, c'est-à-dire que le champ de choix sera composé des noms des points connus dans la base de données.

Comment s'appelle get_locations?

Utils.APIConsts.Custom.py:

def get_locations():
    """
    Returns the names of the locations in KnownLocation model.
    """
    return [loc.Name for loc in KnownLocation.objects.all()]


def get_known_location():

    qeuryset = KnownLocation.objects.all()
    serialized_data = KnownLocationSerializer(qeuryset,
                                              many=True)

    locations_data = serialized_data.data
    to_repr_dict = repack(data=locations_data, return_type='dict')
    return to_repr_dict


known_locations_data = get_known_location()

Récupère les données du qeuryset, sérialise-le, récupère les données et crée un dictionnaire exploitable à partir de celui-ci, avec les éléments suivants:

from Utils.APIConsts.Custom import get_locations, known_locations_data
from django.utils.functional import lazy
from rest_framework.fields import ChoiceField, DictField
from rest_framework.serializers import HyperlinkedModelSerializer

from .models import Mission


class MissionSerializer(HyperlinkedModelSerializer):
    gdt = ChoiceField(choices=lazy(get_locations, tuple)())
    locations = DictField(known_locations_data)

    class Meta:
        model = Mission
        fields = ('Area', 'gdt', 'MissionName', 'UavLatitude', 'UavLongitude', 'UavElevation',
                  'locations')

Enfin, les données utilisées dans la vue, en utilisant la fonction return by name pour obtenir les données.

class Mission(models.Model):
    id = models.UUIDField(primary_key=False, default=uuid.uuid4, editable=False)

    mission_name = models.CharField(name='MissionName',
                                    verbose_name="Mission Name",
                                    max_length=255,
                                    blank=False,
                                    help_text="Enter the mission's name",
                                    unique=True,
                                    primary_key=True
                                    # We want to be able to query missions not let them be confused with other missions.
                                    )

    uav_lat = models.FloatField(name="UavLatitude",
                                verbose_name="UAV Latitude",
                                unique=False, max_length=255, blank=False,
                                help_text="Enter the location's Latitude, first when extracting from Google Maps.",
                                default=DEFAULT_VALUE)

    uav_lon = models.FloatField(name="UavLongitude",
                                verbose_name="UAV Longitude",
                                unique=False, max_length=255, blank=False,
                                help_text="Enter the location's Longitude, second when extracting from Google Maps.",
                                default=DEFAULT_VALUE)


    gdt = models.CharField(verbose_name='Locations',
                           max_length=20)

p>


0 commentaires