erp 도전

레코드 복사, 반복문 추가, bulk_update 등

나도초딩 2023. 4. 26.

https://django-orm-cookbook-ko.readthedocs.io/en/latest/copy.html

 

2. 기존에 저장된 행을 복사해 새로 저장하는 방법은 무엇인가요? — Django ORM Cookbook 2.0 documentation

2. 기존에 저장된 행을 복사해 새로 저장하는 방법은 무엇인가요? 장고 ORM에는 모델 인스턴스를 복사하는 내장 메서드가 없습니다. 하지만 모든 필드의 값을 복사하여 새 인스턴스를 만들고 새

django-orm-cookbook-ko.readthedocs.io

save 와  create

save 는 조회(인스턴스 생성)후, 저장

create 는 바로 만들어.

레코드 복사

장고 ORM에는 모델 인스턴스를 복사하는 내장 메서드가 없습니다. 하지만 모든 필드의 값을 복사하여 새 인스턴스를 만들고 새로 저장하는 것은 어렵지 않습니다.

모델 인스턴스를 저장할 때, pk 필드 값이 None 으로 지정되어 있으면 데이터베이스에 새 행으로 저장됩니다. pk 외의 모든 필드 값은 그대로 복제됩니다.

In [2]: Hero.objects.all().count()
Out[2]: 4

In [3]: hero = Hero.objects.first()

In [4]: hero.pk = None

In [5]: hero.save()

In [6]: Hero.objects.all().count()
Out[6]: 5

반복문으로 처리

요런 느낌?

for object in (Iti.objects.all()):
       object.tour_item_id = 포린키값 
       object.save()

for index, objet in enumerate(BibleKorhrv.objects.all()):
       object.fake_id = index + 1 
       object.save()레코드 신규

## bulk_create

>>> Category.objects.all().count()
2
>>> Category.objects.bulk_create(
    [Category(name="God"),
     Category(name="Demi God"),
     Category(name="Mortal")]
)
[<Category: God>, <Category: Demi God>, <Category: Mortal>]
>>> Category.objects.all().count()
5

 

이미 생성된 object들을 동일하게 복사해 생성시켜야 할 때가 있습니다.

Django 공식 문서를 참고해서 해결 해 보겠습니다.


가장 기본적인 방법은, 해당 object의 pk를 None으로 설정하는 방법입니다.

blog = Blog(name='My blog', tagline='Blogging is easy')
blog.save() # blog.pk == 1

blog.pk = None
blog.save() # blog.pk == 2

해당 pk가 None으로 설정된 instance는 DB에 새로운 레코드로 생성되며, pk를 제외한 나머지 모든 필드는 기존의 값이 복사됩니다.

 


이번에는 상속된 model을 clone하는 방법입니다.

class ThemeBlog(Blog):
    theme = models.CharField(max_length=200)

django_blog = ThemeBlog(name='Django', tagline='Django is easy', theme='python')
django_blog.save() # django_blog.pk == 3
django_blog.pk = None
django_blog.id = None
django_blog.save() # django_blog.pk == 4

pk와 함께 id 또한 None으로 설정해야 합니다.

 

 


단, 위와 같은 방법은 DB table에 존재하지 않는, relation들은 복사하지 않습니다.

Entry가 ManyToManyField로 Author를 가지고 있다고 해 봅시다.

entry = Entry.objects.all()[0] # some previous entry
old_authors = entry.authors.all()
entry.pk = None
entry.save()
entry.authors.set(old_authors)

위와 같이 이전의 author들을 명시적으로 복사해 주는 구문이 필요하게 됩니다.

 

 

OneToOneField일 경우, one-to-one unique constraint를 피하기 위해 연관된 객체를 복제해서 대입해 주어야 합니다.

detail = EntryDetail.objects.all()[0]
detail.pk = None
detail.entry = entry
detail.save()

entry를 미리 복제한 후, 위처럼 대입해 주면 됩니다.

 


instancesdocs.djangoproject.com/en/3.1/topics/db/queries/#copying-model-instances

 

Making queries | Django documentation | Django

Django The web framework for perfectionists with deadlines. Overview Download Documentation News Community Code Issues About ♥ Donate

docs.djangoproject.com

update_or_create는 장고에서 제공하는 메서드로 get_or_create와 비슷하게 작동한다.
객체가 이미 존재하는 경우 update 하고 없는 경우 create하는 것이다.
get_or_create와 마찬가지로 (object, created) 튜플을 반환한다.
object는 update되거나 create되는 객체이고 created는 boolean으로 객체가 create되면 True, 이미 있다면 False로 반환된다.
경쟁조건을 피하기 위해 get_or_create와 마찬가지로 defaults 파라미터를 활용할 수 있다.

defaults = {'first_name': 'Bob'}
try:
    obj = Person.objects.get(first_name='John', last_name='Lennon')
    for key, value in defaults.items():
        setattr(obj, key, value)
    obj.save()
except Person.DoesNotExist:
    new_values = {'first_name': 'John', 'last_name': 'Lennon'}
    new_values.update(defaults)
    obj = Person(**new_values)
    obj.save()

# 위 코드와 같은 결과가 나오는 update_or_create
obj, created = Person.objects.update_or_create(
    first_name='John', last_name='Lennon',
    defaults={'first_name': 'Bob'},
)

출처: https://docs.djangoproject.com/en/4.0/ref/models/querysets/#update-or-create

 

Django

The web framework for perfectionists with deadlines.

docs.djangoproject.com

 

bulk_update

from django.db import models

class Person(models.Model):
    username = models.CharField(max_length = 200, unique = True)
    firstName = models.CharField(max_length = 200)
    middleName = models.CharField(max_length = 200)
    lastName = models.CharField(max_length = 200)
    age = models.IntegerField(default = 0)
people = Person.objects.all()

for person in people:
    person.age += 1

Person.objects.bulk_update(people, update_fields = ['age']) 

bulk update는 인자값으로 fields 지정 필수.

Person.objects.save(people) 하면 오래걸린다 머 그거지.

 

bulk_update()메소드를 사용하여 인스턴스의 기본 키를 업데이트 할 수 없습니다.

다.

아래 코드에서 some_models =[] 에는 필드값이 업데이트된 Some_Model의 QuerySet 객체가 들어있다고 보면 된다.

 

Some_Model.objects.bulk_update(
    some_models,
    batch_size=3000,
    fields=["status", "result"],
)

댓글