Django бірегей, null және бос CharField әкімші бетінде 'бар-жоғын' келтіреді

Мен бұрын-соңды болмаған қателікті алып жүрдім. Менде Адам моделі бар

class Person(models.Model):
    user = models.OneToOneField(User, primary_key=True)
    facebook_id = models.CharField(max_length=225, unique=True, null=True, blank=True)
    twitter_id = models.CharField(max_length=225, unique=True, null=True, blank=True)
    suggested_person = models.BooleanField(default=False)

Мен жақында twitter_id өрісін қосқан болатынмын. Мен Django әкімшісі бетіне кіргенде және ұсынылған адамға «адам» дегенді өзгертуге тырыстым, келесі қатені көремін:

 Person with this Twitter id already exists.

Мен бұл қателікті өте қызық деп санаймын, себебі Facebook_id өрісі Twitter_id өрісі сияқты дәл осындай жолмен жасалған.

Мұның себебі неде?

5

7 жауаптар

Бұл ескі нәрсе, бірақ қазір менде осындай мәселе болған, алайда мен балама шешімді ұсынатын едім.

Мен CharField-ді null = True, blank = True және бірегей = True-мен иемдену керек болатын жағдайды. Егер бос жолды әкімші тақтасына жіберсем, бос жол бірегей емес, себебі ол жіберілмейді.

Мұны түзету үшін мен ModelForm ішіндегі 'таза' функцияны қайта анықтай аламын, сонда ол бос жолдың бар-жоғын тексеріп, нәтижені бірдей қайтарады.

class MyModelChangeForm(forms.ModelForm):

    class Meta:
        model = models.MyModel
        fields = ['email', 'name', 'something_unique_or_null',]

    def clean_something_unique_or_null(self):
        if self.cleaned_data['something_unique_or_null'] == "":
            return None
        else:
            return self.cleaned_data['something_unique_or_null']

Бұл модель өрісіндегі бірегей атрибутты құрбандыққа берместен, мен үшін проблеманы шешті.

Бұл көмектеседі деп үміттенемін.

EDIT: Өзіңіздің өрісіңіздің атына «something_unique_or_null» деп қойған жерімді өзгерту керек. Мысалы, «clean_twitter_id».

16
қосылды
Бұл керемет, бірақ тек белгілі бір нысан үшін. Ең жақсы шешім @shacker-ден төмен, себебі ол модельге тікелей қолданылады (барлық нысандарға, API-лерге және т.б.).
қосылды автор François Constant, көзі

Жауаптардың ешқайсысы мәселенің түп-тамырын анық сипаттайды.

Әдетте db ішінде NULL! = NULL деген null = True, unique = True өрісін жасауға болады. Сондықтан әрбір бос мән бұрынғыдай бірегей болып саналады.

Өкінішке орай, CharField үшін Django бос жолды сақтайды «» (өйткені, сіз нысанды жібергенде Django жолдар ретінде келеді және сіз шынымен бос жол «» - Django None түрлендіру керек пе білмейді)

Бұл негізінен Django-де CharField (бірегей = True, null = True, blank = True) қолдануға болмайды. Өзгелердің айтуынша, db-деңгейдегі ерекше шектеулерден бас тартуға тура келеді және модельде өзіңіздің жеке тексерулеріңізді жасаңыз.

Қосымша ақпаратты мына жерден қараңыз: https://code.djangoproject.com/ticket/4136 < br> (өкінішке орай, жазу кезінде шешілмеген жақсы шешімдер жоқ)

10
қосылды
бәрі дұрыс, жаңартылады
қосылды автор Anentropic, көзі
Python бағдарламасында None == None .
қосылды автор Vlad V, көзі
Билет 4136 енді бекітілді. Django 1.11 + -те None деген бос мәндерді қолмен алмастырусыз CharField (бірегей = True, null = True, blank = True) қолдануға болады.
қосылды автор Alasdair, көзі

Django 1.11-де CharFields нысаны None функциясын пайдалануға мүмкіндік беретін empty_value дәлелін пайдаланыңыз.

Үлгі формалары, соның ішінде Django әкімшісі, автоматты түрде CharField үлгісінің null = True болса, бос_мөлшер = Жоқ .

CharField үлгісінде бірге null = True , blank = True және unique = True кодты> проблемаларды тудыратын бірегей шектеулер жоқ.

7
қосылды

