我需要实现以下内容:
将向用户显示一个表格,该表格将包含由属性名称组成的下拉选项菜单。有两种类型的属性:常规属性,即所有用户和自定义属性共有的属性,即每个用户在此之前定义的属性。模型看起来像这样:
class GeneralPropertyName(models.Model):
name = models.CharField(max_length=20)
class CustomPropertyName(models.Model):
user = models.ForeignKey(User)
name = models.CharField(max_length=20)
下拉菜单应包含所有常规属性,并且只包含与用户相关的自定义属性。
第一个问题:如何定义这样的模型? 我需要:1。以某种方式统一两个属性,2。仅从CustomPropertyName中获取与用户相关的那些项
class SpecData(models.Model):
user = models.ForeignKey(User)
selection_title = models.CharField(max_length=20)
property = ForeignKey(GeneralPropertyName) ??UNIFY??? ForeignKey(CustomPropertyName)
其次,ModelForm需要做些什么特别的事情吗?
class SpecDataForm(ModelForm):
class Meta:
model = SpecData
第三个问题是视图中需要做什么?我将需要使用内联表单集,因为我将有一些这样的动态表单。
def index(request):
user = User.objects.get(username=request.user.username)
specdataFormSet = inlineformset_factory(User, SpecData, form=SpecDataForm, extra=30)
...
specdata_formset = specdataFormSet(instance=user, prefix='specdata_set')
...
感谢。
编辑:调整了juliocesar建议包含formsets。不知何故,我收到以下错误消息:无法将关键字'property'解析为字段。选项包括:id,name,selection_title,user
def index(request):
user = User.objects.get(username=request.user.username)
user_specdata_form = UserSpecDataForm(user=user)
SpecdataFormSet = inlineformset_factory(User, SpecData, form=user_specdata_form, extra=30)
答案 0 :(得分:1)
1a)你看过django的ContentType framework这将允许你拥有通用外键,你可以限制存储可接受的模型类型。
1b)我认为接受哪种外键可接受的验证不应该在你的模型中,而应该在保存之前成为表单验证的一部分。
2)如果您确实使用了模型表单,则必须为自由字段定义自己的custom widget。这意味着您可能必须编写自己的渲染函数来渲染字段中的html。您还应该在表单上定义自己的验证功能,以确保只有适当的数据才能保存。
3)我认为你不必做任何你在视图中没有做过的事情
答案 1 :(得分:1)
使用GenericForeignKey:
class SpecData(models.Model):
user = models.ForeignKey(User)
selection_title = models.CharField(max_length=20)
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
property = GenericForeignKey('content_type', 'object_id')
您可以使用this将两个字段(类型和ID)组合到一个选项字段中。
答案 2 :(得分:1)
您可以使用GenericForeignKey来处理它,但您仍需要更多解决方案和视图的更多问题。
我已经举例说明了如何解决问题(已记录的用户可以从常规属性和他的自定义属性中选择,非登录用户只能选择常规属性)。我使用模型继承作为属性(在您的示例代码中,似乎CustomPropertyName
是PropertyName
与其他字段)。我认为继承是比ContentTypes更容易和更基本的概念,它符合您的需求。
注意:我删除了一些代码,例如导入以简化代码。
1)models.py文件:
class PropertyName(models.Model):
name = models.CharField(max_length=20)
def __unicode__(self):
return self.name
class CustomPropertyName(PropertyName): # <-- Inheritance!!
user = models.ForeignKey(User)
def __unicode__(self):
return self.name
class SpecData(models.Model):
user = models.ForeignKey(User)
selection_title = models.CharField(max_length=20)
property = models.ForeignKey(PropertyName)
注意:字段SpecData.property
指向PropertyName,因为所有属性都保存在PropertyName的数据库表中。
2)forms.py文件:
from django import forms
from django.db.models import Q
from models import SpecData, PropertyName
def UserSpecDataForm(user=None):
UserPropertiesQueryset = PropertyName.objects.filter(Q(custompropertyname__user=None) | Q(custompropertyname__user__id=user.id))
class SpecDataForm(forms.ModelForm):
property = forms.ModelChoiceField(queryset=UserPropertiesQueryset)
class Meta:
model = SpecData
exclude = ('user',)
return SpecDataForm
注意:这里的技巧是通过根据参数中指定的用户过滤属性来动态生成表单SpecDataForm
。
3)views.py文件:
from forms import UserSpecDataForm
def index(request):
if request.POST:
form = UserSpecDataForm(request.user)(request.POST) # instance=user
if form.is_valid():
spec_data = form.save(commit=False)
spec_data.user = request.user
spec_data.save()
else:
form = UserSpecDataForm(request.user)()
return render_to_response('properties.html', {'form': form}, context_instance=RequestContext(request))
注意:这里没什么特别的,只是调用form.UserSpecDataForm(request.user)
返回表单类然后实例化。同时将已登录用户设置为save
上返回的对象,因为form
中已将其排除在前端未显示。
按照这个基本示例,如果需要,可以对formset执行相同的操作。
<强>更新强>
可以通过向视图添加以下代码来使用Formset:
user_specdata_form = UserSpecDataForm(user=request.user)
SpecdataFormSet = inlineformset_factory(User, SpecData, form=user_specdata_form, extra=30)
下载完整的项目示例
希望这有帮助
答案 3 :(得分:1)
一种方法是你只有一个模型,让用户可以为空:
class PropertyName(models.Model):
user = models.ForeignKey(User, null=True, blank=True)
name = models.CharField(max_length=20)
class SpecData(models.Model):
user = models.ForeignKey(User)
selection_title = models.CharField(max_length=20)
property = ForeignKey(PropertyName)
因此,如果未设置用户,则它是一般属性。如果已设置,则与该用户相关。
但是,请注意,如果您需要唯一的属性名称,那么NULL!= NULL。
当然,建议的GenericForeignKey解决方案在某些情况下更好。
此外,您可以轻松地使用您描述的正常(非模型)表单,并将表单逻辑与模型逻辑分开。