Уведомления

Группа в Telegram: @pythonsu

#1 Дек. 3, 2012 17:22:09

SorrowFuck
От: Хабаровск
Зарегистрирован: 2012-10-10
Сообщения: 64
Репутация: +  2  -
Профиль   Отправить e-mail  

INSERT вместо UPDATE

Есть модель:

class UserAbout(models.Model):
    user = models.ForeignKey(User, related_name='UserAboutToUser', unique=True)
    about = models.TextField(max_length = 1000, blank=True, null=True, unique=False)
    family = models.TextField(max_length = 140, blank=True, null=True, unique=False)
    why = models.CharField(max_length = 140, blank=True, null=True, unique=False)
    trust = models.TextField(max_length = 140, blank=True, null=True, unique=False)
    hobby = models.CharField(max_length = 1000, blank=True, null=True, unique=False)
    job = models.TextField(max_length = 140, blank=True, null=True, unique=False)
    politic = models.CharField(max_length = 140, blank=True, null=True, unique=False)
    book = models.TextField(max_length = 140, blank=True, null=True, unique=False)
    film = models.TextField(max_length = 140, blank=True, null=True, unique=False)
    music = models.TextField(max_length = 140, blank=True, null=True, unique=False)
    
class UserAboutForm(ModelForm):
    class Meta:
        model = UserAbout
        exclude = ('user',)

Есть представление которое должно обновлять данные в таблице.
def UserProfileEdit(request, *offset):
    if request.user.is_authenticated() and request.user.username == offset[0]:
        if request.method == 'POST':
            if offset[1] == 'person':
                form = UserAboutForm(request.POST)
                mainProfile = User.objects.get(username = offset[0])
                if form.is_valid():
                    addProfile = UserAbout(user = mainProfile, 
                                      about = request.POST.get('about'), 
                                      family = request.POST.get('family'), 
                                      why = request.POST.get('why'), 
                                      trust = request.POST.get('trust'), 
                                      hobby = request.POST.get('hobby'), 
                                      job = request.POST.get('job'), 
                                      politic = request.POST.get('politic'), 
                                      book = request.POST.get('book'), 
                                      film = request.POST.get('film'), 
                                      music = request.POST.get('music'),)
                    addProfile.save()
                return HttpResponseRedirect("/profile/print/%s/%s/" %(offset[0], offset[1]))
Не могу добиться от него именно обновления данных, запрос с такого кода идет на INSERT и соответственно БД возвращает ошибку, т.к. дублируется первичный ключ.



_________
Новичок

Офлайн

#2 Дек. 3, 2012 18:00:16

FishHook
От:
Зарегистрирован: 2011-01-08
Сообщения: 8312
Репутация: +  568  -
Профиль   Отправить e-mail  

INSERT вместо UPDATE

Ой-ой. Что это Вы делаете, какой страшный код.
1. Почему Вы не используете формы для валидации и сохранения данных?

form.save()
вместо кучи
about = request.POST.get('about'), 
2. Откуда фреймворк должен знать, что Вам нужно апдейтить, а не инсертить? Если в Вашем коде нужен апдейт, то сделайте инстанс модели и апдейтите его, полученными данными
You may have noticed Django database objects use the same save() method for creating and changing objects. Django abstracts the need to use INSERT or UPDATE SQL statements. Specifically, when you call save(), Django follows this algorithm:

If the object's primary key attribute is set to a value that evaluates to True (i.e., a value other than None or the empty string), Django executes a SELECT query to determine whether a record with the given primary key already exists.
If the record with the given primary key does already exist, Django executes an UPDATE query.
If the object's primary key attribute is not set, or if it's set but a record doesn't exist, Django executes an INSERT.
The one gotcha here is that you should be careful not to specify a primary-key value explicitly when saving new objects, if you cannot guarantee the primary-key value is unused. For more on this nuance, see Explicitly specifying auto-primary-key values above and Forcing an INSERT or UPDATE below.



Отредактировано FishHook (Дек. 3, 2012 18:24:53)

Офлайн

#3 Дек. 3, 2012 18:23:53

SorrowFuck
От: Хабаровск
Зарегистрирован: 2012-10-10
Сообщения: 64
Репутация: +  2  -
Профиль   Отправить e-mail  

INSERT вместо UPDATE

FishHook
Ой-ой. Что это Вы делаете, какой страшный код.1. Почему Вы не используете формы?2. Откуда фреймворк должен знать, что Вам нужно апдейтить, а не инсертить?
Я использовал формы весьма успешно, пока не столкнулся с exclude.
Форма валидна, а записывать ее нельзя т.к. она в базе будет пустое поле user.
Из-за этого такую муть и по-написал.
If the record with the given primary key does already exist, Django executes an UPDATE query.
Запись то с таким первичным ключом уже существует, в том-то и загвоздка, что Django не выполняет UPDATE.
Хотя, я думаю, что все будет вглядить гораздо проще если по нормальному сделаю с формой. Но не знаю как записать за один раз и PK и форму.
                form = UserAboutForm(request.POST)
                mainProfile = User.objects.get(username = offset[0])
                if form.is_valid():
                    addProfile = UserAbout(user = mainProfile, form)
                    addProfile.save()
