【问题标题】:Django : form is not saved into my databaseDjango:表单未保存到我的数据库中
【发布时间】:2015-10-13 20:52:58
【问题描述】:

尽管我发送报价的表单已正确显示并且我在提交报价时没有错误,但它们并未保存在我的数据库中。 我知道通过检查管理站点,没有保存任何对象。 但是另一方面,我已经编写了注册代码,并且将用户保存在数据库中。

我怀疑我的两个模型之间的 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 shell 中保存报价:

>>> 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'

编辑:解决方案是添加这些行:

    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 中有描述。

【问题讨论】:

  • 不知道这是否能解决您的问题,但您忘记了模板中的结束 &lt;/form&gt; 标记。
  • 很遗憾没有。但这确实是一个错误。
  • 只是为了确定——你能在“offerform.save()”的正上方打印并确保它被调用吗?
  • 我刚刚在 offerform.save() 上方添加了“print("OK")”。当我提交报价时,我看不到 OK,但我不确定它是否会起作用。提交报价时,我也有我的参数“sent = True”。
  • 尝试导入 ipd 并在保存后放置 ipdb.set_trace()。然后在调试器控制台中检查所有涉及的变量的值并逐步执行代码以查看发生了什么

标签: django django-models foreign-keys django-1.8


【解决方案1】:

在 ModelForm 上,如果在实例化时不传递任何对象,它将在指定类型的数据库中创建一个新对象。因此,在这种情况下,您已在 SendOfferForm 上指定了 Offer。如果您确实传递了现有对象,则在本例中它必须是指定的类型。

您似乎正在尝试使用当前登录的用户自动填充发布者字段。为此,您需要手动将发布者字段设置为用户实例。

如果您打算让表单在数据库中创建新的报价,请执行此操作

offerform = SendOfferForm(request.POST)

如果您尝试更新当前报价,那么您需要将实例对象传递到表单中

offerform = SendOfferForm(request.POST, instance=someOffer)

要手动添加用户字段调用 save 在您的表单上使用 commit=False 这将返回一个优惠对象而不保存到数据库。此时您就有机会自定义对象中的数据,然后保存。

offer = offerform.save(commit=False)
offer.publisher = request.user.id
offer.save()

所有这些在 django 文档中都有更详细的解释 ModelForm documentation

【讨论】:

  • 我不确定我是否理解。你的意思是我应该在views.py中写这样的东西:Offer_publisher = logged_in_user.username offerform = SendOfferForm(request.POST, instance=Offer_publisher) 而不是:offerform = SendOfferForm(request.POST, instance=logged_user)?
  • 是的,模型表单需要它所代表的对象的实例。如果您不允许用户在表单上编辑该字段,则必须手动设置 fk 字段。
  • 不,更糟。我遇到了错误:/envoyer_une_offre 'str' 对象的 AttributeError 没有属性 '_meta' 我只是将 publisher = logged_user.username 放在函数的开头,然后我写了 offerform = SendOfferForm(request.POST, instance=publisher )
  • 您需要阅读文档。为什么要使用 OfferForm 以外的实例设置 OfferForm ?此外,当您设置发布者时,它需要实例而不是用户名。我现在是移动设备,所以很难编写任何代码 sn-p 向您展示。等我回家的时候如果没有解决,我会给你看一些代码。
  • 我认为像 Offer.id 和 offer.publisher 这样的隐藏字段将填充 User 模型的字段,因为它们已经填充了 logged_in_user 的数据。如果您能向我展示可以解决我的问题的代码 sn-p,我将不胜感激。这很奇怪,但我在书中找不到任何保存此类模型的示例。
猜你喜欢
  • 2021-08-13
  • 1970-01-01
  • 2021-10-07
  • 1970-01-01
  • 1970-01-01
  • 2021-06-28
  • 1970-01-01
  • 2020-02-16
  • 1970-01-01
相关资源
最近更新 更多