django change formfield data - django

I am working with django-taggit (https://github.com/alex/django-taggit). To let a user add tags i use a formfield that I convert into the tags and add them.
However, when i try to load the template for editing. i get the taggit objects in my bar.
Now i want to convert those in a normal readable string again.
However, i can't seem to edit that field of the instance before passing it to my form.
The Form:
class NewCampaignForm(forms.ModelForm):
""" Create a new campaign and add the searchtags """
queryset = Game.objects.all().order_by("name")
game = forms.ModelChoiceField(queryset=queryset, required=True)
tags = forms.CharField(required=False)
focus = forms.ChoiceField(required=False, choices=Campaign.CHOICES)
class Meta:
model = Campaign
fields = ["game", "tags", "focus"]
exclude = ["owner"]
my model:
class Campaign(models.Model):
""" campaign information """
ROLEPLAY = "Roleplay"
COMBAT = "Combat"
BOTH = "Both"
CHOICES = (
(ROLEPLAY, "Roleplay"),
(COMBAT, "Combat"),
(BOTH, "Both"),
)
owner = models.ForeignKey(User)
game = models.ForeignKey(Game)
focus = models.CharField(max_length=15, choices=CHOICES)
tags = TaggableManager()
view:
def campaign_view(request, campaign_id):
campaign = get_object_or_404(Campaign, pk=campaign_id)
campaign.tags = "Some string"
new_campaign_form = NewCampaignForm(instance=campaign)
But when i try this i still get the taggit objects([]) in my inputfield instead of the "Some string"
How should i solve this

I am not sure how i overlooked this. But this works:
new_campaign_form = NewCampaignForm(instance=campaign, initial={"tags": "Some String"})
Excuse me, should have looked more and try better

Related

How can I use Linkify with Django_tables2

I have read a few similar questions and all the docs I can find on this but I am still not able to understand the solution. I have built my model to have a player, the text description of a keyboard and a url to it. I want to show in a table the player, the keyboard and i want to have the keyboard text have the url column embedded within it. Any help would be appreciated.
Models.py:
class player_hardware(models.Model):
Player = models.TextField(blank = False, primary_key = True)
keyboard = models.TextField(blank = True, max_length = 200)
keyboard_url = models.TextField(blank = True, max_length = 200)
Views.py:
class PlayerListView(SingleTableView):
model = player_hardware
table_class = PersonTable
template_name = 'application/playerlist.html'
Tables.py
class PersonTable(tables.Table):
class Meta:
model = player_hardware
template_name = "django_tables2/bootstrap4.html"
fields = ("Player", "keyboard")
If the keyboard_url is to an external website, it's simpler to add the url link in a custom render_field method on the Table.
class PersonTable(tables.Table):
def render_keyboard(self, record):
return mark_safe(f'{record.keyboard}')
The linkify field appears to be more for internal urls, but if you absolutely wanted to use linkify to create an external link, it would look like:
class PersonTable(tables.Table):
keyboard = tables.Column(linkify=self.get_keyboard_url)
def get_keyboard_url(self, record):
return record.keyboard_url

Doing a Multi-step form with Django Class-based CreateView

I have multiple class-based createviews. My goal is to link all createviews such that when I post the first createview, it will redirect me to the second createview where it will retrieve the data entered from first createview.
Does anyone know the solution to this?
The first createview (Step01) contains django-inline-formset-factory code which is similar to this code, while the rest (Step02 and Step03) contain basic code.
I have referred to this link, but the solution is based on using function-based view. Have also made attempt using Django's Form-Wizard, but handling django-inline-formset with it is still too complicated for me.
Why do I do this? So that each group level (i.e. general, staff, managerial) can access their respective view but not the view for other group level.
This is my current code:
models.py
class Model_Step01_Cart(models.Model):
cart_name = models.CharField(max_length=100)
class Model_Step01_CartItem(models.Model):
cart = models.ForeignKey(Profile)
item_name = models.CharField(max_length = 100)
item_quantity = models.FloatField(null = True, blank = True)
class Model_Step02_Staffnote(models.Model):
note_staff = models.TextField(max_length = 500, null = True, blank = True)
class Model_Step03_Managernote(models.Model):
note_manager = models.TextField(max_length = 500, null = True, blank = True)
forms.py
class Form_Step01_Cart(forms.ModelForm):
class Meta:
model = Model_Step01_Cart
fields = ["cart_name"]
class Form_Step01_CartItem(forms.ModelForm):
class Meta:
model = Model_Step01_CartItem
fields = ["cart", "item_name", "item_quantity"]
Formset_CartItem = forms.inlineformset_factory(
Model_Step01_Cart,
Model_Step01_CartItem,
form = Form_Step01_CartItem,
extra = 3
)
class Form_Step02(forms.ModelForm):
class Meta:
model = Model_Step02_Staffnote
fields = ["note_staff"]
class Form_Step03(forms.ModelForm):
class Meta:
model = Model_Step03_Managernote
fields = ["note_manager"]
views.py
class View_Step01(CreateView):
# contains formset_factory for "Model_Step01_Cart" and "Model_Step01_CartItem"
model = Model_Step01_Cart
fields = ["cart_name"]
# similar with the code displays here: https://medium.com/#adandan01/django-inline-formsets-example-mybook-420cc4b6225d
class View_Step02(CreateView):
# gets info from step 01, and adds staff's note
class View_Step03(CreateView):
# gets info from step 01 and 02, and adds manager's note.
Find my answer to split a single form across multiple views. You can configure the gist script to fit your requirement
For class-based-view map the success url of one view to other CreateView.as_view(model=myModel, success_url="/<path-to-view2/")

How to save many to many relationship?

I'm almost using following code(I striped down a little bit), I use auto complete light to load users and users can insert different people name(users) seperated by comma. the problem is when I try to save I get following error
ValueError at /write/
"<Article: test1>" needs to have a value for field "article" before this many-to-many relationship can be used.
models.py
class Article(models.Model):
author = models.ForeignKey(User,)
people = models.ManyToManyField(User, related_name="with", null=True,)
content = models.TextField()
forms.py
class ArticleForm(forms.ModelForm):
people = forms.CharField(widget=autocomplete_light.TextWidget('UserAutocomplete'))
class Meta:
model = Article
views.py
def write(request):
if request.POST:
form = ArticleForm(request.POST)
if form.is_valid():
content = form.cleaned_data['content']
user = User.objects.get(username=request.user.username)
people_str = form.cleaned_data['accompanied']
people = [x.strip() for x in accompanied_str.split(',')]
article = Article(
content = content,
author = user,
)
for username in accompanied:
user = User.objects.get(username=username)
article.people.add(user)
article.save()
return HttpResponseRedirect('/success/')
In order to create a relation you need the ids of both side. The newly created article has no id yet. If you save the article first and then add people to it it should work fine.
article = Article(
content = content,
author = user,
)
article.save()
article.add(*User.objects.filter(username__in=accompanied))
The process of adding people can be cheaper by getting all users that have a username from the list of accompanied in one fetch.

Django entry creating. Method in views/other file or as a method of model class

Django creating entry.
1) As seen in Django docs:
class Article(models.Model):
user = models.ForeignField(User)
title = models.CharField(#some_params)
content = models.CharField(#some_params)
date = models.DateTimeField(#some_params)
Then in my views I can:
new_article = Article(user=user, title="abc", content="xyz", date = datetime.utcnow())
new_article.save()
2) But it also can be done like by calling method within Article class, ie:
class Article(models.Model):
user = models.ForeignField(User)
title = models.CharField()
content = models.CharField()
def add_article(self, title, content):
self.title = title
self.content = content
self.date = datetime.utcnow()
self.save()
and then in views:
title = "abc"
content = "xyz"
new_article = Article(user=user)
new_article.add_article(abc, xyz)
I am asking because I have seen both ways of adding content into database. I would like to ask:
What is better practice?
Any concerns about security in 2nd example?
Option 1 is, in my opinion, better practice. add_article is unnecessary, because you can set the date by using the auto_now property of the date field, and everything else is already built-in. You'll have less code and less maintenance.

How to get logged-in user info in Django's forms.py

I have created a Profile model including the Gender info. There is also models called Dorm and Registration (not used for user registration) like this:
class Registration(models.Model):
user = models.ForeignKey(User)
pref1 = models.ForeignKey(Dorm, related_name="pref1",verbose_name=u"Preference 1",null=True)
...
friend1 = models.CharField(u"Friend 1", max_length=15,blank=True)
class Dorm(models.Model):
name = models.ForeignKey(Building)
gender = models.CharField(u"Gender", max_length=1, blank=True, choices=GENDER_CHOICES)
Now, i am trying to generate a form for this Registration model with forms.ModelForm like this:
class RegistrationForm(forms.ModelForm):
dorms = Dorm.objects.filter(gender='M')
pref1 = forms.ModelChoiceField(queryset=dorms, empty_label=None)
...
class Meta:
model = Registration
exclude = ('user')
as you can see in the second line, i am querying the dorms with a hardcoded gender value M. Instead of the hardcoded value, I need to get the users' gender, and query the database with that gender information.
I have been searching the documentation but I could not find anything. Can you help me? How can I learn the logged-in User' profile information in Django Forms?
So without using some sort of monkeying around of the init function a "form_factory" is probably the best approach.
def RegFormFactory(user)
dorms = Form.objects.filter(gender = "user.gender")
class _RegistrationForm(forms.ModelForm):
pref1 = forms.ModelChoiceField(queryset = dorms, empty_label=None)
class Meta:
model = Registration
exclude = ('user')
return _RegistrationForm
then use:
formclass = RegFormFactory(user)
form_inst = formclass()
...
form_inst = formclass(request.POST)
This is described very nicely in a blog post here: So you want a dynamic form.
James Bennett wrote a blog post that should explain perfectly what you need: So you want a dynamic form