Так не работает.



_________
Новичок

Офлайн

#4 Дек. 3, 2012 18:36:25

FishHook
От:
Зарегистрирован: 2011-01-08
Сообщения: 8312
Репутация: +  568  -
Профиль   Отправить e-mail  

INSERT вместо UPDATE

Самый тупой и простой вариант

.....
user = models.ForeignKey(User, related_name='UserAboutToUser', unique=True, null=True, bkank=true)
.....
if form.is_valid():
                    mainProfile = User.objects.get(username = offset[0])
                    addProfile =form.save()
                    addProfile.user=mainProfile
                    addProfile.save()
А еще можно __init__ у формы переопределить, или save или заюзать form.instance + get_or_cretate, да еще много что можно придумать, но только не так как у Вас



Офлайн

#5 Дек. 3, 2012 18:57:24

SorrowFuck
От: Хабаровск
Зарегистрирован: 2012-10-10
Сообщения: 64
Репутация: +  2  -
Профиль   Отправить e-mail  

INSERT вместо UPDATE

FishHook
Самый тупой и простой вариант
Я попробовал в лоб, для простоты. На что postgre выругался:

2012-12-04 03:51:51 VLAT ERROR:  duplicate key value violates unique constraint "users_userabout_user_id_key"
2012-12-04 03:51:51 VLAT DETAIL:  Key (user_id)=(1) already exists.
2012-12-04 03:51:51 VLAT STATEMENT:  
UPDATE "users_userabout" 
SET "user_id" = 1, "about" = '1', "family" = '2', "why" = '3', "trust" = '4', 
"hobby" = '5', "job" = '6', "politic" = '7', "book" = '8', "film" = '9', "music" = '10' 
WHERE "users_userabout"."id" = 2 
2012-12-04 03:51:51 VLAT ERROR:  current transaction is aborted, commands ignored until end of transaction block
2012-12-04 03:51:51 VLAT STATEMENT:  SHOW default_transaction_isolation
Причин такой ругани на апдейт я не понимаю.



_________
Новичок

Отредактировано SorrowFuck (Дек. 3, 2012 19:03:12)

Офлайн

#6 Дек. 3, 2012 19:50:45

reclosedev
От: Н.Новгород
Зарегистрирован: 2012-03-29
Сообщения: 870
Репутация: +  173  -
Профиль   Отправить e-mail  

INSERT вместо UPDATE

addProfile = form.save(commit=False)
?

Офлайн

#7 Дек. 3, 2012 20:03:34

SorrowFuck
От: Хабаровск
Зарегистрирован: 2012-10-10
Сообщения: 64
Репутация: +  2  -
Профиль   Отправить e-mail  

INSERT вместо UPDATE

reclosedev
?
То же самое выходит:
2012-12-04 05:00:57 VLAT ERROR:  duplicate key value violates unique constraint "users_userabout_user_id_key"
2012-12-04 05:00:57 VLAT DETAIL:  Key (user_id)=(1) already exists.
2012-12-04 05:00:57 VLAT STATEMENT:  INSERT INTO "users_userabout" ("user_id", "about", "family", "why", "trust", "hobby", "job", "politic", "book", "film", "music") VALUES (1, '1', '2', '3', '4', '5', '6', '7', '8', '9', '10') RETURNING "users_userabout"."id"



_________
Новичок

Офлайн

#8 Дек. 4, 2012 07:18:01

reclosedev
От: Н.Новгород
Зарегистрирован: 2012-03-29
Сообщения: 870
Репутация: +  173  -
Профиль   Отправить e-mail  

INSERT вместо UPDATE

Так если он существует, значит надо сначала его найти

...
try:
    addProfile = UserAbout.objects.get(user=request.user)
except UserAbout.DoesNotExist:
    addProfile = None
form = UserAboutForm(request.POST, instance=addProfile)
if form.is_valid():
    addProfile = form.save(commit=False)
    addProfile.user = request.user
    addProfile.save()
...
Если конечно я правильно понял, т.к. названия offset, mainProfile и addProfile запутывают.
И похоже, request.user и есть mainProfile если
request.user.username == offset[0]

Кстати, для профайлов есть стандартные решения
https://docs.djangoproject.com/en/1.4/topics/auth/#storing-additional-information-about-users
Но в 1.5 изменится
https://docs.djangoproject.com/en/dev/topics/auth/#auth-custom-user

Отредактировано reclosedev (Дек. 4, 2012 07:18:45)

Офлайн

#9 Дек. 4, 2012 07:47:28

SorrowFuck
От: Хабаровск
Зарегистрирован: 2012-10-10
Сообщения: 64
Репутация: +  2  -
Профиль   Отправить e-mail  

INSERT вместо UPDATE

reclosedev
Так если он существует, значит надо сначала его найти
Да, действительно, так работает, спасибо.
С профайлом может быть велосипед вышел, но я просто расширил стандартную модель, добавив еще одну и связав ее с помощью ForeignKey. От сюда и такие название AddedProfile и MainProfile, расширенный и основной.



_________
Новичок

Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version