Django создать пользовательский идентификатор def save()

У меня есть функция postgres, которая делает следующее: когда я сохраняю элемент, она создает cl_itemid test2021-20221-1. затем в таблице clearing_office столбец office_serial увеличивается на +1, поэтому следующий сохраненный элемент будет test2021-20221-2

SELECT CONCAT(f_office_id,f_sy,f_sem,'-',office_serial) INTO office_lastnumber from curriculum.clearing_office
    where office_id=f_office_id;
    
UPDATE curriculum.clearing_office SET office_serial =office_serial+1 where office_id=f_office_id;


{
    "studid": "4321-4321",
    "office": "test",
    "sem": "1",
    "sy": "2021-2022",
}

Возможно ли создать это через модели Django или, возможно, есть альтернативное решение для этой проблемы?

Это мой класс модели

class Item(models.Model):
    cl_itemid = models.CharField(primary_key=True, max_length=20)
    studid = models.CharField(max_length=9, blank=True, null=True)
    office = models.ForeignKey('ClearingOffice', models.DO_NOTHING, blank=True, null=True)
    sem = models.CharField(max_length=1, blank=True, null=True)
    sy = models.CharField(max_length=9, blank=True, null=True)

    class Meta:
        managed = False
        db_table = 'item'

Я делаю это во многих своих моделях, но немного по-другому. Я просто использую Forms и tac на пользовательском методе сохранения
. Я не работал с неуправляемыми моделями, но из того, что я вижу в google, это не отличается

Form (forms.py)

class ItemForm(forms.ModelForm):
    class Meta:
        model = Item
        fields = (
            'cl_itemid',
            'studid',
            'office',
            'sem',
            'sy',
            )

    def __init__(self,  *args, **kwargs):
        super(ItemForm, self).__init__(*args, **kwargs)

    def save(self, commit=True):
        obj = super(ItemForm, self).save(commit=False)

        if not self.instance:
            # you only want it hitting this if it's new!
            from datetime import datetime
            now = datetime.now()

            count = Item.objects.all().count()
            # you could also just grab the last
            #   + chop the id to get the last number

            obj.cl_itemid = 'test{0}-{1}'.format(now.strftime('%Y-%m%d%y'), count)

        if commit:
            obj.save()

Возможно, вы даже сможете сделать это ДО метода сохранения super(ItemForm, self).save(commit=False) или даже сделать cl_itemid ... Я проведу некоторые тесты на своей стороне, чтобы увидеть, может ли это быть вариантом, может быть намного чище

Usage

View (POST)

def ItemFormView(request):
    from app.forms import ItemForm
    if request.method == "POST":
        # this is just for edits
        itemObj = Item.objects.get(pk=request.POST.get('itemid')) if request.POST.get('itemid') else None

        form = ItemForm(request.POST or None, instance=itemObj)
        if form.is_valid():
            obj = form.save()
            return HttpResponseRedirect(reverse('sucesspage')

        print(form.errors)
        print(form.errors.as_data())
        # this will render the page with the errors
        data = {'form': form}
    else:
        data = {'form': ItemForm()}
    return render(request, 'itemform.html', data)
<
f = ItemForm(data={'office':'test', 'sem':'1', 'etc':'etc'})
if f.is_valid():
    o = f.save()

Одним из простых способов может быть использование функции default в python.

def get_default_id():
    last_id = Item.objects.last().cl_itemid
    split_id = last_id.split('-')
    split_id[-1] = str(int(split_id[-1])+1)
    new_id = '-'.join(split_id)
    return new_id

class Item(models.Model):
    cl_itemid = models.CharField(..., default=get_default_id)

Подобный подход описан в этом ответе.

Однако при таком подходе необходимо предусмотреть возможность возникновения условий гонки при одновременном создании двух или более новых объектов (т.е. функция по умолчанию выполняется одновременно для двух новых объектов, что может привести к возврату одного и того же ID для двух новых объектов). Вы можете обойти эту потенциальную проблему с помощью транзакций или повторов, если считаете, что это будет проблемой в вашем приложении.

Надежным подходом было бы создание собственного поля модели и внутренняя обработка реализации в этом поле. Это позволит вам реализовать решение различными способами в зависимости от диалекта БД и обеспечить его работу в разных реализациях БД без проблемы состояния гонки.

Вернуться на верх