Вопрос:
Наверху моя форма для отправки предложения отображается правильно и у меня нет ошибки при отправке предложений, они не сохраняются в моей базе данных. Я знаю, что, проверяя админ-сайт, объекты не сохраняются. Но, с другой стороны, я уже написал код для регистрации, и пользователи сохраняются в базе данных.
Я подозреваю отношение ForeignKey между двумя моими моделями в качестве виновника.
models.py
from django.db import models class User(models.Model): username = models.CharField(max_length=30, unique=True, blank=False) password1 = models.CharField(max_length=40, blank=False) password2 = models.CharField(max_length=40, blank=False) mail = models.EmailField(unique=True, blank=False) birthday = models.DateField(blank=False) date = models.DateTimeField(auto_now_add=True, auto_now=False, verbose_name=»Date d’inscription») def __str__(self): return self.username class Offer(models.Model): publisher = models.ForeignKey(User) content = models.TextField() date = models.DateTimeField(auto_now_add=True, auto_now=False, verbose_name=»Date de parution») def __str__(self): return self.publisher.username
forms.py
from django import forms from django.contrib import admin from django.contrib.auth.hashers import make_password, check_password from django.utils.translation import ugettext_lazy as _ from myuser.models import User, Offer class UserCreationForm(forms.ModelForm): class Meta: model = User widgets = { ‘password1’ : forms.PasswordInput(), ‘password2’ : forms.PasswordInput(), } fields = («username», «password1», «password2», «mail») def clean_password2(self): # Check that the two password entries match password1 = self.cleaned_data.get(«password1») password2 = self.cleaned_data.get(«password2») if password1 and password2 and password1 != password2: raise forms.ValidationError(«les mots de passes ne correspondent pas») return password2 def save(self, commit=True): # Save the provided password in hashed format user = super(UserCreationForm, self).save(commit=False) user.password1 = make_password(self.cleaned_data[«password1»]) user.password2 = make_password(self.cleaned_data[«password2″]) if commit: user.save() return user class LoginForm(forms.Form): username = forms.CharField(label=»nom d’utilisateur») password = forms.CharField(label=»mot de passe», widget = forms.PasswordInput) def clean(self): cleaned_data = super(LoginForm, self).clean() username = cleaned_data.get(‘username’) password = cleaned_data.get(‘password’) user = User.objects.get(username=username) if check_password(password, user.password1): return cleaned_data else: raise forms.ValidationError(«Le nom d’utilisateur et le mot de passe ne correspondent pas») class SendOfferForm(forms.ModelForm): class Meta: model = Offer fields = (‘content’,)
Views.py
from django.shortcuts import render from django.http import HttpResponseRedirect, HttpResponse from django.core.exceptions import ObjectDoesNotExist from myuser.models import User, Offer from myuser.forms import UserCreationForm, LoginForm, SendOfferForm def get_logged_user_from_request(request): if ‘logged_user_id’ in request.session: logged_user_id = request.session[‘logged_user_id’] return User.objects.get(id=logged_user_id) else: return None def register(request): registered = False if request.method == ‘POST’: user_form = UserCreationForm(data=request.POST) if user_form.is_valid(): user = user_form.save() registered = True else: print(user_form.errors) else: user_form = UserCreationForm() return render(request, ‘myuser/create_account.html’, {‘user_form’: user_form, ‘registered’: registered} ) def login(request): if request.method==’POST’: form = LoginForm(request.POST) try: if form.is_valid(): user = User.objects.get(username=request.POST.get(‘username’)) logged_user = User.objects.get(username=request.POST.get(‘username’)) request.session[‘logged_user_id’] = logged_user.id return HttpResponseRedirect(‘/’) else: error = «le nom d’utilisateur et le mot de passe ne correspondent pas» return HttpResponse(«Invalid login details supplied.») except User.DoesNotExist: return HttpResponse(«Invalid login details supplied.») else: form = LoginForm return render(request, ‘myuser/mylogin.html’, locals()) def send_offer(request): sent = False logged_user = get_logged_user_from_request(request) if logged_user: if request.method == ‘POST’: try: offerform = SendOfferForm(request.POST, instance=logged_user) if offerform.is_valid(): sent = True offerform.save() else: print(offerform.errors) except: return HttpResponse(«drapeau except») else: offerform = SendOfferForm(instance=logged_user) else: return HttpResponse(«Vous n’êtes pas connecté») return render(request, ‘myuser/send_offer.html’, locals())
urls.py
from django.conf.urls import patterns, url, include from django.views.generic import TemplateView urlpatterns = patterns(‘myuser.views’, url(r’^inscription/$’, ‘register’, name=’create_account’), url(r’^connexion/$’, ‘login’, name=’login’), url(r’^envoyer_une_offre$’, ‘send_offer’, name=’send_offer’), )
send_offer.html
{% extends «base.html» %} {% block content %} <h1> Offer </h1> {% if not sent %} <p> write your offer <p/> <form action=»{% url «send_offer» %}» method=’POST’ class=’sendofferform’> {{ form.errors }} {{ form.non_field_errors }} {% csrf_token %} {{ offerform.as_p }} <input type=»submit» value=»Submit» /> </form> {% else %} Offer is published <a href=»/poster_une_offre»>publish another offer?</a><br /> <a href=»/»>get back to the homepage</a><br /> {% endif %} {% endblock %}
admin.py
from django.contrib import admin from myuser.models import User, Offer#, Message class UserAdmin(admin.ModelAdmin): list_display = (‘id’, ‘username’, ‘status’, ‘college’, ‘apercu_description’) list_filter = (‘id’, ‘username’, ‘birthday’) date_hierarchy = ‘date’ ordering = (‘date’, ) search_fields = (‘username’, ‘description’) def apercu_description(self, User): text = User.description[0:40] if len(User.description) > 40: return ‘%s’ % text else: return text class OfferAdmin(admin.ModelAdmin): list_display = (‘id’, ‘publisher’, ‘apercu_offre’) list_filter = (‘id’, ) date_hierarchy = ‘date’ ordering = (‘date’, ) search_fields = (‘publisher’,) def apercu_offre(self, Offer): text = Offer.content[0:40] if len(Offer.content) > 40: return ‘%s’ % text else: return text admin.site.register(User, UserAdmin) admin.site.register(Offer, OfferAdmin)
Вся другая функция работает (регистр и логин), а функция register() правильно сохраняет пользователя, но функция send_offer(), которая очень похожа на функцию регистра, не работает и после поиска в Интернете в течение нескольких часов, я все еще не знаю, почему предложения не сохраняются.
Но когда я пытаюсь добавить предложение на админ-сайт, он работает.
Кроме того, я попытался сохранить предложение в оболочке python manage.py:
>>> Offer.publisher = «a» >>> Offer.content = «lalalala» >>> Offer.save() Traceback (most recent call last): File «/usr/local/lib/python3.4/dist-packages/django/core/management/commands/shell.py», line 69, in handle self.run_shell(shell=options[‘interface’]) File «/usr/local/lib/python3.4/dist-packages/django/core/management/commands/shell.py», line 61, in run_shell raise ImportError ImportError During handling of the above exception, another exception occurred: Traceback (most recent call last): File «/usr/lib/python3.4/code.py», line 90, in runcode exec(code, self.locals) File «<console>», line 1, in <module> TypeError: save() missing 1 required positional argument: ‘self’
EDIT: решение заключалось в том, чтобы добавить следующие строки:
if offerform.is_valid(): sent = True offer = offerform.save(commit=False) offer.publisher = User.objects.get(id=logged_user.id) offer.save()
Обратите внимание, что logged_user – это функция, описанная в view.py.
Лучший ответ:
В ModelForm, если вы не передаете какой-либо объект при его создании. Он создаст новый объект в базе данных указанного типа. Таким образом, в этом случае на вашем SendOfferForm вы указали Предложение. Если вы передаете существующий объект, он должен быть указанным типом в этом случае.
Похоже, вы пытаетесь автоматически заполнить поле издателя текущим пользователем. Для этого вам нужно вручную установить поле издателя в экземпляр пользователя.
Если вы намерены создать форму для создания нового предложения в базе данных, сделайте это
offerform = SendOfferForm(request.POST)
Если вы пытаетесь обновить текущее предложение THEN, вам нужно передать экземпляр объекта в форму
offerform = SendOfferForm(request.POST, instance=someOffer)
Чтобы вручную добавить сохранение поля пользователя в форму с помощью commit = False, это вернет объект предложения БЕЗ сохранения в БД. На этом этапе у вас есть возможность настроить данные в объекте и затем сохранить.
offer = offerform.save(commit=False) offer.publisher = request.user.id offer.save()
Все это объясняется более подробно в документации документации ModelForm django