Деректерді API деңгейінде, импорттау сценарийлері арқылы қабықтан және т.б. енгізу арқылы формула деңгейінде емес, модельдік деңгейде шешу өте маңызды. CharField-дегі null = True параметрінің төмендеуі баған бос жолдар мен NULL-лермен аяқталуы мүмкін, бұл біршама анық емес, бірақ менің тәжірибемдегі жалпы проблема емес. Егер сіз осы белгісіздікпен өмір сүруге дайын болсаңыз, онда оны бірнеше қадаммен қалай жасау керек:

1) Өрістегі null = True, blank = True параметрін орнатыңыз және өзгерістерге көшіңіз.

2) Барлық бос жолдар NULL-ке ауысатын етіп деректеріңізді уқалаңыз:

items = Foo.objects.all()
for item in items:
  if not item.somefield:
    item.somefield = None
    item.save()

3) үлгіге save() әдісін қосыңыз:

def save(self, *args, **kwargs):
    # Empty strings are not unique, but we can save multiple NULLs
    if not self.somefield:
        self.somefield = None

    super().save(*args, **kwargs)  # Python3-style super()

4) Өрістегі unique = True параметрін орнатыңыз да, оны сол жерден тасымалдаңыз.

Енді сіз әкімші немесе басқа деректерді енгізу әдісін пайдаланып жатсаңыз, somefield -ды бос немесе бірегей мән ретінде сақтай аласыз.

Егер сіз бірнеше қоныс аудармауды қаламасаңыз, мұнда бір миграцияда мұны қалай жасауға болады:

# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models

def set_nulls(apps, schema_editor):
    Event = apps.get_model("events", "Event")
    events = Event.objects.all()
    for e in events:
        if not e.wdid:
            e.wdid = None
            e.save()


class Migration(migrations.Migration):

    dependencies = [
        ('events', '0008_something'),
    ]

    operations = [
        migrations.AlterField(
            model_name='event',
            name='wdid',
            field=models.CharField(blank=True, max_length=32, null=True),
        ),
        migrations.RunPython(set_nulls),
        migrations.AlterField(
            model_name='event',
            name='wdid',
            field=models.CharField(blank=True, max_length=32, null=True, unique=True),
        ),
    ]
4
қосылды
Мен оны өзгертуге болмайды: егер self.somefield болмаса және self.somefield.strip() == '' ештеңе өзгерген кезде жарамсыздығын болдырмау үшін.
қосылды автор lapin, көзі

Проблеманың тамыры Django бос мәнді бос жол ретінде емес, нөлге дейін сақтап қалады. Мұны түзету үшін, CharField-ты төмендегідей қосуға болады:

class CharNullField(models.CharField):
    description = "CharField that stores NULL"

    def get_db_prep_value(self, value, connection=None, prepared=False):
        value = super(CharNullField, self).get_db_prep_value(value, connection, prepared)
        if value=="":
            return None
        else:
            return value

Сондықтан get_db_prep_value нөлдік сақталуын қамтамасыз етеді

4
қосылды

null = True, бос = True және unique = True болғандықтан, django None немесе бірегей жазба ретінде бос. Бірегей шектеулерді алып тастап, кодтағы бірегейлікті бөлігін өңдеу.

1
қосылды
Мен Twitter_id өрісін жойып, оны оңтүстікке қосып қостық. Енді маған ешқандай мәселе берместен жақсы жұмыс істейді
қосылды автор noahandthewhale, көзі
Django бос өрісті '' бос жол ретінде өңдейді және unique = True бірнеше кодты '' мәнімен бірге енгізуге рұқсат бермейді. Алайда twitter_id = Жоқ деген бірнеше жазбаға рұқсат бермек.
қосылды автор Alasdair, көзі

Сіз бос мәндерді қабылдайсыз және оларды бірегей деп күтесіз. бұл дегеніміз тек twitter_id-ті тек ONE жазбасы болуы мүмкін

сен істей аласың

  • бірегей қарама-қайшыны алып тастаңыз
  • бос = True
  • алып тастаңыз
  • өріс үшін әдепкі мән беріңіз (бірақ әдепкі бірегей болу керек)
1
қосылды
Әдепкі мән жұмыс істемейді. Тағы бір мәселе. Сондай-ақ, бос орынды жою мәселені тудырады
қосылды автор karthikr, көзі
иә, бірегей шектеулер. бірақ әдепкі мән функциядан немесе бір нәрседен келуі мүмкін.
қосылды автор user2404546, көзі